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);
75 double GetDifficulty(const CBlockIndex* blockindex = NULL)
77 // Floating point number that is a multiple of the minimum difficulty,
78 // minimum difficulty = 1.0.
79 if (blockindex == NULL)
81 if (pindexBest == NULL)
84 blockindex = pindexBest;
87 int nShift = (blockindex->nBits >> 24) & 0xff;
90 (double)0x0000ffff / (double)(blockindex->nBits & 0x00ffffff);
107 int64 AmountFromValue(const Value& value)
109 double dAmount = value.get_real();
110 if (dAmount <= 0.0 || dAmount > 21000000.0)
111 throw JSONRPCError(-3, "Invalid amount");
112 int64 nAmount = roundint64(dAmount * COIN);
113 if (!MoneyRange(nAmount))
114 throw JSONRPCError(-3, "Invalid amount");
118 Value ValueFromAmount(int64 amount)
120 return (double)amount / (double)COIN;
123 void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
125 int confirms = wtx.GetDepthInMainChain();
126 entry.push_back(Pair("confirmations", confirms));
129 entry.push_back(Pair("blockhash", wtx.hashBlock.GetHex()));
130 entry.push_back(Pair("blockindex", wtx.nIndex));
132 entry.push_back(Pair("txid", wtx.GetHash().GetHex()));
133 entry.push_back(Pair("time", (boost::int64_t)wtx.GetTxTime()));
134 BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
135 entry.push_back(Pair(item.first, item.second));
138 string AccountFromValue(const Value& value)
140 string strAccount = value.get_str();
141 if (strAccount == "*")
142 throw JSONRPCError(-11, "Invalid account name");
146 Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex)
149 result.push_back(Pair("hash", block.GetHash().GetHex()));
150 result.push_back(Pair("blockcount", blockindex->nHeight));
151 result.push_back(Pair("version", block.nVersion));
152 result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex()));
153 result.push_back(Pair("time", (boost::int64_t)block.GetBlockTime()));
154 result.push_back(Pair("nonce", (boost::uint64_t)block.nNonce));
155 result.push_back(Pair("difficulty", GetDifficulty(blockindex)));
157 BOOST_FOREACH (const CTransaction&tx, block.vtx)
158 txhashes.push_back(tx.GetHash().GetHex());
159 result.push_back(Pair("tx", txhashes));
161 if (blockindex->pprev)
162 result.push_back(Pair("hashprevious", blockindex->pprev->GetBlockHash().GetHex()));
163 if (blockindex->pnext)
164 result.push_back(Pair("hashnext", blockindex->pnext->GetBlockHash().GetHex()));
171 /// Note: This interface may still be subject to change.
175 Value help(const Array& params, bool fHelp)
177 if (fHelp || params.size() > 1)
180 "List commands, or get help for a command.");
183 if (params.size() > 0)
184 strCommand = params[0].get_str();
187 set<rpcfn_type> setDone;
188 for (map<string, rpcfn_type>::iterator mi = mapCallTable.begin(); mi != mapCallTable.end(); ++mi)
190 string strMethod = (*mi).first;
191 // We already filter duplicates, but these deprecated screw up the sort order
192 if (strMethod == "getamountreceived" ||
193 strMethod == "getallreceived" ||
194 strMethod == "getblocknumber" || // deprecated
195 (strMethod.find("label") != string::npos))
197 if (strCommand != "" && strMethod != strCommand)
202 rpcfn_type pfn = (*mi).second;
203 if (setDone.insert(pfn).second)
204 (*pfn)(params, true);
206 catch (std::exception& e)
208 // Help text is returned in an exception
209 string strHelp = string(e.what());
210 if (strCommand == "")
211 if (strHelp.find('\n') != -1)
212 strHelp = strHelp.substr(0, strHelp.find('\n'));
213 strRet += strHelp + "\n";
217 strRet = strprintf("help: unknown command: %s\n", strCommand.c_str());
218 strRet = strRet.substr(0,strRet.size()-1);
223 Value stop(const Array& params, bool fHelp)
225 if (fHelp || params.size() != 0)
228 "Stop bitcoin server.");
230 // Shutdown will take long enough that the response should get back
231 CreateThread(Shutdown, NULL);
232 return "bitcoin server stopping";
234 throw runtime_error("NYI: cannot shut down GUI with RPC command");
239 Value getblockcount(const Array& params, bool fHelp)
241 if (fHelp || params.size() != 0)
244 "Returns the number of blocks in the longest block chain.");
251 Value getblocknumber(const Array& params, bool fHelp)
253 if (fHelp || params.size() != 0)
256 "Deprecated. Use getblockcount.");
262 Value getconnectioncount(const Array& params, bool fHelp)
264 if (fHelp || params.size() != 0)
266 "getconnectioncount\n"
267 "Returns the number of connections to other nodes.");
269 return (int)vNodes.size();
273 Value getdifficulty(const Array& params, bool fHelp)
275 if (fHelp || params.size() != 0)
278 "Returns the proof-of-work difficulty as a multiple of the minimum difficulty.");
280 return GetDifficulty();
284 Value getgenerate(const Array& params, bool fHelp)
286 if (fHelp || params.size() != 0)
289 "Returns true or false.");
291 return (bool)fGenerateBitcoins;
295 Value setgenerate(const Array& params, bool fHelp)
297 if (fHelp || params.size() < 1 || params.size() > 2)
299 "setgenerate <generate> [genproclimit]\n"
300 "<generate> is true or false to turn generation on or off.\n"
301 "Generation is limited to [genproclimit] processors, -1 is unlimited.");
303 bool fGenerate = true;
304 if (params.size() > 0)
305 fGenerate = params[0].get_bool();
307 if (params.size() > 1)
309 int nGenProcLimit = params[1].get_int();
310 fLimitProcessors = (nGenProcLimit != -1);
311 WriteSetting("fLimitProcessors", fLimitProcessors);
312 if (nGenProcLimit != -1)
313 WriteSetting("nLimitProcessors", nLimitProcessors = nGenProcLimit);
314 if (nGenProcLimit == 0)
318 GenerateBitcoins(fGenerate, pwalletMain);
323 Value gethashespersec(const Array& params, bool fHelp)
325 if (fHelp || params.size() != 0)
328 "Returns a recent hashes per second performance measurement while generating.");
330 if (GetTimeMillis() - nHPSTimerStart > 8000)
331 return (boost::int64_t)0;
332 return (boost::int64_t)dHashesPerSec;
336 Value getinfo(const Array& params, bool fHelp)
338 if (fHelp || params.size() != 0)
341 "Returns an object containing various state info.");
344 obj.push_back(Pair("version", (int)CLIENT_VERSION));
345 obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION));
346 obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
347 obj.push_back(Pair("blocks", (int)nBestHeight));
348 obj.push_back(Pair("connections", (int)vNodes.size()));
349 obj.push_back(Pair("proxy", (fUseProxy ? addrProxy.ToStringIPPort() : string())));
350 obj.push_back(Pair("difficulty", (double)GetDifficulty()));
351 obj.push_back(Pair("testnet", fTestNet));
352 obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));
353 obj.push_back(Pair("keypoolsize", pwalletMain->GetKeyPoolSize()));
354 obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee)));
355 if (pwalletMain->IsCrypted())
356 obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime));
357 obj.push_back(Pair("errors", GetWarnings("statusbar")));
362 Value getmininginfo(const Array& params, bool fHelp)
364 if (fHelp || params.size() != 0)
367 "Returns an object containing mining-related information.");
370 obj.push_back(Pair("blocks", (int)nBestHeight));
371 obj.push_back(Pair("currentblocksize",(uint64_t)nLastBlockSize));
372 obj.push_back(Pair("currentblocktx",(uint64_t)nLastBlockTx));
373 obj.push_back(Pair("difficulty", (double)GetDifficulty()));
374 obj.push_back(Pair("errors", GetWarnings("statusbar")));
375 obj.push_back(Pair("generate", (bool)fGenerateBitcoins));
376 obj.push_back(Pair("genproclimit", (int)(fLimitProcessors ? nLimitProcessors : -1)));
377 obj.push_back(Pair("hashespersec", gethashespersec(params, false)));
378 obj.push_back(Pair("pooledtx", (uint64_t)nPooledTx));
379 obj.push_back(Pair("testnet", fTestNet));
384 Value getnewaddress(const Array& params, bool fHelp)
386 if (fHelp || params.size() > 1)
388 "getnewaddress [account]\n"
389 "Returns a new bitcoin address for receiving payments. "
390 "If [account] is specified (recommended), it is added to the address book "
391 "so payments received with the address will be credited to [account].");
393 // Parse the account first so we don't generate a key if there's an error
395 if (params.size() > 0)
396 strAccount = AccountFromValue(params[0]);
398 if (!pwalletMain->IsLocked())
399 pwalletMain->TopUpKeyPool();
401 // Generate a new key that is added to wallet
402 std::vector<unsigned char> newKey;
403 if (!pwalletMain->GetKeyFromPool(newKey, false))
404 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
405 CBitcoinAddress address(newKey);
407 pwalletMain->SetAddressBookName(address, strAccount);
409 return address.ToString();
413 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
415 CWalletDB walletdb(pwalletMain->strWalletFile);
418 walletdb.ReadAccount(strAccount, account);
420 bool bKeyUsed = false;
422 // Check if the current key has been used
423 if (!account.vchPubKey.empty())
425 CScript scriptPubKey;
426 scriptPubKey.SetBitcoinAddress(account.vchPubKey);
427 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
428 it != pwalletMain->mapWallet.end() && !account.vchPubKey.empty();
431 const CWalletTx& wtx = (*it).second;
432 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
433 if (txout.scriptPubKey == scriptPubKey)
438 // Generate a new key
439 if (account.vchPubKey.empty() || bForceNew || bKeyUsed)
441 if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false))
442 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
444 pwalletMain->SetAddressBookName(CBitcoinAddress(account.vchPubKey), strAccount);
445 walletdb.WriteAccount(strAccount, account);
448 return CBitcoinAddress(account.vchPubKey);
451 Value getaccountaddress(const Array& params, bool fHelp)
453 if (fHelp || params.size() != 1)
455 "getaccountaddress <account>\n"
456 "Returns the current bitcoin address for receiving payments to this account.");
458 // Parse the account first so we don't generate a key if there's an error
459 string strAccount = AccountFromValue(params[0]);
463 ret = GetAccountAddress(strAccount).ToString();
470 Value setaccount(const Array& params, bool fHelp)
472 if (fHelp || params.size() < 1 || params.size() > 2)
474 "setaccount <bitcoinaddress> <account>\n"
475 "Sets the account associated with the given address.");
477 CBitcoinAddress address(params[0].get_str());
478 if (!address.IsValid())
479 throw JSONRPCError(-5, "Invalid bitcoin address");
483 if (params.size() > 1)
484 strAccount = AccountFromValue(params[1]);
486 // Detect when changing the account of an address that is the 'unused current key' of another account:
487 if (pwalletMain->mapAddressBook.count(address))
489 string strOldAccount = pwalletMain->mapAddressBook[address];
490 if (address == GetAccountAddress(strOldAccount))
491 GetAccountAddress(strOldAccount, true);
494 pwalletMain->SetAddressBookName(address, strAccount);
500 Value getaccount(const Array& params, bool fHelp)
502 if (fHelp || params.size() != 1)
504 "getaccount <bitcoinaddress>\n"
505 "Returns the account associated with the given address.");
507 CBitcoinAddress address(params[0].get_str());
508 if (!address.IsValid())
509 throw JSONRPCError(-5, "Invalid bitcoin address");
512 map<CBitcoinAddress, string>::iterator mi = pwalletMain->mapAddressBook.find(address);
513 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
514 strAccount = (*mi).second;
519 Value getaddressesbyaccount(const Array& params, bool fHelp)
521 if (fHelp || params.size() != 1)
523 "getaddressesbyaccount <account>\n"
524 "Returns the list of addresses for the given account.");
526 string strAccount = AccountFromValue(params[0]);
528 // Find all addresses that have the given account
530 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
532 const CBitcoinAddress& address = item.first;
533 const string& strName = item.second;
534 if (strName == strAccount)
535 ret.push_back(address.ToString());
540 Value settxfee(const Array& params, bool fHelp)
542 if (fHelp || params.size() < 1 || params.size() > 1)
544 "settxfee <amount>\n"
545 "<amount> is a real and is rounded to the nearest 0.00000001");
549 if (params[0].get_real() != 0.0)
550 nAmount = AmountFromValue(params[0]); // rejects 0.0 amounts
552 nTransactionFee = nAmount;
556 Value sendtoaddress(const Array& params, bool fHelp)
558 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
560 "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
561 "<amount> is a real and is rounded to the nearest 0.00000001\n"
562 "requires wallet passphrase to be set with walletpassphrase first");
563 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
565 "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
566 "<amount> is a real and is rounded to the nearest 0.00000001");
568 CBitcoinAddress address(params[0].get_str());
569 if (!address.IsValid())
570 throw JSONRPCError(-5, "Invalid bitcoin address");
573 int64 nAmount = AmountFromValue(params[1]);
577 if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
578 wtx.mapValue["comment"] = params[2].get_str();
579 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
580 wtx.mapValue["to"] = params[3].get_str();
582 if (pwalletMain->IsLocked())
583 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
585 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
587 throw JSONRPCError(-4, strError);
589 return wtx.GetHash().GetHex();
592 static const string strMessageMagic = "Bitcoin Signed Message:\n";
594 Value signmessage(const Array& params, bool fHelp)
596 if (fHelp || params.size() != 2)
598 "signmessage <bitcoinaddress> <message>\n"
599 "Sign a message with the private key of an address");
601 if (pwalletMain->IsLocked())
602 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
604 string strAddress = params[0].get_str();
605 string strMessage = params[1].get_str();
607 CBitcoinAddress addr(strAddress);
609 throw JSONRPCError(-3, "Invalid address");
612 if (!pwalletMain->GetKey(addr, key))
613 throw JSONRPCError(-4, "Private key not available");
615 CDataStream ss(SER_GETHASH);
616 ss << strMessageMagic;
619 vector<unsigned char> vchSig;
620 if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig))
621 throw JSONRPCError(-5, "Sign failed");
623 return EncodeBase64(&vchSig[0], vchSig.size());
626 Value verifymessage(const Array& params, bool fHelp)
628 if (fHelp || params.size() != 3)
630 "verifymessage <bitcoinaddress> <signature> <message>\n"
631 "Verify a signed message");
633 string strAddress = params[0].get_str();
634 string strSign = params[1].get_str();
635 string strMessage = params[2].get_str();
637 CBitcoinAddress addr(strAddress);
639 throw JSONRPCError(-3, "Invalid address");
641 bool fInvalid = false;
642 vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
645 throw JSONRPCError(-5, "Malformed base64 encoding");
647 CDataStream ss(SER_GETHASH);
648 ss << strMessageMagic;
652 if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
655 return (CBitcoinAddress(key.GetPubKey()) == addr);
659 Value getreceivedbyaddress(const Array& params, bool fHelp)
661 if (fHelp || params.size() < 1 || params.size() > 2)
663 "getreceivedbyaddress <bitcoinaddress> [minconf=1]\n"
664 "Returns the total amount received by <bitcoinaddress> in transactions with at least [minconf] confirmations.");
667 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
668 CScript scriptPubKey;
669 if (!address.IsValid())
670 throw JSONRPCError(-5, "Invalid bitcoin address");
671 scriptPubKey.SetBitcoinAddress(address);
672 if (!IsMine(*pwalletMain,scriptPubKey))
675 // Minimum confirmations
677 if (params.size() > 1)
678 nMinDepth = params[1].get_int();
682 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
684 const CWalletTx& wtx = (*it).second;
685 if (wtx.IsCoinBase() || !wtx.IsFinal())
688 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
689 if (txout.scriptPubKey == scriptPubKey)
690 if (wtx.GetDepthInMainChain() >= nMinDepth)
691 nAmount += txout.nValue;
694 return ValueFromAmount(nAmount);
698 void GetAccountAddresses(string strAccount, set<CBitcoinAddress>& setAddress)
700 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
702 const CBitcoinAddress& address = item.first;
703 const string& strName = item.second;
704 if (strName == strAccount)
705 setAddress.insert(address);
710 Value getreceivedbyaccount(const Array& params, bool fHelp)
712 if (fHelp || params.size() < 1 || params.size() > 2)
714 "getreceivedbyaccount <account> [minconf=1]\n"
715 "Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.");
717 // Minimum confirmations
719 if (params.size() > 1)
720 nMinDepth = params[1].get_int();
722 // Get the set of pub keys assigned to account
723 string strAccount = AccountFromValue(params[0]);
724 set<CBitcoinAddress> setAddress;
725 GetAccountAddresses(strAccount, setAddress);
729 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
731 const CWalletTx& wtx = (*it).second;
732 if (wtx.IsCoinBase() || !wtx.IsFinal())
735 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
737 CBitcoinAddress address;
738 if (ExtractAddress(txout.scriptPubKey, address) && pwalletMain->HaveKey(address) && setAddress.count(address))
739 if (wtx.GetDepthInMainChain() >= nMinDepth)
740 nAmount += txout.nValue;
744 return (double)nAmount / (double)COIN;
748 int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth)
752 // Tally wallet transactions
753 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
755 const CWalletTx& wtx = (*it).second;
759 int64 nGenerated, nReceived, nSent, nFee;
760 wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee);
762 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
763 nBalance += nReceived;
764 nBalance += nGenerated - nSent - nFee;
767 // Tally internal accounting entries
768 nBalance += walletdb.GetAccountCreditDebit(strAccount);
773 int64 GetAccountBalance(const string& strAccount, int nMinDepth)
775 CWalletDB walletdb(pwalletMain->strWalletFile);
776 return GetAccountBalance(walletdb, strAccount, nMinDepth);
780 Value getbalance(const Array& params, bool fHelp)
782 if (fHelp || params.size() > 2)
784 "getbalance [account] [minconf=1]\n"
785 "If [account] is not specified, returns the server's total available balance.\n"
786 "If [account] is specified, returns the balance in the account.");
788 if (params.size() == 0)
789 return ValueFromAmount(pwalletMain->GetBalance());
792 if (params.size() > 1)
793 nMinDepth = params[1].get_int();
795 if (params[0].get_str() == "*") {
796 // Calculate total balance a different way from GetBalance()
797 // (GetBalance() sums up all unspent TxOuts)
798 // getbalance and getbalance '*' should always return the same number.
800 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
802 const CWalletTx& wtx = (*it).second;
806 int64 allGeneratedImmature, allGeneratedMature, allFee;
807 allGeneratedImmature = allGeneratedMature = allFee = 0;
808 string strSentAccount;
809 list<pair<CBitcoinAddress, int64> > listReceived;
810 list<pair<CBitcoinAddress, int64> > listSent;
811 wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
812 if (wtx.GetDepthInMainChain() >= nMinDepth)
813 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listReceived)
814 nBalance += r.second;
815 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listSent)
816 nBalance -= r.second;
818 nBalance += allGeneratedMature;
820 return ValueFromAmount(nBalance);
823 string strAccount = AccountFromValue(params[0]);
825 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
827 return ValueFromAmount(nBalance);
831 Value movecmd(const Array& params, bool fHelp)
833 if (fHelp || params.size() < 3 || params.size() > 5)
835 "move <fromaccount> <toaccount> <amount> [minconf=1] [comment]\n"
836 "Move from one account in your wallet to another.");
838 string strFrom = AccountFromValue(params[0]);
839 string strTo = AccountFromValue(params[1]);
840 int64 nAmount = AmountFromValue(params[2]);
841 if (params.size() > 3)
842 // unused parameter, used to be nMinDepth, keep type-checking it though
843 (void)params[3].get_int();
845 if (params.size() > 4)
846 strComment = params[4].get_str();
848 CWalletDB walletdb(pwalletMain->strWalletFile);
851 int64 nNow = GetAdjustedTime();
854 CAccountingEntry debit;
855 debit.strAccount = strFrom;
856 debit.nCreditDebit = -nAmount;
858 debit.strOtherAccount = strTo;
859 debit.strComment = strComment;
860 walletdb.WriteAccountingEntry(debit);
863 CAccountingEntry credit;
864 credit.strAccount = strTo;
865 credit.nCreditDebit = nAmount;
867 credit.strOtherAccount = strFrom;
868 credit.strComment = strComment;
869 walletdb.WriteAccountingEntry(credit);
871 walletdb.TxnCommit();
877 Value sendfrom(const Array& params, bool fHelp)
879 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
881 "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
882 "<amount> is a real and is rounded to the nearest 0.00000001\n"
883 "requires wallet passphrase to be set with walletpassphrase first");
884 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
886 "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
887 "<amount> is a real and is rounded to the nearest 0.00000001");
889 string strAccount = AccountFromValue(params[0]);
890 CBitcoinAddress address(params[1].get_str());
891 if (!address.IsValid())
892 throw JSONRPCError(-5, "Invalid bitcoin address");
893 int64 nAmount = AmountFromValue(params[2]);
895 if (params.size() > 3)
896 nMinDepth = params[3].get_int();
899 wtx.strFromAccount = strAccount;
900 if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
901 wtx.mapValue["comment"] = params[4].get_str();
902 if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
903 wtx.mapValue["to"] = params[5].get_str();
905 if (pwalletMain->IsLocked())
906 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
909 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
910 if (nAmount > nBalance)
911 throw JSONRPCError(-6, "Account has insufficient funds");
914 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
916 throw JSONRPCError(-4, strError);
918 return wtx.GetHash().GetHex();
922 Value sendmany(const Array& params, bool fHelp)
924 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
926 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
927 "amounts are double-precision floating point numbers\n"
928 "requires wallet passphrase to be set with walletpassphrase first");
929 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
931 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
932 "amounts are double-precision floating point numbers");
934 string strAccount = AccountFromValue(params[0]);
935 Object sendTo = params[1].get_obj();
937 if (params.size() > 2)
938 nMinDepth = params[2].get_int();
941 wtx.strFromAccount = strAccount;
942 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
943 wtx.mapValue["comment"] = params[3].get_str();
945 set<CBitcoinAddress> setAddress;
946 vector<pair<CScript, int64> > vecSend;
948 int64 totalAmount = 0;
949 BOOST_FOREACH(const Pair& s, sendTo)
951 CBitcoinAddress address(s.name_);
952 if (!address.IsValid())
953 throw JSONRPCError(-5, string("Invalid bitcoin address:")+s.name_);
955 if (setAddress.count(address))
956 throw JSONRPCError(-8, string("Invalid parameter, duplicated address: ")+s.name_);
957 setAddress.insert(address);
959 CScript scriptPubKey;
960 scriptPubKey.SetBitcoinAddress(address);
961 int64 nAmount = AmountFromValue(s.value_);
962 totalAmount += nAmount;
964 vecSend.push_back(make_pair(scriptPubKey, nAmount));
967 if (pwalletMain->IsLocked())
968 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
971 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
972 if (totalAmount > nBalance)
973 throw JSONRPCError(-6, "Account has insufficient funds");
976 CReserveKey keyChange(pwalletMain);
977 int64 nFeeRequired = 0;
978 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
981 if (totalAmount + nFeeRequired > pwalletMain->GetBalance())
982 throw JSONRPCError(-6, "Insufficient funds");
983 throw JSONRPCError(-4, "Transaction creation failed");
985 if (!pwalletMain->CommitTransaction(wtx, keyChange))
986 throw JSONRPCError(-4, "Transaction commit failed");
988 return wtx.GetHash().GetHex();
991 Value addmultisigaddress(const Array& params, bool fHelp)
993 if (fHelp || params.size() < 2 || params.size() > 3)
995 string msg = "addmultisigaddress <nrequired> <'[\"key\",\"key\"]'> [account]\n"
996 "Add a nrequired-to-sign multisignature address to the wallet\"\n"
997 "each key is a bitcoin address or hex-encoded public key\n"
998 "If [account] is specified, assign address to [account].";
999 throw runtime_error(msg);
1002 throw runtime_error("addmultisigaddress available only when running -testnet\n");
1004 int nRequired = params[0].get_int();
1005 const Array& keys = params[1].get_array();
1007 if (params.size() > 2)
1008 strAccount = AccountFromValue(params[2]);
1010 // Gather public keys
1011 if (nRequired < 1 || keys.size() < nRequired)
1012 throw runtime_error(
1013 strprintf("wrong number of keys"
1014 "(got %d, need at least %d)", keys.size(), nRequired));
1015 std::vector<CKey> pubkeys;
1016 pubkeys.resize(keys.size());
1017 for (int i = 0; i < keys.size(); i++)
1019 const std::string& ks = keys[i].get_str();
1021 // Case 1: bitcoin address and we have full public key:
1022 CBitcoinAddress address(ks);
1023 if (address.IsValid())
1025 if (address.IsScript())
1026 throw runtime_error(
1027 strprintf("%s is a pay-to-script address",ks.c_str()));
1028 std::vector<unsigned char> vchPubKey;
1029 if (!pwalletMain->GetPubKey(address, vchPubKey))
1030 throw runtime_error(
1031 strprintf("no full public key for address %s",ks.c_str()));
1032 if (vchPubKey.empty() || !pubkeys[i].SetPubKey(vchPubKey))
1033 throw runtime_error(" Invalid public key: "+ks);
1036 // Case 2: hex public key
1039 vector<unsigned char> vchPubKey = ParseHex(ks);
1040 if (vchPubKey.empty() || !pubkeys[i].SetPubKey(vchPubKey))
1041 throw runtime_error(" Invalid public key: "+ks);
1045 throw runtime_error(" Invalid public key: "+ks);
1049 // Construct using pay-to-script-hash:
1051 inner.SetMultisig(nRequired, pubkeys);
1053 uint160 scriptHash = Hash160(inner);
1054 CScript scriptPubKey;
1055 scriptPubKey.SetPayToScriptHash(inner);
1056 pwalletMain->AddCScript(inner);
1057 CBitcoinAddress address;
1058 address.SetScriptHash160(scriptHash);
1060 pwalletMain->SetAddressBookName(address, strAccount);
1061 return address.ToString();
1072 nConf = std::numeric_limits<int>::max();
1076 Value ListReceived(const Array& params, bool fByAccounts)
1078 // Minimum confirmations
1080 if (params.size() > 0)
1081 nMinDepth = params[0].get_int();
1083 // Whether to include empty accounts
1084 bool fIncludeEmpty = false;
1085 if (params.size() > 1)
1086 fIncludeEmpty = params[1].get_bool();
1089 map<CBitcoinAddress, tallyitem> mapTally;
1090 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1092 const CWalletTx& wtx = (*it).second;
1094 if (wtx.IsCoinBase() || !wtx.IsFinal())
1097 int nDepth = wtx.GetDepthInMainChain();
1098 if (nDepth < nMinDepth)
1101 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
1103 CBitcoinAddress address;
1104 if (!ExtractAddress(txout.scriptPubKey, address) || !pwalletMain->HaveKey(address) || !address.IsValid())
1107 tallyitem& item = mapTally[address];
1108 item.nAmount += txout.nValue;
1109 item.nConf = min(item.nConf, nDepth);
1115 map<string, tallyitem> mapAccountTally;
1116 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
1118 const CBitcoinAddress& address = item.first;
1119 const string& strAccount = item.second;
1120 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
1121 if (it == mapTally.end() && !fIncludeEmpty)
1125 int nConf = std::numeric_limits<int>::max();
1126 if (it != mapTally.end())
1128 nAmount = (*it).second.nAmount;
1129 nConf = (*it).second.nConf;
1134 tallyitem& item = mapAccountTally[strAccount];
1135 item.nAmount += nAmount;
1136 item.nConf = min(item.nConf, nConf);
1141 obj.push_back(Pair("address", address.ToString()));
1142 obj.push_back(Pair("account", strAccount));
1143 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1144 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1151 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
1153 int64 nAmount = (*it).second.nAmount;
1154 int nConf = (*it).second.nConf;
1156 obj.push_back(Pair("account", (*it).first));
1157 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1158 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1166 Value listreceivedbyaddress(const Array& params, bool fHelp)
1168 if (fHelp || params.size() > 2)
1169 throw runtime_error(
1170 "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
1171 "[minconf] is the minimum number of confirmations before payments are included.\n"
1172 "[includeempty] whether to include addresses that haven't received any payments.\n"
1173 "Returns an array of objects containing:\n"
1174 " \"address\" : receiving address\n"
1175 " \"account\" : the account of the receiving address\n"
1176 " \"amount\" : total amount received by the address\n"
1177 " \"confirmations\" : number of confirmations of the most recent transaction included");
1179 return ListReceived(params, false);
1182 Value listreceivedbyaccount(const Array& params, bool fHelp)
1184 if (fHelp || params.size() > 2)
1185 throw runtime_error(
1186 "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
1187 "[minconf] is the minimum number of confirmations before payments are included.\n"
1188 "[includeempty] whether to include accounts that haven't received any payments.\n"
1189 "Returns an array of objects containing:\n"
1190 " \"account\" : the account of the receiving addresses\n"
1191 " \"amount\" : total amount received by addresses with this account\n"
1192 " \"confirmations\" : number of confirmations of the most recent transaction included");
1194 return ListReceived(params, true);
1197 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret)
1199 int64 nGeneratedImmature, nGeneratedMature, nFee;
1200 string strSentAccount;
1201 list<pair<CBitcoinAddress, int64> > listReceived;
1202 list<pair<CBitcoinAddress, int64> > listSent;
1204 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1206 bool fAllAccounts = (strAccount == string("*"));
1208 // Generated blocks assigned to account ""
1209 if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == ""))
1212 entry.push_back(Pair("account", string("")));
1213 if (nGeneratedImmature)
1215 entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
1216 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
1220 entry.push_back(Pair("category", "generate"));
1221 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
1224 WalletTxToJSON(wtx, entry);
1225 ret.push_back(entry);
1229 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1231 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1234 entry.push_back(Pair("account", strSentAccount));
1235 entry.push_back(Pair("address", s.first.ToString()));
1236 entry.push_back(Pair("category", "send"));
1237 entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1238 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1240 WalletTxToJSON(wtx, entry);
1241 ret.push_back(entry);
1246 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1247 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1250 if (pwalletMain->mapAddressBook.count(r.first))
1251 account = pwalletMain->mapAddressBook[r.first];
1252 if (fAllAccounts || (account == strAccount))
1255 entry.push_back(Pair("account", account));
1256 entry.push_back(Pair("address", r.first.ToString()));
1257 entry.push_back(Pair("category", "receive"));
1258 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1260 WalletTxToJSON(wtx, entry);
1261 ret.push_back(entry);
1266 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1268 bool fAllAccounts = (strAccount == string("*"));
1270 if (fAllAccounts || acentry.strAccount == strAccount)
1273 entry.push_back(Pair("account", acentry.strAccount));
1274 entry.push_back(Pair("category", "move"));
1275 entry.push_back(Pair("time", (boost::int64_t)acentry.nTime));
1276 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1277 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1278 entry.push_back(Pair("comment", acentry.strComment));
1279 ret.push_back(entry);
1283 Value listtransactions(const Array& params, bool fHelp)
1285 if (fHelp || params.size() > 3)
1286 throw runtime_error(
1287 "listtransactions [account] [count=10] [from=0]\n"
1288 "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1290 string strAccount = "*";
1291 if (params.size() > 0)
1292 strAccount = params[0].get_str();
1294 if (params.size() > 1)
1295 nCount = params[1].get_int();
1297 if (params.size() > 2)
1298 nFrom = params[2].get_int();
1301 CWalletDB walletdb(pwalletMain->strWalletFile);
1303 // Firs: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap:
1304 typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
1305 typedef multimap<int64, TxPair > TxItems;
1308 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1310 CWalletTx* wtx = &((*it).second);
1311 txByTime.insert(make_pair(wtx->GetTxTime(), TxPair(wtx, (CAccountingEntry*)0)));
1313 list<CAccountingEntry> acentries;
1314 walletdb.ListAccountCreditDebit(strAccount, acentries);
1315 BOOST_FOREACH(CAccountingEntry& entry, acentries)
1317 txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
1320 // Now: iterate backwards until we have nCount items to return:
1321 TxItems::reverse_iterator it = txByTime.rbegin();
1322 if (txByTime.size() > nFrom) std::advance(it, nFrom);
1323 for (; it != txByTime.rend(); ++it)
1325 CWalletTx *const pwtx = (*it).second.first;
1327 ListTransactions(*pwtx, strAccount, 0, true, ret);
1328 CAccountingEntry *const pacentry = (*it).second.second;
1330 AcentryToJSON(*pacentry, strAccount, ret);
1332 if (ret.size() >= nCount) break;
1334 // ret is now newest to oldest
1336 // Make sure we return only last nCount items (sends-to-self might give us an extra):
1337 if (ret.size() > nCount)
1339 Array::iterator last = ret.begin();
1340 std::advance(last, nCount);
1341 ret.erase(last, ret.end());
1343 std::reverse(ret.begin(), ret.end()); // oldest to newest
1348 Value listaccounts(const Array& params, bool fHelp)
1350 if (fHelp || params.size() > 1)
1351 throw runtime_error(
1352 "listaccounts [minconf=1]\n"
1353 "Returns Object that has account names as keys, account balances as values.");
1356 if (params.size() > 0)
1357 nMinDepth = params[0].get_int();
1359 map<string, int64> mapAccountBalances;
1360 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& entry, pwalletMain->mapAddressBook) {
1361 if (pwalletMain->HaveKey(entry.first)) // This address belongs to me
1362 mapAccountBalances[entry.second] = 0;
1365 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1367 const CWalletTx& wtx = (*it).second;
1368 int64 nGeneratedImmature, nGeneratedMature, nFee;
1369 string strSentAccount;
1370 list<pair<CBitcoinAddress, int64> > listReceived;
1371 list<pair<CBitcoinAddress, int64> > listSent;
1372 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1373 mapAccountBalances[strSentAccount] -= nFee;
1374 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1375 mapAccountBalances[strSentAccount] -= s.second;
1376 if (wtx.GetDepthInMainChain() >= nMinDepth)
1378 mapAccountBalances[""] += nGeneratedMature;
1379 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1380 if (pwalletMain->mapAddressBook.count(r.first))
1381 mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1383 mapAccountBalances[""] += r.second;
1387 list<CAccountingEntry> acentries;
1388 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1389 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1390 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1393 BOOST_FOREACH(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) {
1394 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1399 Value listsinceblock(const Array& params, bool fHelp)
1402 throw runtime_error(
1403 "listsinceblock [blockid] [target-confirmations]\n"
1404 "Get all transactions in blocks since block [blockid], or all transactions if omitted");
1406 CBlockIndex *pindex = NULL;
1407 int target_confirms = 1;
1409 if (params.size() > 0)
1411 uint256 blockId = 0;
1413 blockId.SetHex(params[0].get_str());
1414 pindex = CBlockLocator(blockId).GetBlockIndex();
1417 if (params.size() > 1)
1419 target_confirms = params[1].get_int();
1421 if (target_confirms < 1)
1422 throw JSONRPCError(-8, "Invalid parameter");
1425 int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1;
1429 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1431 CWalletTx tx = (*it).second;
1433 if (depth == -1 || tx.GetDepthInMainChain() < depth)
1434 ListTransactions(tx, "*", 0, true, transactions);
1439 if (target_confirms == 1)
1442 lastblock = hashBestChain;
1446 int target_height = pindexBest->nHeight + 1 - target_confirms;
1449 for (block = pindexBest;
1450 block && block->nHeight > target_height;
1451 block = block->pprev) { }
1453 lastblock = block ? block->GetBlockHash() : 0;
1457 ret.push_back(Pair("transactions", transactions));
1458 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1463 Value gettransaction(const Array& params, bool fHelp)
1465 if (fHelp || params.size() != 1)
1466 throw runtime_error(
1467 "gettransaction <txid>\n"
1468 "Get detailed information about <txid>");
1471 hash.SetHex(params[0].get_str());
1475 if (!pwalletMain->mapWallet.count(hash))
1476 throw JSONRPCError(-5, "Invalid or non-wallet transaction id");
1477 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1479 int64 nCredit = wtx.GetCredit();
1480 int64 nDebit = wtx.GetDebit();
1481 int64 nNet = nCredit - nDebit;
1482 int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
1484 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1486 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1488 WalletTxToJSON(pwalletMain->mapWallet[hash], entry);
1491 ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
1492 entry.push_back(Pair("details", details));
1498 Value backupwallet(const Array& params, bool fHelp)
1500 if (fHelp || params.size() != 1)
1501 throw runtime_error(
1502 "backupwallet <destination>\n"
1503 "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1505 string strDest = params[0].get_str();
1506 BackupWallet(*pwalletMain, strDest);
1512 Value keypoolrefill(const Array& params, bool fHelp)
1514 if (pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1515 throw runtime_error(
1517 "Fills the keypool, requires wallet passphrase to be set.");
1518 if (!pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1519 throw runtime_error(
1521 "Fills the keypool.");
1523 if (pwalletMain->IsLocked())
1524 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
1526 pwalletMain->TopUpKeyPool();
1528 if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100))
1529 throw JSONRPCError(-4, "Error refreshing keypool.");
1535 void ThreadTopUpKeyPool(void* parg)
1537 pwalletMain->TopUpKeyPool();
1540 void ThreadCleanWalletPassphrase(void* parg)
1542 int64 nMyWakeTime = GetTime() + *((int*)parg);
1544 if (nWalletUnlockTime == 0)
1546 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1548 nWalletUnlockTime = nMyWakeTime;
1551 while (GetTime() < nWalletUnlockTime)
1552 Sleep(GetTime() - nWalletUnlockTime);
1554 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1556 nWalletUnlockTime = 0;
1561 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1563 if (nWalletUnlockTime < nMyWakeTime)
1564 nWalletUnlockTime = nMyWakeTime;
1570 pwalletMain->Lock();
1575 Value walletpassphrase(const Array& params, bool fHelp)
1577 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1578 throw runtime_error(
1579 "walletpassphrase <passphrase> <timeout>\n"
1580 "Stores the wallet decryption key in memory for <timeout> seconds.");
1583 if (!pwalletMain->IsCrypted())
1584 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1586 if (!pwalletMain->IsLocked())
1587 throw JSONRPCError(-17, "Error: Wallet is already unlocked.");
1589 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1590 SecureString strWalletPass;
1591 strWalletPass.reserve(100);
1592 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1593 // Alternately, find a way to make params[0] mlock()'d to begin with.
1594 strWalletPass = params[0].get_str().c_str();
1596 if (strWalletPass.length() > 0)
1598 if (!pwalletMain->Unlock(strWalletPass))
1599 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1602 throw runtime_error(
1603 "walletpassphrase <passphrase> <timeout>\n"
1604 "Stores the wallet decryption key in memory for <timeout> seconds.");
1606 CreateThread(ThreadTopUpKeyPool, NULL);
1607 int* pnSleepTime = new int(params[1].get_int());
1608 CreateThread(ThreadCleanWalletPassphrase, pnSleepTime);
1614 Value walletpassphrasechange(const Array& params, bool fHelp)
1616 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1617 throw runtime_error(
1618 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1619 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1622 if (!pwalletMain->IsCrypted())
1623 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1625 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1626 // Alternately, find a way to make params[0] mlock()'d to begin with.
1627 SecureString strOldWalletPass;
1628 strOldWalletPass.reserve(100);
1629 strOldWalletPass = params[0].get_str().c_str();
1631 SecureString strNewWalletPass;
1632 strNewWalletPass.reserve(100);
1633 strNewWalletPass = params[1].get_str().c_str();
1635 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1636 throw runtime_error(
1637 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1638 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1640 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1641 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1647 Value walletlock(const Array& params, bool fHelp)
1649 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1650 throw runtime_error(
1652 "Removes the wallet encryption key from memory, locking the wallet.\n"
1653 "After calling this method, you will need to call walletpassphrase again\n"
1654 "before being able to call any methods which require the wallet to be unlocked.");
1657 if (!pwalletMain->IsCrypted())
1658 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called.");
1660 pwalletMain->Lock();
1661 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1663 nWalletUnlockTime = 0;
1670 Value encryptwallet(const Array& params, bool fHelp)
1672 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1673 throw runtime_error(
1674 "encryptwallet <passphrase>\n"
1675 "Encrypts the wallet with <passphrase>.");
1678 if (pwalletMain->IsCrypted())
1679 throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
1682 // shutting down via RPC while the GUI is running does not work (yet):
1683 throw runtime_error("Not Yet Implemented: use GUI to encrypt wallet, not RPC command");
1686 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1687 // Alternately, find a way to make params[0] mlock()'d to begin with.
1688 SecureString strWalletPass;
1689 strWalletPass.reserve(100);
1690 strWalletPass = params[0].get_str().c_str();
1692 if (strWalletPass.length() < 1)
1693 throw runtime_error(
1694 "encryptwallet <passphrase>\n"
1695 "Encrypts the wallet with <passphrase>.");
1697 if (!pwalletMain->EncryptWallet(strWalletPass))
1698 throw JSONRPCError(-16, "Error: Failed to encrypt the wallet.");
1700 // BDB seems to have a bad habit of writing old data into
1701 // slack space in .dat files; that is bad if the old data is
1702 // unencrypted private keys. So:
1703 CreateThread(Shutdown, NULL);
1704 return "wallet encrypted; bitcoin server stopping, restart to run with encrypted wallet";
1708 Value validateaddress(const Array& params, bool fHelp)
1710 if (fHelp || params.size() != 1)
1711 throw runtime_error(
1712 "validateaddress <bitcoinaddress>\n"
1713 "Return information about <bitcoinaddress>.");
1715 CBitcoinAddress address(params[0].get_str());
1716 bool isValid = address.IsValid();
1719 ret.push_back(Pair("isvalid", isValid));
1722 // Call Hash160ToAddress() so we always return current ADDRESSVERSION
1723 // version of the address:
1724 string currentAddress = address.ToString();
1725 ret.push_back(Pair("address", currentAddress));
1726 if (pwalletMain->HaveKey(address))
1728 ret.push_back(Pair("ismine", true));
1729 std::vector<unsigned char> vchPubKey;
1730 pwalletMain->GetPubKey(address, vchPubKey);
1731 ret.push_back(Pair("pubkey", HexStr(vchPubKey)));
1733 key.SetPubKey(vchPubKey);
1734 ret.push_back(Pair("iscompressed", key.IsCompressed()));
1736 else if (pwalletMain->HaveCScript(address.GetHash160()))
1738 ret.push_back(Pair("isscript", true));
1740 pwalletMain->GetCScript(address.GetHash160(), subscript);
1741 ret.push_back(Pair("ismine", ::IsMine(*pwalletMain, subscript)));
1742 std::vector<CBitcoinAddress> addresses;
1743 txnouttype whichType;
1745 ExtractAddresses(subscript, whichType, addresses, nRequired);
1746 ret.push_back(Pair("script", GetTxnOutputType(whichType)));
1748 BOOST_FOREACH(const CBitcoinAddress& addr, addresses)
1749 a.push_back(addr.ToString());
1750 ret.push_back(Pair("addresses", a));
1751 if (whichType == TX_MULTISIG)
1752 ret.push_back(Pair("sigsrequired", nRequired));
1755 ret.push_back(Pair("ismine", false));
1756 if (pwalletMain->mapAddressBook.count(address))
1757 ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
1762 Value getwork(const Array& params, bool fHelp)
1764 if (fHelp || params.size() > 1)
1765 throw runtime_error(
1767 "If [data] is not specified, returns formatted hash data to work on:\n"
1768 " \"midstate\" : precomputed hash state after hashing the first half of the data (DEPRECATED)\n" // deprecated
1769 " \"data\" : block data\n"
1770 " \"hash1\" : formatted hash buffer for second hash (DEPRECATED)\n" // deprecated
1771 " \"target\" : little endian hash target\n"
1772 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1775 throw JSONRPCError(-9, "Bitcoin is not connected!");
1777 if (IsInitialBlockDownload())
1778 throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
1780 typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
1781 static mapNewBlock_t mapNewBlock;
1782 static vector<CBlock*> vNewBlock;
1783 static CReserveKey reservekey(pwalletMain);
1785 if (params.size() == 0)
1788 static unsigned int nTransactionsUpdatedLast;
1789 static CBlockIndex* pindexPrev;
1790 static int64 nStart;
1791 static CBlock* pblock;
1792 if (pindexPrev != pindexBest ||
1793 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
1795 if (pindexPrev != pindexBest)
1797 // Deallocate old blocks since they're obsolete now
1798 mapNewBlock.clear();
1799 BOOST_FOREACH(CBlock* pblock, vNewBlock)
1803 nTransactionsUpdatedLast = nTransactionsUpdated;
1804 pindexPrev = pindexBest;
1808 pblock = CreateNewBlock(reservekey);
1810 throw JSONRPCError(-7, "Out of memory");
1811 vNewBlock.push_back(pblock);
1815 pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
1818 // Update nExtraNonce
1819 static unsigned int nExtraNonce = 0;
1820 IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
1823 mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
1825 // Prebuild hash buffers
1829 FormatHashBuffers(pblock, pmidstate, pdata, phash1);
1831 uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
1834 result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate)))); // deprecated
1835 result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata))));
1836 result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1)))); // deprecated
1837 result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
1843 vector<unsigned char> vchData = ParseHex(params[0].get_str());
1844 if (vchData.size() != 128)
1845 throw JSONRPCError(-8, "Invalid parameter");
1846 CBlock* pdata = (CBlock*)&vchData[0];
1849 for (int i = 0; i < 128/4; i++)
1850 ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]);
1853 if (!mapNewBlock.count(pdata->hashMerkleRoot))
1855 CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
1857 pblock->nTime = pdata->nTime;
1858 pblock->nNonce = pdata->nNonce;
1859 pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
1860 pblock->hashMerkleRoot = pblock->BuildMerkleTree();
1862 return CheckWork(pblock, *pwalletMain, reservekey);
1867 Value getmemorypool(const Array& params, bool fHelp)
1869 if (fHelp || params.size() > 1)
1870 throw runtime_error(
1871 "getmemorypool [data]\n"
1872 "If [data] is not specified, returns data needed to construct a block to work on:\n"
1873 " \"version\" : block version\n"
1874 " \"previousblockhash\" : hash of current highest block\n"
1875 " \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
1876 " \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
1877 " \"coinbaseflags\" : data that should be included in coinbase so support for new features can be judged\n"
1878 " \"time\" : timestamp appropriate for next block\n"
1879 " \"mintime\" : minimum timestamp appropriate for next block\n"
1880 " \"curtime\" : current timestamp\n"
1881 " \"bits\" : compressed target of next block\n"
1882 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1884 if (params.size() == 0)
1887 throw JSONRPCError(-9, "Bitcoin is not connected!");
1889 if (IsInitialBlockDownload())
1890 throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
1892 static CReserveKey reservekey(pwalletMain);
1895 static unsigned int nTransactionsUpdatedLast;
1896 static CBlockIndex* pindexPrev;
1897 static int64 nStart;
1898 static CBlock* pblock;
1899 if (pindexPrev != pindexBest ||
1900 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5))
1902 nTransactionsUpdatedLast = nTransactionsUpdated;
1903 pindexPrev = pindexBest;
1909 pblock = CreateNewBlock(reservekey);
1911 throw JSONRPCError(-7, "Out of memory");
1915 pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
1919 BOOST_FOREACH(CTransaction tx, pblock->vtx) {
1926 transactions.push_back(HexStr(ssTx.begin(), ssTx.end()));
1930 result.push_back(Pair("version", pblock->nVersion));
1931 result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
1932 result.push_back(Pair("transactions", transactions));
1933 result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
1934 result.push_back(Pair("coinbaseflags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end())));
1935 result.push_back(Pair("time", (int64_t)pblock->nTime));
1936 result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1));
1937 result.push_back(Pair("curtime", (int64_t)GetAdjustedTime()));
1943 uBits.nBits = htonl((int32_t)pblock->nBits);
1944 result.push_back(Pair("bits", HexStr(BEGIN(uBits.cBits), END(uBits.cBits))));
1951 CDataStream ssBlock(ParseHex(params[0].get_str()));
1955 return ProcessBlock(NULL, &pblock);
1959 Value getblockhash(const Array& params, bool fHelp)
1961 if (fHelp || params.size() != 1)
1962 throw runtime_error(
1963 "getblockhash <index>\n"
1964 "Returns hash of block in best-block-chain at <index>.");
1966 int nHeight = params[0].get_int();
1967 if (nHeight < 0 || nHeight > nBestHeight)
1968 throw runtime_error("Block number out of range.");
1971 CBlockIndex* pblockindex = mapBlockIndex[hashBestChain];
1972 while (pblockindex->nHeight > nHeight)
1973 pblockindex = pblockindex->pprev;
1974 return pblockindex->phashBlock->GetHex();
1977 Value getblock(const Array& params, bool fHelp)
1979 if (fHelp || params.size() != 1)
1980 throw runtime_error(
1982 "Returns details of a block with given block-hash.");
1984 std::string strHash = params[0].get_str();
1985 uint256 hash(strHash);
1987 if (mapBlockIndex.count(hash) == 0)
1988 throw JSONRPCError(-5, "Block not found");
1991 CBlockIndex* pblockindex = mapBlockIndex[hash];
1992 block.ReadFromDisk(pblockindex, true);
1994 return blockToJSON(block, pblockindex);
2011 pair<string, rpcfn_type> pCallTable[] =
2013 make_pair("help", &help),
2014 make_pair("stop", &stop),
2015 make_pair("getblockcount", &getblockcount),
2016 make_pair("getblocknumber", &getblocknumber),
2017 make_pair("getconnectioncount", &getconnectioncount),
2018 make_pair("getdifficulty", &getdifficulty),
2019 make_pair("getgenerate", &getgenerate),
2020 make_pair("setgenerate", &setgenerate),
2021 make_pair("gethashespersec", &gethashespersec),
2022 make_pair("getinfo", &getinfo),
2023 make_pair("getmininginfo", &getmininginfo),
2024 make_pair("getnewaddress", &getnewaddress),
2025 make_pair("getaccountaddress", &getaccountaddress),
2026 make_pair("setaccount", &setaccount),
2027 make_pair("getaccount", &getaccount),
2028 make_pair("getaddressesbyaccount", &getaddressesbyaccount),
2029 make_pair("sendtoaddress", &sendtoaddress),
2030 make_pair("getreceivedbyaddress", &getreceivedbyaddress),
2031 make_pair("getreceivedbyaccount", &getreceivedbyaccount),
2032 make_pair("listreceivedbyaddress", &listreceivedbyaddress),
2033 make_pair("listreceivedbyaccount", &listreceivedbyaccount),
2034 make_pair("backupwallet", &backupwallet),
2035 make_pair("keypoolrefill", &keypoolrefill),
2036 make_pair("walletpassphrase", &walletpassphrase),
2037 make_pair("walletpassphrasechange", &walletpassphrasechange),
2038 make_pair("walletlock", &walletlock),
2039 make_pair("encryptwallet", &encryptwallet),
2040 make_pair("validateaddress", &validateaddress),
2041 make_pair("getbalance", &getbalance),
2042 make_pair("move", &movecmd),
2043 make_pair("sendfrom", &sendfrom),
2044 make_pair("sendmany", &sendmany),
2045 make_pair("addmultisigaddress", &addmultisigaddress),
2046 make_pair("getblock", &getblock),
2047 make_pair("getblockhash", &getblockhash),
2048 make_pair("gettransaction", &gettransaction),
2049 make_pair("listtransactions", &listtransactions),
2050 make_pair("signmessage", &signmessage),
2051 make_pair("verifymessage", &verifymessage),
2052 make_pair("getwork", &getwork),
2053 make_pair("listaccounts", &listaccounts),
2054 make_pair("settxfee", &settxfee),
2055 make_pair("getmemorypool", &getmemorypool),
2056 make_pair("listsinceblock", &listsinceblock),
2057 make_pair("dumpprivkey", &dumpprivkey),
2058 make_pair("importprivkey", &importprivkey)
2060 map<string, rpcfn_type> mapCallTable(pCallTable, pCallTable + sizeof(pCallTable)/sizeof(pCallTable[0]));
2062 string pAllowInSafeMode[] =
2067 "getblocknumber", // deprecated
2068 "getconnectioncount",
2076 "getaccountaddress",
2078 "getaddressesbyaccount",
2087 set<string> setAllowInSafeMode(pAllowInSafeMode, pAllowInSafeMode + sizeof(pAllowInSafeMode)/sizeof(pAllowInSafeMode[0]));
2095 // This ain't Apache. We're just using HTTP header for the length field
2096 // and to be compatible with other JSON-RPC implementations.
2099 string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
2102 s << "POST / HTTP/1.1\r\n"
2103 << "User-Agent: bitcoin-json-rpc/" << FormatFullVersion() << "\r\n"
2104 << "Host: 127.0.0.1\r\n"
2105 << "Content-Type: application/json\r\n"
2106 << "Content-Length: " << strMsg.size() << "\r\n"
2107 << "Connection: close\r\n"
2108 << "Accept: application/json\r\n";
2109 BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
2110 s << item.first << ": " << item.second << "\r\n";
2111 s << "\r\n" << strMsg;
2116 string rfc1123Time()
2121 struct tm* now_gmt = gmtime(&now);
2122 string locale(setlocale(LC_TIME, NULL));
2123 setlocale(LC_TIME, "C"); // we want posix (aka "C") weekday/month strings
2124 strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt);
2125 setlocale(LC_TIME, locale.c_str());
2126 return string(buffer);
2129 static string HTTPReply(int nStatus, const string& strMsg)
2132 return strprintf("HTTP/1.0 401 Authorization Required\r\n"
2134 "Server: bitcoin-json-rpc/%s\r\n"
2135 "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
2136 "Content-Type: text/html\r\n"
2137 "Content-Length: 296\r\n"
2139 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
2140 "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
2143 "<TITLE>Error</TITLE>\r\n"
2144 "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
2146 "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
2147 "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
2148 const char *cStatus;
2149 if (nStatus == 200) cStatus = "OK";
2150 else if (nStatus == 400) cStatus = "Bad Request";
2151 else if (nStatus == 403) cStatus = "Forbidden";
2152 else if (nStatus == 404) cStatus = "Not Found";
2153 else if (nStatus == 500) cStatus = "Internal Server Error";
2156 "HTTP/1.1 %d %s\r\n"
2158 "Connection: close\r\n"
2159 "Content-Length: %d\r\n"
2160 "Content-Type: application/json\r\n"
2161 "Server: bitcoin-json-rpc/%s\r\n"
2166 rfc1123Time().c_str(),
2168 FormatFullVersion().c_str(),
2172 int ReadHTTPStatus(std::basic_istream<char>& stream)
2175 getline(stream, str);
2176 vector<string> vWords;
2177 boost::split(vWords, str, boost::is_any_of(" "));
2178 if (vWords.size() < 2)
2180 return atoi(vWords[1].c_str());
2183 int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
2189 std::getline(stream, str);
2190 if (str.empty() || str == "\r")
2192 string::size_type nColon = str.find(":");
2193 if (nColon != string::npos)
2195 string strHeader = str.substr(0, nColon);
2196 boost::trim(strHeader);
2197 boost::to_lower(strHeader);
2198 string strValue = str.substr(nColon+1);
2199 boost::trim(strValue);
2200 mapHeadersRet[strHeader] = strValue;
2201 if (strHeader == "content-length")
2202 nLen = atoi(strValue.c_str());
2208 int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
2210 mapHeadersRet.clear();
2214 int nStatus = ReadHTTPStatus(stream);
2217 int nLen = ReadHTTPHeader(stream, mapHeadersRet);
2218 if (nLen < 0 || nLen > MAX_SIZE)
2224 vector<char> vch(nLen);
2225 stream.read(&vch[0], nLen);
2226 strMessageRet = string(vch.begin(), vch.end());
2232 bool HTTPAuthorized(map<string, string>& mapHeaders)
2234 string strAuth = mapHeaders["authorization"];
2235 if (strAuth.substr(0,6) != "Basic ")
2237 string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
2238 string strUserPass = DecodeBase64(strUserPass64);
2239 return strUserPass == strRPCUserColonPass;
2243 // JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
2244 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
2245 // unspecified (HTTP errors and contents of 'error').
2247 // 1.0 spec: http://json-rpc.org/wiki/specification
2248 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
2249 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
2252 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
2255 request.push_back(Pair("method", strMethod));
2256 request.push_back(Pair("params", params));
2257 request.push_back(Pair("id", id));
2258 return write_string(Value(request), false) + "\n";
2261 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
2264 if (error.type() != null_type)
2265 reply.push_back(Pair("result", Value::null));
2267 reply.push_back(Pair("result", result));
2268 reply.push_back(Pair("error", error));
2269 reply.push_back(Pair("id", id));
2270 return write_string(Value(reply), false) + "\n";
2273 void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
2275 // Send error reply from json-rpc error object
2277 int code = find_value(objError, "code").get_int();
2278 if (code == -32600) nStatus = 400;
2279 else if (code == -32601) nStatus = 404;
2280 string strReply = JSONRPCReply(Value::null, objError, id);
2281 stream << HTTPReply(nStatus, strReply) << std::flush;
2284 bool ClientAllowed(const string& strAddress)
2286 if (strAddress == asio::ip::address_v4::loopback().to_string())
2288 const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
2289 BOOST_FOREACH(string strAllow, vAllow)
2290 if (WildcardMatch(strAddress, strAllow))
2297 // IOStream device that speaks SSL but can also speak non-SSL
2299 class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
2301 SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
2303 fUseSSL = fUseSSLIn;
2304 fNeedHandshake = fUseSSLIn;
2307 void handshake(ssl::stream_base::handshake_type role)
2309 if (!fNeedHandshake) return;
2310 fNeedHandshake = false;
2311 stream.handshake(role);
2313 std::streamsize read(char* s, std::streamsize n)
2315 handshake(ssl::stream_base::server); // HTTPS servers read first
2316 if (fUseSSL) return stream.read_some(asio::buffer(s, n));
2317 return stream.next_layer().read_some(asio::buffer(s, n));
2319 std::streamsize write(const char* s, std::streamsize n)
2321 handshake(ssl::stream_base::client); // HTTPS clients write first
2322 if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
2323 return asio::write(stream.next_layer(), asio::buffer(s, n));
2325 bool connect(const std::string& server, const std::string& port)
2327 ip::tcp::resolver resolver(stream.get_io_service());
2328 ip::tcp::resolver::query query(server.c_str(), port.c_str());
2329 ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
2330 ip::tcp::resolver::iterator end;
2331 boost::system::error_code error = asio::error::host_not_found;
2332 while (error && endpoint_iterator != end)
2334 stream.lowest_layer().close();
2335 stream.lowest_layer().connect(*endpoint_iterator++, error);
2343 bool fNeedHandshake;
2349 void ThreadRPCServer(void* parg)
2351 IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
2354 vnThreadsRunning[4]++;
2355 ThreadRPCServer2(parg);
2356 vnThreadsRunning[4]--;
2358 catch (std::exception& e) {
2359 vnThreadsRunning[4]--;
2360 PrintException(&e, "ThreadRPCServer()");
2362 vnThreadsRunning[4]--;
2363 PrintException(NULL, "ThreadRPCServer()");
2365 printf("ThreadRPCServer exiting\n");
2368 void ThreadRPCServer2(void* parg)
2370 printf("ThreadRPCServer started\n");
2372 strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
2373 if (strRPCUserColonPass == ":")
2375 string strWhatAmI = "To use bitcoind";
2376 if (mapArgs.count("-server"))
2377 strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
2378 else if (mapArgs.count("-daemon"))
2379 strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
2381 _("Error: %s, you must set rpcpassword=<password>\nin the configuration file: %s\n"
2382 "If the file does not exist, create it with owner-readable-only file permissions.\n"),
2384 GetConfigFile().c_str());
2386 CreateThread(Shutdown, NULL);
2391 bool fUseSSL = GetBoolArg("-rpcssl");
2392 asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
2394 asio::io_service io_service;
2395 ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", 8332));
2396 ip::tcp::acceptor acceptor(io_service, endpoint);
2398 acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
2401 ssl::context context(io_service, ssl::context::sslv23);
2404 context.set_options(ssl::context::no_sslv2);
2405 filesystem::path certfile = GetArg("-rpcsslcertificatechainfile", "server.cert");
2406 if (!certfile.is_complete()) certfile = filesystem::path(GetDataDir()) / certfile;
2407 if (filesystem::exists(certfile)) context.use_certificate_chain_file(certfile.string().c_str());
2408 else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", certfile.string().c_str());
2409 filesystem::path pkfile = GetArg("-rpcsslprivatekeyfile", "server.pem");
2410 if (!pkfile.is_complete()) pkfile = filesystem::path(GetDataDir()) / pkfile;
2411 if (filesystem::exists(pkfile)) context.use_private_key_file(pkfile.string().c_str(), ssl::context::pem);
2412 else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pkfile.string().c_str());
2414 string ciphers = GetArg("-rpcsslciphers",
2415 "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
2416 SSL_CTX_set_cipher_list(context.impl(), ciphers.c_str());
2420 throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
2425 // Accept connection
2427 SSLStream sslStream(io_service, context);
2428 SSLIOStreamDevice d(sslStream, fUseSSL);
2429 iostreams::stream<SSLIOStreamDevice> stream(d);
2431 ip::tcp::iostream stream;
2434 ip::tcp::endpoint peer;
2435 vnThreadsRunning[4]--;
2437 acceptor.accept(sslStream.lowest_layer(), peer);
2439 acceptor.accept(*stream.rdbuf(), peer);
2441 vnThreadsRunning[4]++;
2445 // Restrict callers by IP
2446 if (!ClientAllowed(peer.address().to_string()))
2448 // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
2450 stream << HTTPReply(403, "") << std::flush;
2454 map<string, string> mapHeaders;
2457 boost::thread api_caller(ReadHTTP, boost::ref(stream), boost::ref(mapHeaders), boost::ref(strRequest));
2458 if (!api_caller.timed_join(boost::posix_time::seconds(GetArg("-rpctimeout", 30))))
2461 printf("ThreadRPCServer ReadHTTP timeout\n");
2465 // Check authorization
2466 if (mapHeaders.count("authorization") == 0)
2468 stream << HTTPReply(401, "") << std::flush;
2471 if (!HTTPAuthorized(mapHeaders))
2473 // Deter brute-forcing short passwords
2474 if (mapArgs["-rpcpassword"].size() < 15)
2477 stream << HTTPReply(401, "") << std::flush;
2478 printf("ThreadRPCServer incorrect password attempt\n");
2482 Value id = Value::null;
2487 if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
2488 throw JSONRPCError(-32700, "Parse error");
2489 const Object& request = valRequest.get_obj();
2491 // Parse id now so errors from here on will have the id
2492 id = find_value(request, "id");
2495 Value valMethod = find_value(request, "method");
2496 if (valMethod.type() == null_type)
2497 throw JSONRPCError(-32600, "Missing method");
2498 if (valMethod.type() != str_type)
2499 throw JSONRPCError(-32600, "Method must be a string");
2500 string strMethod = valMethod.get_str();
2501 if (strMethod != "getwork" && strMethod != "getmemorypool")
2502 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
2505 Value valParams = find_value(request, "params");
2507 if (valParams.type() == array_type)
2508 params = valParams.get_array();
2509 else if (valParams.type() == null_type)
2512 throw JSONRPCError(-32600, "Params must be an array");
2515 map<string, rpcfn_type>::iterator mi = mapCallTable.find(strMethod);
2516 if (mi == mapCallTable.end())
2517 throw JSONRPCError(-32601, "Method not found");
2519 // Observe safe mode
2520 string strWarning = GetWarnings("rpc");
2521 if (strWarning != "" && !GetBoolArg("-disablesafemode") && !setAllowInSafeMode.count(strMethod))
2522 throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
2528 CRITICAL_BLOCK(cs_main)
2529 CRITICAL_BLOCK(pwalletMain->cs_wallet)
2530 result = (*(*mi).second)(params, false);
2533 string strReply = JSONRPCReply(result, Value::null, id);
2534 stream << HTTPReply(200, strReply) << std::flush;
2536 catch (std::exception& e)
2538 ErrorReply(stream, JSONRPCError(-1, e.what()), id);
2541 catch (Object& objError)
2543 ErrorReply(stream, objError, id);
2545 catch (std::exception& e)
2547 ErrorReply(stream, JSONRPCError(-32700, e.what()), id);
2555 Object CallRPC(const string& strMethod, const Array& params)
2557 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2558 throw runtime_error(strprintf(
2559 _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
2560 "If the file does not exist, create it with owner-readable-only file permissions."),
2561 GetConfigFile().c_str()));
2563 // Connect to localhost
2564 bool fUseSSL = GetBoolArg("-rpcssl");
2566 asio::io_service io_service;
2567 ssl::context context(io_service, ssl::context::sslv23);
2568 context.set_options(ssl::context::no_sslv2);
2569 SSLStream sslStream(io_service, context);
2570 SSLIOStreamDevice d(sslStream, fUseSSL);
2571 iostreams::stream<SSLIOStreamDevice> stream(d);
2572 if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332")))
2573 throw runtime_error("couldn't connect to server");
2576 throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
2578 ip::tcp::iostream stream(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332"));
2580 throw runtime_error("couldn't connect to server");
2584 // HTTP basic authentication
2585 string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
2586 map<string, string> mapRequestHeaders;
2587 mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
2590 string strRequest = JSONRPCRequest(strMethod, params, 1);
2591 string strPost = HTTPPost(strRequest, mapRequestHeaders);
2592 stream << strPost << std::flush;
2595 map<string, string> mapHeaders;
2597 int nStatus = ReadHTTP(stream, mapHeaders, strReply);
2599 throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
2600 else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
2601 throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
2602 else if (strReply.empty())
2603 throw runtime_error("no response from server");
2607 if (!read_string(strReply, valReply))
2608 throw runtime_error("couldn't parse reply from server");
2609 const Object& reply = valReply.get_obj();
2611 throw runtime_error("expected reply to have result, error and id properties");
2619 template<typename T>
2620 void ConvertTo(Value& value)
2622 if (value.type() == str_type)
2624 // reinterpret string as unquoted json value
2626 if (!read_string(value.get_str(), value2))
2627 throw runtime_error("type mismatch");
2628 value = value2.get_value<T>();
2632 value = value.get_value<T>();
2636 int CommandLineRPC(int argc, char *argv[])
2643 while (argc > 1 && IsSwitchChar(argv[1][0]))
2651 throw runtime_error("too few parameters");
2652 string strMethod = argv[1];
2654 // Parameters default to strings
2656 for (int i = 2; i < argc; i++)
2657 params.push_back(argv[i]);
2658 int n = params.size();
2661 // Special case non-string parameter types
2663 if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
2664 if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2665 if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
2666 if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]);
2667 if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2668 if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2669 if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2670 if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
2671 if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2672 if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
2673 if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2674 if (strMethod == "getblockhash" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2675 if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]);
2676 if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2677 if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]);
2678 if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2679 if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2680 if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2681 if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2682 if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2683 if (strMethod == "listsinceblock" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2684 if (strMethod == "sendmany" && n > 1)
2686 string s = params[1].get_str();
2688 if (!read_string(s, v) || v.type() != obj_type)
2689 throw runtime_error("type mismatch");
2690 params[1] = v.get_obj();
2692 if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2693 if (strMethod == "addmultisigaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2694 if (strMethod == "addmultisigaddress" && n > 1)
2696 string s = params[1].get_str();
2698 if (!read_string(s, v) || v.type() != array_type)
2699 throw runtime_error("type mismatch "+s);
2700 params[1] = v.get_array();
2704 Object reply = CallRPC(strMethod, params);
2707 const Value& result = find_value(reply, "result");
2708 const Value& error = find_value(reply, "error");
2710 if (error.type() != null_type)
2713 strPrint = "error: " + write_string(error, false);
2714 int code = find_value(error.get_obj(), "code").get_int();
2720 if (result.type() == null_type)
2722 else if (result.type() == str_type)
2723 strPrint = result.get_str();
2725 strPrint = write_string(result, true);
2728 catch (std::exception& e)
2730 strPrint = string("error: ") + e.what();
2735 PrintException(NULL, "CommandLineRPC()");
2740 fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
2749 int main(int argc, char *argv[])
2752 // Turn off microsoft heap dump noise
2753 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
2754 _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
2756 setbuf(stdin, NULL);
2757 setbuf(stdout, NULL);
2758 setbuf(stderr, NULL);
2762 if (argc >= 2 && string(argv[1]) == "-server")
2764 printf("server ready\n");
2765 ThreadRPCServer(NULL);
2769 return CommandLineRPC(argc, argv);
2772 catch (std::exception& e) {
2773 PrintException(&e, "main()");
2775 PrintException(NULL, "main()");