1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2012 The Bitcoin developers
3 // Distributed under the MIT/X11 software license, see the accompanying
4 // file license.txt or http://www.opensource.org/licenses/mit-license.php.
11 #include <boost/asio.hpp>
12 #include <boost/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;
124 HexBits(unsigned int nBits)
130 uBits.nBits = htonl((int32_t)nBits);
131 return HexStr(BEGIN(uBits.cBits), END(uBits.cBits));
134 void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
136 int confirms = wtx.GetDepthInMainChain();
137 entry.push_back(Pair("confirmations", confirms));
140 entry.push_back(Pair("blockhash", wtx.hashBlock.GetHex()));
141 entry.push_back(Pair("blockindex", wtx.nIndex));
143 entry.push_back(Pair("txid", wtx.GetHash().GetHex()));
144 entry.push_back(Pair("time", (boost::int64_t)wtx.GetTxTime()));
145 BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
146 entry.push_back(Pair(item.first, item.second));
149 string AccountFromValue(const Value& value)
151 string strAccount = value.get_str();
152 if (strAccount == "*")
153 throw JSONRPCError(-11, "Invalid account name");
157 Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex)
160 result.push_back(Pair("hash", block.GetHash().GetHex()));
161 result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK)));
162 result.push_back(Pair("height", blockindex->nHeight));
163 result.push_back(Pair("version", block.nVersion));
164 result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex()));
165 result.push_back(Pair("time", (boost::int64_t)block.GetBlockTime()));
166 result.push_back(Pair("nonce", (boost::uint64_t)block.nNonce));
167 result.push_back(Pair("bits", HexBits(block.nBits)));
168 result.push_back(Pair("difficulty", GetDifficulty(blockindex)));
170 BOOST_FOREACH (const CTransaction&tx, block.vtx)
171 txhashes.push_back(tx.GetHash().GetHex());
172 result.push_back(Pair("tx", txhashes));
174 if (blockindex->pprev)
175 result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex()));
176 if (blockindex->pnext)
177 result.push_back(Pair("nextblockhash", blockindex->pnext->GetBlockHash().GetHex()));
184 /// Note: This interface may still be subject to change.
188 Value help(const Array& params, bool fHelp)
190 if (fHelp || params.size() > 1)
193 "List commands, or get help for a command.");
196 if (params.size() > 0)
197 strCommand = params[0].get_str();
200 set<rpcfn_type> setDone;
201 for (map<string, rpcfn_type>::iterator mi = mapCallTable.begin(); mi != mapCallTable.end(); ++mi)
203 string strMethod = (*mi).first;
204 // We already filter duplicates, but these deprecated screw up the sort order
205 if (strMethod == "getamountreceived" ||
206 strMethod == "getallreceived" ||
207 strMethod == "getblocknumber" || // deprecated
208 (strMethod.find("label") != string::npos))
210 if (strCommand != "" && strMethod != strCommand)
215 rpcfn_type pfn = (*mi).second;
216 if (setDone.insert(pfn).second)
217 (*pfn)(params, true);
219 catch (std::exception& e)
221 // Help text is returned in an exception
222 string strHelp = string(e.what());
223 if (strCommand == "")
224 if (strHelp.find('\n') != -1)
225 strHelp = strHelp.substr(0, strHelp.find('\n'));
226 strRet += strHelp + "\n";
230 strRet = strprintf("help: unknown command: %s\n", strCommand.c_str());
231 strRet = strRet.substr(0,strRet.size()-1);
236 Value stop(const Array& params, bool fHelp)
238 if (fHelp || params.size() != 0)
241 "Stop bitcoin server.");
243 // Shutdown will take long enough that the response should get back
244 CreateThread(Shutdown, NULL);
245 return "bitcoin server stopping";
247 throw runtime_error("NYI: cannot shut down GUI with RPC command");
252 Value getblockcount(const Array& params, bool fHelp)
254 if (fHelp || params.size() != 0)
257 "Returns the number of blocks in the longest block chain.");
264 Value getblocknumber(const Array& params, bool fHelp)
266 if (fHelp || params.size() != 0)
269 "Deprecated. Use getblockcount.");
275 Value getconnectioncount(const Array& params, bool fHelp)
277 if (fHelp || params.size() != 0)
279 "getconnectioncount\n"
280 "Returns the number of connections to other nodes.");
282 return (int)vNodes.size();
286 Value getdifficulty(const Array& params, bool fHelp)
288 if (fHelp || params.size() != 0)
291 "Returns the proof-of-work difficulty as a multiple of the minimum difficulty.");
293 return GetDifficulty();
297 Value getgenerate(const Array& params, bool fHelp)
299 if (fHelp || params.size() != 0)
302 "Returns true or false.");
304 return GetBoolArg("-gen");
308 Value setgenerate(const Array& params, bool fHelp)
310 if (fHelp || params.size() < 1 || params.size() > 2)
312 "setgenerate <generate> [genproclimit]\n"
313 "<generate> is true or false to turn generation on or off.\n"
314 "Generation is limited to [genproclimit] processors, -1 is unlimited.");
316 bool fGenerate = true;
317 if (params.size() > 0)
318 fGenerate = params[0].get_bool();
320 if (params.size() > 1)
322 int nGenProcLimit = params[1].get_int();
323 mapArgs["-genproclimit"] = itostr(nGenProcLimit);
324 if (nGenProcLimit == 0)
327 mapArgs["-gen"] = (fGenerate ? "1" : "0");
329 GenerateBitcoins(fGenerate, pwalletMain);
334 Value gethashespersec(const Array& params, bool fHelp)
336 if (fHelp || params.size() != 0)
339 "Returns a recent hashes per second performance measurement while generating.");
341 if (GetTimeMillis() - nHPSTimerStart > 8000)
342 return (boost::int64_t)0;
343 return (boost::int64_t)dHashesPerSec;
347 Value getinfo(const Array& params, bool fHelp)
349 if (fHelp || params.size() != 0)
352 "Returns an object containing various state info.");
355 obj.push_back(Pair("version", (int)CLIENT_VERSION));
356 obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION));
357 obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
358 obj.push_back(Pair("blocks", (int)nBestHeight));
359 obj.push_back(Pair("connections", (int)vNodes.size()));
360 obj.push_back(Pair("proxy", (fUseProxy ? addrProxy.ToStringIPPort() : string())));
361 obj.push_back(Pair("difficulty", (double)GetDifficulty()));
362 obj.push_back(Pair("testnet", fTestNet));
363 obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));
364 obj.push_back(Pair("keypoolsize", pwalletMain->GetKeyPoolSize()));
365 obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee)));
366 if (pwalletMain->IsCrypted())
367 obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime / 1000));
368 obj.push_back(Pair("errors", GetWarnings("statusbar")));
373 Value getmininginfo(const Array& params, bool fHelp)
375 if (fHelp || params.size() != 0)
378 "Returns an object containing mining-related information.");
381 obj.push_back(Pair("blocks", (int)nBestHeight));
382 obj.push_back(Pair("currentblocksize",(uint64_t)nLastBlockSize));
383 obj.push_back(Pair("currentblocktx",(uint64_t)nLastBlockTx));
384 obj.push_back(Pair("difficulty", (double)GetDifficulty()));
385 obj.push_back(Pair("errors", GetWarnings("statusbar")));
386 obj.push_back(Pair("generate", GetBoolArg("-gen")));
387 obj.push_back(Pair("genproclimit", (int)GetArg("-genproclimit", -1)));
388 obj.push_back(Pair("hashespersec", gethashespersec(params, false)));
389 obj.push_back(Pair("pooledtx", (uint64_t)nPooledTx));
390 obj.push_back(Pair("testnet", fTestNet));
395 Value getnewaddress(const Array& params, bool fHelp)
397 if (fHelp || params.size() > 1)
399 "getnewaddress [account]\n"
400 "Returns a new bitcoin address for receiving payments. "
401 "If [account] is specified (recommended), it is added to the address book "
402 "so payments received with the address will be credited to [account].");
404 // Parse the account first so we don't generate a key if there's an error
406 if (params.size() > 0)
407 strAccount = AccountFromValue(params[0]);
409 if (!pwalletMain->IsLocked())
410 pwalletMain->TopUpKeyPool();
412 // Generate a new key that is added to wallet
413 std::vector<unsigned char> newKey;
414 if (!pwalletMain->GetKeyFromPool(newKey, false))
415 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
416 CBitcoinAddress address(newKey);
418 pwalletMain->SetAddressBookName(address, strAccount);
420 return address.ToString();
424 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
426 CWalletDB walletdb(pwalletMain->strWalletFile);
429 walletdb.ReadAccount(strAccount, account);
431 bool bKeyUsed = false;
433 // Check if the current key has been used
434 if (!account.vchPubKey.empty())
436 CScript scriptPubKey;
437 scriptPubKey.SetBitcoinAddress(account.vchPubKey);
438 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
439 it != pwalletMain->mapWallet.end() && !account.vchPubKey.empty();
442 const CWalletTx& wtx = (*it).second;
443 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
444 if (txout.scriptPubKey == scriptPubKey)
449 // Generate a new key
450 if (account.vchPubKey.empty() || bForceNew || bKeyUsed)
452 if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false))
453 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
455 pwalletMain->SetAddressBookName(CBitcoinAddress(account.vchPubKey), strAccount);
456 walletdb.WriteAccount(strAccount, account);
459 return CBitcoinAddress(account.vchPubKey);
462 Value getaccountaddress(const Array& params, bool fHelp)
464 if (fHelp || params.size() != 1)
466 "getaccountaddress <account>\n"
467 "Returns the current bitcoin address for receiving payments to this account.");
469 // Parse the account first so we don't generate a key if there's an error
470 string strAccount = AccountFromValue(params[0]);
474 ret = GetAccountAddress(strAccount).ToString();
481 Value setaccount(const Array& params, bool fHelp)
483 if (fHelp || params.size() < 1 || params.size() > 2)
485 "setaccount <bitcoinaddress> <account>\n"
486 "Sets the account associated with the given address.");
488 CBitcoinAddress address(params[0].get_str());
489 if (!address.IsValid())
490 throw JSONRPCError(-5, "Invalid bitcoin address");
494 if (params.size() > 1)
495 strAccount = AccountFromValue(params[1]);
497 // Detect when changing the account of an address that is the 'unused current key' of another account:
498 if (pwalletMain->mapAddressBook.count(address))
500 string strOldAccount = pwalletMain->mapAddressBook[address];
501 if (address == GetAccountAddress(strOldAccount))
502 GetAccountAddress(strOldAccount, true);
505 pwalletMain->SetAddressBookName(address, strAccount);
511 Value getaccount(const Array& params, bool fHelp)
513 if (fHelp || params.size() != 1)
515 "getaccount <bitcoinaddress>\n"
516 "Returns the account associated with the given address.");
518 CBitcoinAddress address(params[0].get_str());
519 if (!address.IsValid())
520 throw JSONRPCError(-5, "Invalid bitcoin address");
523 map<CBitcoinAddress, string>::iterator mi = pwalletMain->mapAddressBook.find(address);
524 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
525 strAccount = (*mi).second;
530 Value getaddressesbyaccount(const Array& params, bool fHelp)
532 if (fHelp || params.size() != 1)
534 "getaddressesbyaccount <account>\n"
535 "Returns the list of addresses for the given account.");
537 string strAccount = AccountFromValue(params[0]);
539 // Find all addresses that have the given account
541 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
543 const CBitcoinAddress& address = item.first;
544 const string& strName = item.second;
545 if (strName == strAccount)
546 ret.push_back(address.ToString());
551 Value settxfee(const Array& params, bool fHelp)
553 if (fHelp || params.size() < 1 || params.size() > 1)
555 "settxfee <amount>\n"
556 "<amount> is a real and is rounded to the nearest 0.00000001");
560 if (params[0].get_real() != 0.0)
561 nAmount = AmountFromValue(params[0]); // rejects 0.0 amounts
563 nTransactionFee = nAmount;
567 Value sendtoaddress(const Array& params, bool fHelp)
569 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
571 "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
572 "<amount> is a real and is rounded to the nearest 0.00000001\n"
573 "requires wallet passphrase to be set with walletpassphrase first");
574 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
576 "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
577 "<amount> is a real and is rounded to the nearest 0.00000001");
579 CBitcoinAddress address(params[0].get_str());
580 if (!address.IsValid())
581 throw JSONRPCError(-5, "Invalid bitcoin address");
584 int64 nAmount = AmountFromValue(params[1]);
588 if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
589 wtx.mapValue["comment"] = params[2].get_str();
590 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
591 wtx.mapValue["to"] = params[3].get_str();
593 if (pwalletMain->IsLocked())
594 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
596 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
598 throw JSONRPCError(-4, strError);
600 return wtx.GetHash().GetHex();
603 Value signmessage(const Array& params, bool fHelp)
605 if (fHelp || params.size() != 2)
607 "signmessage <bitcoinaddress> <message>\n"
608 "Sign a message with the private key of an address");
610 if (pwalletMain->IsLocked())
611 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
613 string strAddress = params[0].get_str();
614 string strMessage = params[1].get_str();
616 CBitcoinAddress addr(strAddress);
618 throw JSONRPCError(-3, "Invalid address");
621 if (!pwalletMain->GetKey(addr, key))
622 throw JSONRPCError(-4, "Private key not available");
624 CDataStream ss(SER_GETHASH);
625 ss << strMessageMagic;
628 vector<unsigned char> vchSig;
629 if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig))
630 throw JSONRPCError(-5, "Sign failed");
632 return EncodeBase64(&vchSig[0], vchSig.size());
635 Value verifymessage(const Array& params, bool fHelp)
637 if (fHelp || params.size() != 3)
639 "verifymessage <bitcoinaddress> <signature> <message>\n"
640 "Verify a signed message");
642 string strAddress = params[0].get_str();
643 string strSign = params[1].get_str();
644 string strMessage = params[2].get_str();
646 CBitcoinAddress addr(strAddress);
648 throw JSONRPCError(-3, "Invalid address");
650 bool fInvalid = false;
651 vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
654 throw JSONRPCError(-5, "Malformed base64 encoding");
656 CDataStream ss(SER_GETHASH);
657 ss << strMessageMagic;
661 if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
664 return (CBitcoinAddress(key.GetPubKey()) == addr);
668 Value getreceivedbyaddress(const Array& params, bool fHelp)
670 if (fHelp || params.size() < 1 || params.size() > 2)
672 "getreceivedbyaddress <bitcoinaddress> [minconf=1]\n"
673 "Returns the total amount received by <bitcoinaddress> in transactions with at least [minconf] confirmations.");
676 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
677 CScript scriptPubKey;
678 if (!address.IsValid())
679 throw JSONRPCError(-5, "Invalid bitcoin address");
680 scriptPubKey.SetBitcoinAddress(address);
681 if (!IsMine(*pwalletMain,scriptPubKey))
684 // Minimum confirmations
686 if (params.size() > 1)
687 nMinDepth = params[1].get_int();
691 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
693 const CWalletTx& wtx = (*it).second;
694 if (wtx.IsCoinBase() || !wtx.IsFinal())
697 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
698 if (txout.scriptPubKey == scriptPubKey)
699 if (wtx.GetDepthInMainChain() >= nMinDepth)
700 nAmount += txout.nValue;
703 return ValueFromAmount(nAmount);
707 void GetAccountAddresses(string strAccount, set<CBitcoinAddress>& setAddress)
709 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
711 const CBitcoinAddress& address = item.first;
712 const string& strName = item.second;
713 if (strName == strAccount)
714 setAddress.insert(address);
719 Value getreceivedbyaccount(const Array& params, bool fHelp)
721 if (fHelp || params.size() < 1 || params.size() > 2)
723 "getreceivedbyaccount <account> [minconf=1]\n"
724 "Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.");
726 // Minimum confirmations
728 if (params.size() > 1)
729 nMinDepth = params[1].get_int();
731 // Get the set of pub keys assigned to account
732 string strAccount = AccountFromValue(params[0]);
733 set<CBitcoinAddress> setAddress;
734 GetAccountAddresses(strAccount, setAddress);
738 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
740 const CWalletTx& wtx = (*it).second;
741 if (wtx.IsCoinBase() || !wtx.IsFinal())
744 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
746 CBitcoinAddress address;
747 if (ExtractAddress(txout.scriptPubKey, address) && pwalletMain->HaveKey(address) && setAddress.count(address))
748 if (wtx.GetDepthInMainChain() >= nMinDepth)
749 nAmount += txout.nValue;
753 return (double)nAmount / (double)COIN;
757 int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth)
761 // Tally wallet transactions
762 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
764 const CWalletTx& wtx = (*it).second;
768 int64 nGenerated, nReceived, nSent, nFee;
769 wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee);
771 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
772 nBalance += nReceived;
773 nBalance += nGenerated - nSent - nFee;
776 // Tally internal accounting entries
777 nBalance += walletdb.GetAccountCreditDebit(strAccount);
782 int64 GetAccountBalance(const string& strAccount, int nMinDepth)
784 CWalletDB walletdb(pwalletMain->strWalletFile);
785 return GetAccountBalance(walletdb, strAccount, nMinDepth);
789 Value getbalance(const Array& params, bool fHelp)
791 if (fHelp || params.size() > 2)
793 "getbalance [account] [minconf=1]\n"
794 "If [account] is not specified, returns the server's total available balance.\n"
795 "If [account] is specified, returns the balance in the account.");
797 if (params.size() == 0)
798 return ValueFromAmount(pwalletMain->GetBalance());
801 if (params.size() > 1)
802 nMinDepth = params[1].get_int();
804 if (params[0].get_str() == "*") {
805 // Calculate total balance a different way from GetBalance()
806 // (GetBalance() sums up all unspent TxOuts)
807 // getbalance and getbalance '*' should always return the same number.
809 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
811 const CWalletTx& wtx = (*it).second;
815 int64 allGeneratedImmature, allGeneratedMature, allFee;
816 allGeneratedImmature = allGeneratedMature = allFee = 0;
817 string strSentAccount;
818 list<pair<CBitcoinAddress, int64> > listReceived;
819 list<pair<CBitcoinAddress, int64> > listSent;
820 wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
821 if (wtx.GetDepthInMainChain() >= nMinDepth)
822 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listReceived)
823 nBalance += r.second;
824 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listSent)
825 nBalance -= r.second;
827 nBalance += allGeneratedMature;
829 return ValueFromAmount(nBalance);
832 string strAccount = AccountFromValue(params[0]);
834 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
836 return ValueFromAmount(nBalance);
840 Value movecmd(const Array& params, bool fHelp)
842 if (fHelp || params.size() < 3 || params.size() > 5)
844 "move <fromaccount> <toaccount> <amount> [minconf=1] [comment]\n"
845 "Move from one account in your wallet to another.");
847 string strFrom = AccountFromValue(params[0]);
848 string strTo = AccountFromValue(params[1]);
849 int64 nAmount = AmountFromValue(params[2]);
850 if (params.size() > 3)
851 // unused parameter, used to be nMinDepth, keep type-checking it though
852 (void)params[3].get_int();
854 if (params.size() > 4)
855 strComment = params[4].get_str();
857 CWalletDB walletdb(pwalletMain->strWalletFile);
860 int64 nNow = GetAdjustedTime();
863 CAccountingEntry debit;
864 debit.strAccount = strFrom;
865 debit.nCreditDebit = -nAmount;
867 debit.strOtherAccount = strTo;
868 debit.strComment = strComment;
869 walletdb.WriteAccountingEntry(debit);
872 CAccountingEntry credit;
873 credit.strAccount = strTo;
874 credit.nCreditDebit = nAmount;
876 credit.strOtherAccount = strFrom;
877 credit.strComment = strComment;
878 walletdb.WriteAccountingEntry(credit);
880 walletdb.TxnCommit();
886 Value sendfrom(const Array& params, bool fHelp)
888 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
890 "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
891 "<amount> is a real and is rounded to the nearest 0.00000001\n"
892 "requires wallet passphrase to be set with walletpassphrase first");
893 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
895 "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
896 "<amount> is a real and is rounded to the nearest 0.00000001");
898 string strAccount = AccountFromValue(params[0]);
899 CBitcoinAddress address(params[1].get_str());
900 if (!address.IsValid())
901 throw JSONRPCError(-5, "Invalid bitcoin address");
902 int64 nAmount = AmountFromValue(params[2]);
904 if (params.size() > 3)
905 nMinDepth = params[3].get_int();
908 wtx.strFromAccount = strAccount;
909 if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
910 wtx.mapValue["comment"] = params[4].get_str();
911 if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
912 wtx.mapValue["to"] = params[5].get_str();
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 (nAmount > nBalance)
920 throw JSONRPCError(-6, "Account has insufficient funds");
923 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
925 throw JSONRPCError(-4, strError);
927 return wtx.GetHash().GetHex();
931 Value sendmany(const Array& params, bool fHelp)
933 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
935 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
936 "amounts are double-precision floating point numbers\n"
937 "requires wallet passphrase to be set with walletpassphrase first");
938 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
940 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
941 "amounts are double-precision floating point numbers");
943 string strAccount = AccountFromValue(params[0]);
944 Object sendTo = params[1].get_obj();
946 if (params.size() > 2)
947 nMinDepth = params[2].get_int();
950 wtx.strFromAccount = strAccount;
951 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
952 wtx.mapValue["comment"] = params[3].get_str();
954 set<CBitcoinAddress> setAddress;
955 vector<pair<CScript, int64> > vecSend;
957 int64 totalAmount = 0;
958 BOOST_FOREACH(const Pair& s, sendTo)
960 CBitcoinAddress address(s.name_);
961 if (!address.IsValid())
962 throw JSONRPCError(-5, string("Invalid bitcoin address:")+s.name_);
964 if (setAddress.count(address))
965 throw JSONRPCError(-8, string("Invalid parameter, duplicated address: ")+s.name_);
966 setAddress.insert(address);
968 CScript scriptPubKey;
969 scriptPubKey.SetBitcoinAddress(address);
970 int64 nAmount = AmountFromValue(s.value_);
971 totalAmount += nAmount;
973 vecSend.push_back(make_pair(scriptPubKey, nAmount));
976 if (pwalletMain->IsLocked())
977 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
980 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
981 if (totalAmount > nBalance)
982 throw JSONRPCError(-6, "Account has insufficient funds");
985 CReserveKey keyChange(pwalletMain);
986 int64 nFeeRequired = 0;
987 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
990 if (totalAmount + nFeeRequired > pwalletMain->GetBalance())
991 throw JSONRPCError(-6, "Insufficient funds");
992 throw JSONRPCError(-4, "Transaction creation failed");
994 if (!pwalletMain->CommitTransaction(wtx, keyChange))
995 throw JSONRPCError(-4, "Transaction commit failed");
997 return wtx.GetHash().GetHex();
1000 Value addmultisigaddress(const Array& params, bool fHelp)
1002 if (fHelp || params.size() < 2 || params.size() > 3)
1004 string msg = "addmultisigaddress <nrequired> <'[\"key\",\"key\"]'> [account]\n"
1005 "Add a nrequired-to-sign multisignature address to the wallet\"\n"
1006 "each key is a bitcoin address or hex-encoded public key\n"
1007 "If [account] is specified, assign address to [account].";
1008 throw runtime_error(msg);
1011 throw runtime_error("addmultisigaddress available only when running -testnet\n");
1013 int nRequired = params[0].get_int();
1014 const Array& keys = params[1].get_array();
1016 if (params.size() > 2)
1017 strAccount = AccountFromValue(params[2]);
1019 // Gather public keys
1020 if (nRequired < 1 || keys.size() < nRequired)
1021 throw runtime_error(
1022 strprintf("wrong number of keys"
1023 "(got %d, need at least %d)", keys.size(), nRequired));
1024 std::vector<CKey> pubkeys;
1025 pubkeys.resize(keys.size());
1026 for (int i = 0; i < keys.size(); i++)
1028 const std::string& ks = keys[i].get_str();
1030 // Case 1: bitcoin address and we have full public key:
1031 CBitcoinAddress address(ks);
1032 if (address.IsValid())
1034 if (address.IsScript())
1035 throw runtime_error(
1036 strprintf("%s is a pay-to-script address",ks.c_str()));
1037 std::vector<unsigned char> vchPubKey;
1038 if (!pwalletMain->GetPubKey(address, vchPubKey))
1039 throw runtime_error(
1040 strprintf("no full public key for address %s",ks.c_str()));
1041 if (vchPubKey.empty() || !pubkeys[i].SetPubKey(vchPubKey))
1042 throw runtime_error(" Invalid public key: "+ks);
1045 // Case 2: hex public key
1048 vector<unsigned char> vchPubKey = ParseHex(ks);
1049 if (vchPubKey.empty() || !pubkeys[i].SetPubKey(vchPubKey))
1050 throw runtime_error(" Invalid public key: "+ks);
1054 throw runtime_error(" Invalid public key: "+ks);
1058 // Construct using pay-to-script-hash:
1060 inner.SetMultisig(nRequired, pubkeys);
1062 uint160 scriptHash = Hash160(inner);
1063 CScript scriptPubKey;
1064 scriptPubKey.SetPayToScriptHash(inner);
1065 pwalletMain->AddCScript(inner);
1066 CBitcoinAddress address;
1067 address.SetScriptHash160(scriptHash);
1069 pwalletMain->SetAddressBookName(address, strAccount);
1070 return address.ToString();
1081 nConf = std::numeric_limits<int>::max();
1085 Value ListReceived(const Array& params, bool fByAccounts)
1087 // Minimum confirmations
1089 if (params.size() > 0)
1090 nMinDepth = params[0].get_int();
1092 // Whether to include empty accounts
1093 bool fIncludeEmpty = false;
1094 if (params.size() > 1)
1095 fIncludeEmpty = params[1].get_bool();
1098 map<CBitcoinAddress, tallyitem> mapTally;
1099 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1101 const CWalletTx& wtx = (*it).second;
1103 if (wtx.IsCoinBase() || !wtx.IsFinal())
1106 int nDepth = wtx.GetDepthInMainChain();
1107 if (nDepth < nMinDepth)
1110 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
1112 CBitcoinAddress address;
1113 if (!ExtractAddress(txout.scriptPubKey, address) || !pwalletMain->HaveKey(address) || !address.IsValid())
1116 tallyitem& item = mapTally[address];
1117 item.nAmount += txout.nValue;
1118 item.nConf = min(item.nConf, nDepth);
1124 map<string, tallyitem> mapAccountTally;
1125 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
1127 const CBitcoinAddress& address = item.first;
1128 const string& strAccount = item.second;
1129 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
1130 if (it == mapTally.end() && !fIncludeEmpty)
1134 int nConf = std::numeric_limits<int>::max();
1135 if (it != mapTally.end())
1137 nAmount = (*it).second.nAmount;
1138 nConf = (*it).second.nConf;
1143 tallyitem& item = mapAccountTally[strAccount];
1144 item.nAmount += nAmount;
1145 item.nConf = min(item.nConf, nConf);
1150 obj.push_back(Pair("address", address.ToString()));
1151 obj.push_back(Pair("account", strAccount));
1152 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1153 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1160 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
1162 int64 nAmount = (*it).second.nAmount;
1163 int nConf = (*it).second.nConf;
1165 obj.push_back(Pair("account", (*it).first));
1166 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1167 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1175 Value listreceivedbyaddress(const Array& params, bool fHelp)
1177 if (fHelp || params.size() > 2)
1178 throw runtime_error(
1179 "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
1180 "[minconf] is the minimum number of confirmations before payments are included.\n"
1181 "[includeempty] whether to include addresses that haven't received any payments.\n"
1182 "Returns an array of objects containing:\n"
1183 " \"address\" : receiving address\n"
1184 " \"account\" : the account of the receiving address\n"
1185 " \"amount\" : total amount received by the address\n"
1186 " \"confirmations\" : number of confirmations of the most recent transaction included");
1188 return ListReceived(params, false);
1191 Value listreceivedbyaccount(const Array& params, bool fHelp)
1193 if (fHelp || params.size() > 2)
1194 throw runtime_error(
1195 "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
1196 "[minconf] is the minimum number of confirmations before payments are included.\n"
1197 "[includeempty] whether to include accounts that haven't received any payments.\n"
1198 "Returns an array of objects containing:\n"
1199 " \"account\" : the account of the receiving addresses\n"
1200 " \"amount\" : total amount received by addresses with this account\n"
1201 " \"confirmations\" : number of confirmations of the most recent transaction included");
1203 return ListReceived(params, true);
1206 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret)
1208 int64 nGeneratedImmature, nGeneratedMature, nFee;
1209 string strSentAccount;
1210 list<pair<CBitcoinAddress, int64> > listReceived;
1211 list<pair<CBitcoinAddress, int64> > listSent;
1213 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1215 bool fAllAccounts = (strAccount == string("*"));
1217 // Generated blocks assigned to account ""
1218 if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == ""))
1221 entry.push_back(Pair("account", string("")));
1222 if (nGeneratedImmature)
1224 entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
1225 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
1229 entry.push_back(Pair("category", "generate"));
1230 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
1233 WalletTxToJSON(wtx, entry);
1234 ret.push_back(entry);
1238 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1240 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1243 entry.push_back(Pair("account", strSentAccount));
1244 entry.push_back(Pair("address", s.first.ToString()));
1245 entry.push_back(Pair("category", "send"));
1246 entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1247 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1249 WalletTxToJSON(wtx, entry);
1250 ret.push_back(entry);
1255 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1256 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1259 if (pwalletMain->mapAddressBook.count(r.first))
1260 account = pwalletMain->mapAddressBook[r.first];
1261 if (fAllAccounts || (account == strAccount))
1264 entry.push_back(Pair("account", account));
1265 entry.push_back(Pair("address", r.first.ToString()));
1266 entry.push_back(Pair("category", "receive"));
1267 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1269 WalletTxToJSON(wtx, entry);
1270 ret.push_back(entry);
1275 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1277 bool fAllAccounts = (strAccount == string("*"));
1279 if (fAllAccounts || acentry.strAccount == strAccount)
1282 entry.push_back(Pair("account", acentry.strAccount));
1283 entry.push_back(Pair("category", "move"));
1284 entry.push_back(Pair("time", (boost::int64_t)acentry.nTime));
1285 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1286 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1287 entry.push_back(Pair("comment", acentry.strComment));
1288 ret.push_back(entry);
1292 Value listtransactions(const Array& params, bool fHelp)
1294 if (fHelp || params.size() > 3)
1295 throw runtime_error(
1296 "listtransactions [account] [count=10] [from=0]\n"
1297 "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1299 string strAccount = "*";
1300 if (params.size() > 0)
1301 strAccount = params[0].get_str();
1303 if (params.size() > 1)
1304 nCount = params[1].get_int();
1306 if (params.size() > 2)
1307 nFrom = params[2].get_int();
1310 CWalletDB walletdb(pwalletMain->strWalletFile);
1312 // Firs: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap:
1313 typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
1314 typedef multimap<int64, TxPair > TxItems;
1317 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1319 CWalletTx* wtx = &((*it).second);
1320 txByTime.insert(make_pair(wtx->GetTxTime(), TxPair(wtx, (CAccountingEntry*)0)));
1322 list<CAccountingEntry> acentries;
1323 walletdb.ListAccountCreditDebit(strAccount, acentries);
1324 BOOST_FOREACH(CAccountingEntry& entry, acentries)
1326 txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
1329 // Now: iterate backwards until we have nCount items to return:
1330 TxItems::reverse_iterator it = txByTime.rbegin();
1331 if (txByTime.size() > nFrom) std::advance(it, nFrom);
1332 for (; it != txByTime.rend(); ++it)
1334 CWalletTx *const pwtx = (*it).second.first;
1336 ListTransactions(*pwtx, strAccount, 0, true, ret);
1337 CAccountingEntry *const pacentry = (*it).second.second;
1339 AcentryToJSON(*pacentry, strAccount, ret);
1341 if (ret.size() >= nCount) break;
1343 // ret is now newest to oldest
1345 // Make sure we return only last nCount items (sends-to-self might give us an extra):
1346 if (ret.size() > nCount)
1348 Array::iterator last = ret.begin();
1349 std::advance(last, nCount);
1350 ret.erase(last, ret.end());
1352 std::reverse(ret.begin(), ret.end()); // oldest to newest
1357 Value listaccounts(const Array& params, bool fHelp)
1359 if (fHelp || params.size() > 1)
1360 throw runtime_error(
1361 "listaccounts [minconf=1]\n"
1362 "Returns Object that has account names as keys, account balances as values.");
1365 if (params.size() > 0)
1366 nMinDepth = params[0].get_int();
1368 map<string, int64> mapAccountBalances;
1369 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& entry, pwalletMain->mapAddressBook) {
1370 if (pwalletMain->HaveKey(entry.first)) // This address belongs to me
1371 mapAccountBalances[entry.second] = 0;
1374 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1376 const CWalletTx& wtx = (*it).second;
1377 int64 nGeneratedImmature, nGeneratedMature, nFee;
1378 string strSentAccount;
1379 list<pair<CBitcoinAddress, int64> > listReceived;
1380 list<pair<CBitcoinAddress, int64> > listSent;
1381 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1382 mapAccountBalances[strSentAccount] -= nFee;
1383 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1384 mapAccountBalances[strSentAccount] -= s.second;
1385 if (wtx.GetDepthInMainChain() >= nMinDepth)
1387 mapAccountBalances[""] += nGeneratedMature;
1388 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1389 if (pwalletMain->mapAddressBook.count(r.first))
1390 mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1392 mapAccountBalances[""] += r.second;
1396 list<CAccountingEntry> acentries;
1397 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1398 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1399 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1402 BOOST_FOREACH(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) {
1403 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1408 Value listsinceblock(const Array& params, bool fHelp)
1411 throw runtime_error(
1412 "listsinceblock [blockid] [target-confirmations]\n"
1413 "Get all transactions in blocks since block [blockid], or all transactions if omitted");
1415 CBlockIndex *pindex = NULL;
1416 int target_confirms = 1;
1418 if (params.size() > 0)
1420 uint256 blockId = 0;
1422 blockId.SetHex(params[0].get_str());
1423 pindex = CBlockLocator(blockId).GetBlockIndex();
1426 if (params.size() > 1)
1428 target_confirms = params[1].get_int();
1430 if (target_confirms < 1)
1431 throw JSONRPCError(-8, "Invalid parameter");
1434 int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1;
1438 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1440 CWalletTx tx = (*it).second;
1442 if (depth == -1 || tx.GetDepthInMainChain() < depth)
1443 ListTransactions(tx, "*", 0, true, transactions);
1448 if (target_confirms == 1)
1451 lastblock = hashBestChain;
1455 int target_height = pindexBest->nHeight + 1 - target_confirms;
1458 for (block = pindexBest;
1459 block && block->nHeight > target_height;
1460 block = block->pprev) { }
1462 lastblock = block ? block->GetBlockHash() : 0;
1466 ret.push_back(Pair("transactions", transactions));
1467 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1472 Value gettransaction(const Array& params, bool fHelp)
1474 if (fHelp || params.size() != 1)
1475 throw runtime_error(
1476 "gettransaction <txid>\n"
1477 "Get detailed information about <txid>");
1480 hash.SetHex(params[0].get_str());
1484 if (!pwalletMain->mapWallet.count(hash))
1485 throw JSONRPCError(-5, "Invalid or non-wallet transaction id");
1486 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1488 int64 nCredit = wtx.GetCredit();
1489 int64 nDebit = wtx.GetDebit();
1490 int64 nNet = nCredit - nDebit;
1491 int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
1493 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1495 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1497 WalletTxToJSON(pwalletMain->mapWallet[hash], entry);
1500 ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
1501 entry.push_back(Pair("details", details));
1507 Value backupwallet(const Array& params, bool fHelp)
1509 if (fHelp || params.size() != 1)
1510 throw runtime_error(
1511 "backupwallet <destination>\n"
1512 "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1514 string strDest = params[0].get_str();
1515 BackupWallet(*pwalletMain, strDest);
1521 Value keypoolrefill(const Array& params, bool fHelp)
1523 if (pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1524 throw runtime_error(
1526 "Fills the keypool, requires wallet passphrase to be set.");
1527 if (!pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1528 throw runtime_error(
1530 "Fills the keypool.");
1532 if (pwalletMain->IsLocked())
1533 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
1535 pwalletMain->TopUpKeyPool();
1537 if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100))
1538 throw JSONRPCError(-4, "Error refreshing keypool.");
1544 void ThreadTopUpKeyPool(void* parg)
1546 pwalletMain->TopUpKeyPool();
1549 void ThreadCleanWalletPassphrase(void* parg)
1551 int64 nMyWakeTime = GetTimeMillis() + *((int*)parg) * 1000;
1553 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1555 if (nWalletUnlockTime == 0)
1557 nWalletUnlockTime = nMyWakeTime;
1561 if (nWalletUnlockTime==0)
1563 int64 nToSleep = nWalletUnlockTime - GetTimeMillis();
1567 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1569 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1573 if (nWalletUnlockTime)
1575 nWalletUnlockTime = 0;
1576 pwalletMain->Lock();
1581 if (nWalletUnlockTime < nMyWakeTime)
1582 nWalletUnlockTime = nMyWakeTime;
1585 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1590 Value walletpassphrase(const Array& params, bool fHelp)
1592 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1593 throw runtime_error(
1594 "walletpassphrase <passphrase> <timeout>\n"
1595 "Stores the wallet decryption key in memory for <timeout> seconds.");
1598 if (!pwalletMain->IsCrypted())
1599 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1601 if (!pwalletMain->IsLocked())
1602 throw JSONRPCError(-17, "Error: Wallet is already unlocked.");
1604 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1605 SecureString strWalletPass;
1606 strWalletPass.reserve(100);
1607 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1608 // Alternately, find a way to make params[0] mlock()'d to begin with.
1609 strWalletPass = params[0].get_str().c_str();
1611 if (strWalletPass.length() > 0)
1613 if (!pwalletMain->Unlock(strWalletPass))
1614 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1617 throw runtime_error(
1618 "walletpassphrase <passphrase> <timeout>\n"
1619 "Stores the wallet decryption key in memory for <timeout> seconds.");
1621 CreateThread(ThreadTopUpKeyPool, NULL);
1622 int* pnSleepTime = new int(params[1].get_int());
1623 CreateThread(ThreadCleanWalletPassphrase, pnSleepTime);
1629 Value walletpassphrasechange(const Array& params, bool fHelp)
1631 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1632 throw runtime_error(
1633 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1634 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1637 if (!pwalletMain->IsCrypted())
1638 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1640 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1641 // Alternately, find a way to make params[0] mlock()'d to begin with.
1642 SecureString strOldWalletPass;
1643 strOldWalletPass.reserve(100);
1644 strOldWalletPass = params[0].get_str().c_str();
1646 SecureString strNewWalletPass;
1647 strNewWalletPass.reserve(100);
1648 strNewWalletPass = params[1].get_str().c_str();
1650 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1651 throw runtime_error(
1652 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1653 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1655 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1656 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1662 Value walletlock(const Array& params, bool fHelp)
1664 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1665 throw runtime_error(
1667 "Removes the wallet encryption key from memory, locking the wallet.\n"
1668 "After calling this method, you will need to call walletpassphrase again\n"
1669 "before being able to call any methods which require the wallet to be unlocked.");
1672 if (!pwalletMain->IsCrypted())
1673 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called.");
1675 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1677 pwalletMain->Lock();
1678 nWalletUnlockTime = 0;
1685 Value encryptwallet(const Array& params, bool fHelp)
1687 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1688 throw runtime_error(
1689 "encryptwallet <passphrase>\n"
1690 "Encrypts the wallet with <passphrase>.");
1693 if (pwalletMain->IsCrypted())
1694 throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
1697 // shutting down via RPC while the GUI is running does not work (yet):
1698 throw runtime_error("Not Yet Implemented: use GUI to encrypt wallet, not RPC command");
1701 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1702 // Alternately, find a way to make params[0] mlock()'d to begin with.
1703 SecureString strWalletPass;
1704 strWalletPass.reserve(100);
1705 strWalletPass = params[0].get_str().c_str();
1707 if (strWalletPass.length() < 1)
1708 throw runtime_error(
1709 "encryptwallet <passphrase>\n"
1710 "Encrypts the wallet with <passphrase>.");
1712 if (!pwalletMain->EncryptWallet(strWalletPass))
1713 throw JSONRPCError(-16, "Error: Failed to encrypt the wallet.");
1715 // BDB seems to have a bad habit of writing old data into
1716 // slack space in .dat files; that is bad if the old data is
1717 // unencrypted private keys. So:
1718 CreateThread(Shutdown, NULL);
1719 return "wallet encrypted; bitcoin server stopping, restart to run with encrypted wallet";
1723 Value validateaddress(const Array& params, bool fHelp)
1725 if (fHelp || params.size() != 1)
1726 throw runtime_error(
1727 "validateaddress <bitcoinaddress>\n"
1728 "Return information about <bitcoinaddress>.");
1730 CBitcoinAddress address(params[0].get_str());
1731 bool isValid = address.IsValid();
1734 ret.push_back(Pair("isvalid", isValid));
1737 // Call Hash160ToAddress() so we always return current ADDRESSVERSION
1738 // version of the address:
1739 string currentAddress = address.ToString();
1740 ret.push_back(Pair("address", currentAddress));
1741 if (pwalletMain->HaveKey(address))
1743 ret.push_back(Pair("ismine", true));
1744 std::vector<unsigned char> vchPubKey;
1745 pwalletMain->GetPubKey(address, vchPubKey);
1746 ret.push_back(Pair("pubkey", HexStr(vchPubKey)));
1748 key.SetPubKey(vchPubKey);
1749 ret.push_back(Pair("iscompressed", key.IsCompressed()));
1751 else if (pwalletMain->HaveCScript(address.GetHash160()))
1753 ret.push_back(Pair("isscript", true));
1755 pwalletMain->GetCScript(address.GetHash160(), subscript);
1756 ret.push_back(Pair("ismine", ::IsMine(*pwalletMain, subscript)));
1757 std::vector<CBitcoinAddress> addresses;
1758 txnouttype whichType;
1760 ExtractAddresses(subscript, whichType, addresses, nRequired);
1761 ret.push_back(Pair("script", GetTxnOutputType(whichType)));
1763 BOOST_FOREACH(const CBitcoinAddress& addr, addresses)
1764 a.push_back(addr.ToString());
1765 ret.push_back(Pair("addresses", a));
1766 if (whichType == TX_MULTISIG)
1767 ret.push_back(Pair("sigsrequired", nRequired));
1770 ret.push_back(Pair("ismine", false));
1771 if (pwalletMain->mapAddressBook.count(address))
1772 ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
1777 Value getwork(const Array& params, bool fHelp)
1779 if (fHelp || params.size() > 1)
1780 throw runtime_error(
1782 "If [data] is not specified, returns formatted hash data to work on:\n"
1783 " \"midstate\" : precomputed hash state after hashing the first half of the data (DEPRECATED)\n" // deprecated
1784 " \"data\" : block data\n"
1785 " \"hash1\" : formatted hash buffer for second hash (DEPRECATED)\n" // deprecated
1786 " \"target\" : little endian hash target\n"
1787 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1790 throw JSONRPCError(-9, "Bitcoin is not connected!");
1792 if (IsInitialBlockDownload())
1793 throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
1795 typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
1796 static mapNewBlock_t mapNewBlock;
1797 static vector<CBlock*> vNewBlock;
1798 static CReserveKey reservekey(pwalletMain);
1800 if (params.size() == 0)
1803 static unsigned int nTransactionsUpdatedLast;
1804 static CBlockIndex* pindexPrev;
1805 static int64 nStart;
1806 static CBlock* pblock;
1807 if (pindexPrev != pindexBest ||
1808 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
1810 if (pindexPrev != pindexBest)
1812 // Deallocate old blocks since they're obsolete now
1813 mapNewBlock.clear();
1814 BOOST_FOREACH(CBlock* pblock, vNewBlock)
1818 nTransactionsUpdatedLast = nTransactionsUpdated;
1819 pindexPrev = pindexBest;
1823 pblock = CreateNewBlock(reservekey);
1825 throw JSONRPCError(-7, "Out of memory");
1826 vNewBlock.push_back(pblock);
1830 pblock->UpdateTime(pindexPrev);
1833 // Update nExtraNonce
1834 static unsigned int nExtraNonce = 0;
1835 IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
1838 mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
1840 // Prebuild hash buffers
1844 FormatHashBuffers(pblock, pmidstate, pdata, phash1);
1846 uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
1849 result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate)))); // deprecated
1850 result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata))));
1851 result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1)))); // deprecated
1852 result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
1858 vector<unsigned char> vchData = ParseHex(params[0].get_str());
1859 if (vchData.size() != 128)
1860 throw JSONRPCError(-8, "Invalid parameter");
1861 CBlock* pdata = (CBlock*)&vchData[0];
1864 for (int i = 0; i < 128/4; i++)
1865 ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]);
1868 if (!mapNewBlock.count(pdata->hashMerkleRoot))
1870 CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
1872 pblock->nTime = pdata->nTime;
1873 pblock->nNonce = pdata->nNonce;
1874 pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
1875 pblock->hashMerkleRoot = pblock->BuildMerkleTree();
1877 return CheckWork(pblock, *pwalletMain, reservekey);
1882 Value getmemorypool(const Array& params, bool fHelp)
1884 if (fHelp || params.size() > 1)
1885 throw runtime_error(
1886 "getmemorypool [data]\n"
1887 "If [data] is not specified, returns data needed to construct a block to work on:\n"
1888 " \"version\" : block version\n"
1889 " \"previousblockhash\" : hash of current highest block\n"
1890 " \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
1891 " \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
1892 " \"coinbaseflags\" : data that should be included in coinbase so support for new features can be judged\n"
1893 " \"time\" : timestamp appropriate for next block\n"
1894 " \"mintime\" : minimum timestamp appropriate for next block\n"
1895 " \"curtime\" : current timestamp\n"
1896 " \"bits\" : compressed target of next block\n"
1897 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1899 if (params.size() == 0)
1902 throw JSONRPCError(-9, "Bitcoin is not connected!");
1904 if (IsInitialBlockDownload())
1905 throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
1907 static CReserveKey reservekey(pwalletMain);
1910 static unsigned int nTransactionsUpdatedLast;
1911 static CBlockIndex* pindexPrev;
1912 static int64 nStart;
1913 static CBlock* pblock;
1914 if (pindexPrev != pindexBest ||
1915 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5))
1917 nTransactionsUpdatedLast = nTransactionsUpdated;
1918 pindexPrev = pindexBest;
1924 pblock = CreateNewBlock(reservekey);
1926 throw JSONRPCError(-7, "Out of memory");
1930 pblock->UpdateTime(pindexPrev);
1934 BOOST_FOREACH(CTransaction tx, pblock->vtx) {
1941 transactions.push_back(HexStr(ssTx.begin(), ssTx.end()));
1945 result.push_back(Pair("version", pblock->nVersion));
1946 result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
1947 result.push_back(Pair("transactions", transactions));
1948 result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
1949 result.push_back(Pair("coinbaseflags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end())));
1950 result.push_back(Pair("time", (int64_t)pblock->nTime));
1951 result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1));
1952 result.push_back(Pair("curtime", (int64_t)GetAdjustedTime()));
1953 result.push_back(Pair("bits", HexBits(pblock->nBits)));
1960 CDataStream ssBlock(ParseHex(params[0].get_str()));
1964 return ProcessBlock(NULL, &pblock);
1968 Value getblockhash(const Array& params, bool fHelp)
1970 if (fHelp || params.size() != 1)
1971 throw runtime_error(
1972 "getblockhash <index>\n"
1973 "Returns hash of block in best-block-chain at <index>.");
1975 int nHeight = params[0].get_int();
1976 if (nHeight < 0 || nHeight > nBestHeight)
1977 throw runtime_error("Block number out of range.");
1980 CBlockIndex* pblockindex = mapBlockIndex[hashBestChain];
1981 while (pblockindex->nHeight > nHeight)
1982 pblockindex = pblockindex->pprev;
1983 return pblockindex->phashBlock->GetHex();
1986 Value getblock(const Array& params, bool fHelp)
1988 if (fHelp || params.size() != 1)
1989 throw runtime_error(
1991 "Returns details of a block with given block-hash.");
1993 std::string strHash = params[0].get_str();
1994 uint256 hash(strHash);
1996 if (mapBlockIndex.count(hash) == 0)
1997 throw JSONRPCError(-5, "Block not found");
2000 CBlockIndex* pblockindex = mapBlockIndex[hash];
2001 block.ReadFromDisk(pblockindex, true);
2003 return blockToJSON(block, pblockindex);
2020 pair<string, rpcfn_type> pCallTable[] =
2022 make_pair("help", &help),
2023 make_pair("stop", &stop),
2024 make_pair("getblockcount", &getblockcount),
2025 make_pair("getblocknumber", &getblocknumber),
2026 make_pair("getconnectioncount", &getconnectioncount),
2027 make_pair("getdifficulty", &getdifficulty),
2028 make_pair("getgenerate", &getgenerate),
2029 make_pair("setgenerate", &setgenerate),
2030 make_pair("gethashespersec", &gethashespersec),
2031 make_pair("getinfo", &getinfo),
2032 make_pair("getmininginfo", &getmininginfo),
2033 make_pair("getnewaddress", &getnewaddress),
2034 make_pair("getaccountaddress", &getaccountaddress),
2035 make_pair("setaccount", &setaccount),
2036 make_pair("getaccount", &getaccount),
2037 make_pair("getaddressesbyaccount", &getaddressesbyaccount),
2038 make_pair("sendtoaddress", &sendtoaddress),
2039 make_pair("getreceivedbyaddress", &getreceivedbyaddress),
2040 make_pair("getreceivedbyaccount", &getreceivedbyaccount),
2041 make_pair("listreceivedbyaddress", &listreceivedbyaddress),
2042 make_pair("listreceivedbyaccount", &listreceivedbyaccount),
2043 make_pair("backupwallet", &backupwallet),
2044 make_pair("keypoolrefill", &keypoolrefill),
2045 make_pair("walletpassphrase", &walletpassphrase),
2046 make_pair("walletpassphrasechange", &walletpassphrasechange),
2047 make_pair("walletlock", &walletlock),
2048 make_pair("encryptwallet", &encryptwallet),
2049 make_pair("validateaddress", &validateaddress),
2050 make_pair("getbalance", &getbalance),
2051 make_pair("move", &movecmd),
2052 make_pair("sendfrom", &sendfrom),
2053 make_pair("sendmany", &sendmany),
2054 make_pair("addmultisigaddress", &addmultisigaddress),
2055 make_pair("getblock", &getblock),
2056 make_pair("getblockhash", &getblockhash),
2057 make_pair("gettransaction", &gettransaction),
2058 make_pair("listtransactions", &listtransactions),
2059 make_pair("signmessage", &signmessage),
2060 make_pair("verifymessage", &verifymessage),
2061 make_pair("getwork", &getwork),
2062 make_pair("listaccounts", &listaccounts),
2063 make_pair("settxfee", &settxfee),
2064 make_pair("getmemorypool", &getmemorypool),
2065 make_pair("listsinceblock", &listsinceblock),
2066 make_pair("dumpprivkey", &dumpprivkey),
2067 make_pair("importprivkey", &importprivkey)
2069 map<string, rpcfn_type> mapCallTable(pCallTable, pCallTable + sizeof(pCallTable)/sizeof(pCallTable[0]));
2071 string pAllowInSafeMode[] =
2076 "getblocknumber", // deprecated
2077 "getconnectioncount",
2085 "getaccountaddress",
2087 "getaddressesbyaccount",
2096 set<string> setAllowInSafeMode(pAllowInSafeMode, pAllowInSafeMode + sizeof(pAllowInSafeMode)/sizeof(pAllowInSafeMode[0]));
2104 // This ain't Apache. We're just using HTTP header for the length field
2105 // and to be compatible with other JSON-RPC implementations.
2108 string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
2111 s << "POST / HTTP/1.1\r\n"
2112 << "User-Agent: bitcoin-json-rpc/" << FormatFullVersion() << "\r\n"
2113 << "Host: 127.0.0.1\r\n"
2114 << "Content-Type: application/json\r\n"
2115 << "Content-Length: " << strMsg.size() << "\r\n"
2116 << "Connection: close\r\n"
2117 << "Accept: application/json\r\n";
2118 BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
2119 s << item.first << ": " << item.second << "\r\n";
2120 s << "\r\n" << strMsg;
2125 string rfc1123Time()
2130 struct tm* now_gmt = gmtime(&now);
2131 string locale(setlocale(LC_TIME, NULL));
2132 setlocale(LC_TIME, "C"); // we want posix (aka "C") weekday/month strings
2133 strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt);
2134 setlocale(LC_TIME, locale.c_str());
2135 return string(buffer);
2138 static string HTTPReply(int nStatus, const string& strMsg)
2141 return strprintf("HTTP/1.0 401 Authorization Required\r\n"
2143 "Server: bitcoin-json-rpc/%s\r\n"
2144 "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
2145 "Content-Type: text/html\r\n"
2146 "Content-Length: 296\r\n"
2148 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
2149 "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
2152 "<TITLE>Error</TITLE>\r\n"
2153 "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
2155 "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
2156 "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
2157 const char *cStatus;
2158 if (nStatus == 200) cStatus = "OK";
2159 else if (nStatus == 400) cStatus = "Bad Request";
2160 else if (nStatus == 403) cStatus = "Forbidden";
2161 else if (nStatus == 404) cStatus = "Not Found";
2162 else if (nStatus == 500) cStatus = "Internal Server Error";
2165 "HTTP/1.1 %d %s\r\n"
2167 "Connection: close\r\n"
2168 "Content-Length: %d\r\n"
2169 "Content-Type: application/json\r\n"
2170 "Server: bitcoin-json-rpc/%s\r\n"
2175 rfc1123Time().c_str(),
2177 FormatFullVersion().c_str(),
2181 int ReadHTTPStatus(std::basic_istream<char>& stream)
2184 getline(stream, str);
2185 vector<string> vWords;
2186 boost::split(vWords, str, boost::is_any_of(" "));
2187 if (vWords.size() < 2)
2189 return atoi(vWords[1].c_str());
2192 int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
2198 std::getline(stream, str);
2199 if (str.empty() || str == "\r")
2201 string::size_type nColon = str.find(":");
2202 if (nColon != string::npos)
2204 string strHeader = str.substr(0, nColon);
2205 boost::trim(strHeader);
2206 boost::to_lower(strHeader);
2207 string strValue = str.substr(nColon+1);
2208 boost::trim(strValue);
2209 mapHeadersRet[strHeader] = strValue;
2210 if (strHeader == "content-length")
2211 nLen = atoi(strValue.c_str());
2217 int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
2219 mapHeadersRet.clear();
2223 int nStatus = ReadHTTPStatus(stream);
2226 int nLen = ReadHTTPHeader(stream, mapHeadersRet);
2227 if (nLen < 0 || nLen > MAX_SIZE)
2233 vector<char> vch(nLen);
2234 stream.read(&vch[0], nLen);
2235 strMessageRet = string(vch.begin(), vch.end());
2241 bool HTTPAuthorized(map<string, string>& mapHeaders)
2243 string strAuth = mapHeaders["authorization"];
2244 if (strAuth.substr(0,6) != "Basic ")
2246 string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
2247 string strUserPass = DecodeBase64(strUserPass64);
2248 return strUserPass == strRPCUserColonPass;
2252 // JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
2253 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
2254 // unspecified (HTTP errors and contents of 'error').
2256 // 1.0 spec: http://json-rpc.org/wiki/specification
2257 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
2258 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
2261 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
2264 request.push_back(Pair("method", strMethod));
2265 request.push_back(Pair("params", params));
2266 request.push_back(Pair("id", id));
2267 return write_string(Value(request), false) + "\n";
2270 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
2273 if (error.type() != null_type)
2274 reply.push_back(Pair("result", Value::null));
2276 reply.push_back(Pair("result", result));
2277 reply.push_back(Pair("error", error));
2278 reply.push_back(Pair("id", id));
2279 return write_string(Value(reply), false) + "\n";
2282 void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
2284 // Send error reply from json-rpc error object
2286 int code = find_value(objError, "code").get_int();
2287 if (code == -32600) nStatus = 400;
2288 else if (code == -32601) nStatus = 404;
2289 string strReply = JSONRPCReply(Value::null, objError, id);
2290 stream << HTTPReply(nStatus, strReply) << std::flush;
2293 bool ClientAllowed(const string& strAddress)
2295 if (strAddress == asio::ip::address_v4::loopback().to_string())
2297 const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
2298 BOOST_FOREACH(string strAllow, vAllow)
2299 if (WildcardMatch(strAddress, strAllow))
2306 // IOStream device that speaks SSL but can also speak non-SSL
2308 class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
2310 SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
2312 fUseSSL = fUseSSLIn;
2313 fNeedHandshake = fUseSSLIn;
2316 void handshake(ssl::stream_base::handshake_type role)
2318 if (!fNeedHandshake) return;
2319 fNeedHandshake = false;
2320 stream.handshake(role);
2322 std::streamsize read(char* s, std::streamsize n)
2324 handshake(ssl::stream_base::server); // HTTPS servers read first
2325 if (fUseSSL) return stream.read_some(asio::buffer(s, n));
2326 return stream.next_layer().read_some(asio::buffer(s, n));
2328 std::streamsize write(const char* s, std::streamsize n)
2330 handshake(ssl::stream_base::client); // HTTPS clients write first
2331 if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
2332 return asio::write(stream.next_layer(), asio::buffer(s, n));
2334 bool connect(const std::string& server, const std::string& port)
2336 ip::tcp::resolver resolver(stream.get_io_service());
2337 ip::tcp::resolver::query query(server.c_str(), port.c_str());
2338 ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
2339 ip::tcp::resolver::iterator end;
2340 boost::system::error_code error = asio::error::host_not_found;
2341 while (error && endpoint_iterator != end)
2343 stream.lowest_layer().close();
2344 stream.lowest_layer().connect(*endpoint_iterator++, error);
2352 bool fNeedHandshake;
2358 void ThreadRPCServer(void* parg)
2360 IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
2363 vnThreadsRunning[THREAD_RPCSERVER]++;
2364 ThreadRPCServer2(parg);
2365 vnThreadsRunning[THREAD_RPCSERVER]--;
2367 catch (std::exception& e) {
2368 vnThreadsRunning[THREAD_RPCSERVER]--;
2369 PrintException(&e, "ThreadRPCServer()");
2371 vnThreadsRunning[THREAD_RPCSERVER]--;
2372 PrintException(NULL, "ThreadRPCServer()");
2374 printf("ThreadRPCServer exiting\n");
2377 void ThreadRPCServer2(void* parg)
2379 printf("ThreadRPCServer started\n");
2381 strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
2382 if (mapArgs["-rpcpassword"] == "")
2384 unsigned char rand_pwd[32];
2385 RAND_bytes(rand_pwd, 32);
2386 string strWhatAmI = "To use bitcoind";
2387 if (mapArgs.count("-server"))
2388 strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
2389 else if (mapArgs.count("-daemon"))
2390 strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
2392 _("Error: %s, you must set a rpcpassword in the configuration file:\n %s\n"
2393 "It is recommended you use the following random password:\n"
2394 "rpcuser=bitcoinrpc\n"
2396 "(you do not need to remember this password)\n"
2397 "If the file does not exist, create it with owner-readable-only file permissions.\n"),
2399 GetConfigFile().c_str(),
2400 EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str());
2402 CreateThread(Shutdown, NULL);
2407 bool fUseSSL = GetBoolArg("-rpcssl");
2408 asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
2410 asio::io_service io_service;
2411 ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", 8332));
2412 ip::tcp::acceptor acceptor(io_service, endpoint);
2414 acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
2417 ssl::context context(io_service, ssl::context::sslv23);
2420 context.set_options(ssl::context::no_sslv2);
2421 filesystem::path certfile = GetArg("-rpcsslcertificatechainfile", "server.cert");
2422 if (!certfile.is_complete()) certfile = filesystem::path(GetDataDir()) / certfile;
2423 if (filesystem::exists(certfile)) context.use_certificate_chain_file(certfile.string().c_str());
2424 else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", certfile.string().c_str());
2425 filesystem::path pkfile = GetArg("-rpcsslprivatekeyfile", "server.pem");
2426 if (!pkfile.is_complete()) pkfile = filesystem::path(GetDataDir()) / pkfile;
2427 if (filesystem::exists(pkfile)) context.use_private_key_file(pkfile.string().c_str(), ssl::context::pem);
2428 else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pkfile.string().c_str());
2430 string ciphers = GetArg("-rpcsslciphers",
2431 "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
2432 SSL_CTX_set_cipher_list(context.impl(), ciphers.c_str());
2436 throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
2441 // Accept connection
2443 SSLStream sslStream(io_service, context);
2444 SSLIOStreamDevice d(sslStream, fUseSSL);
2445 iostreams::stream<SSLIOStreamDevice> stream(d);
2447 ip::tcp::iostream stream;
2450 ip::tcp::endpoint peer;
2451 vnThreadsRunning[THREAD_RPCSERVER]--;
2453 acceptor.accept(sslStream.lowest_layer(), peer);
2455 acceptor.accept(*stream.rdbuf(), peer);
2457 vnThreadsRunning[4]++;
2461 // Restrict callers by IP
2462 if (!ClientAllowed(peer.address().to_string()))
2464 // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
2466 stream << HTTPReply(403, "") << std::flush;
2470 map<string, string> mapHeaders;
2473 boost::thread api_caller(ReadHTTP, boost::ref(stream), boost::ref(mapHeaders), boost::ref(strRequest));
2474 if (!api_caller.timed_join(boost::posix_time::seconds(GetArg("-rpctimeout", 30))))
2477 printf("ThreadRPCServer ReadHTTP timeout\n");
2481 // Check authorization
2482 if (mapHeaders.count("authorization") == 0)
2484 stream << HTTPReply(401, "") << std::flush;
2487 if (!HTTPAuthorized(mapHeaders))
2489 printf("ThreadRPCServer incorrect password attempt from %s\n",peer.address().to_string().c_str());
2490 /* Deter brute-forcing short passwords.
2491 If this results in a DOS the user really
2492 shouldn't have their RPC port exposed.*/
2493 if (mapArgs["-rpcpassword"].size() < 20)
2496 stream << HTTPReply(401, "") << std::flush;
2500 Value id = Value::null;
2505 if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
2506 throw JSONRPCError(-32700, "Parse error");
2507 const Object& request = valRequest.get_obj();
2509 // Parse id now so errors from here on will have the id
2510 id = find_value(request, "id");
2513 Value valMethod = find_value(request, "method");
2514 if (valMethod.type() == null_type)
2515 throw JSONRPCError(-32600, "Missing method");
2516 if (valMethod.type() != str_type)
2517 throw JSONRPCError(-32600, "Method must be a string");
2518 string strMethod = valMethod.get_str();
2519 if (strMethod != "getwork" && strMethod != "getmemorypool")
2520 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
2523 Value valParams = find_value(request, "params");
2525 if (valParams.type() == array_type)
2526 params = valParams.get_array();
2527 else if (valParams.type() == null_type)
2530 throw JSONRPCError(-32600, "Params must be an array");
2533 map<string, rpcfn_type>::iterator mi = mapCallTable.find(strMethod);
2534 if (mi == mapCallTable.end())
2535 throw JSONRPCError(-32601, "Method not found");
2537 // Observe safe mode
2538 string strWarning = GetWarnings("rpc");
2539 if (strWarning != "" && !GetBoolArg("-disablesafemode") && !setAllowInSafeMode.count(strMethod))
2540 throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
2546 CRITICAL_BLOCK(cs_main)
2547 CRITICAL_BLOCK(pwalletMain->cs_wallet)
2548 result = (*(*mi).second)(params, false);
2551 string strReply = JSONRPCReply(result, Value::null, id);
2552 stream << HTTPReply(200, strReply) << std::flush;
2554 catch (std::exception& e)
2556 ErrorReply(stream, JSONRPCError(-1, e.what()), id);
2559 catch (Object& objError)
2561 ErrorReply(stream, objError, id);
2563 catch (std::exception& e)
2565 ErrorReply(stream, JSONRPCError(-32700, e.what()), id);
2573 Object CallRPC(const string& strMethod, const Array& params)
2575 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2576 throw runtime_error(strprintf(
2577 _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
2578 "If the file does not exist, create it with owner-readable-only file permissions."),
2579 GetConfigFile().c_str()));
2581 // Connect to localhost
2582 bool fUseSSL = GetBoolArg("-rpcssl");
2584 asio::io_service io_service;
2585 ssl::context context(io_service, ssl::context::sslv23);
2586 context.set_options(ssl::context::no_sslv2);
2587 SSLStream sslStream(io_service, context);
2588 SSLIOStreamDevice d(sslStream, fUseSSL);
2589 iostreams::stream<SSLIOStreamDevice> stream(d);
2590 if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332")))
2591 throw runtime_error("couldn't connect to server");
2594 throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
2596 ip::tcp::iostream stream(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332"));
2598 throw runtime_error("couldn't connect to server");
2602 // HTTP basic authentication
2603 string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
2604 map<string, string> mapRequestHeaders;
2605 mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
2608 string strRequest = JSONRPCRequest(strMethod, params, 1);
2609 string strPost = HTTPPost(strRequest, mapRequestHeaders);
2610 stream << strPost << std::flush;
2613 map<string, string> mapHeaders;
2615 int nStatus = ReadHTTP(stream, mapHeaders, strReply);
2617 throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
2618 else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
2619 throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
2620 else if (strReply.empty())
2621 throw runtime_error("no response from server");
2625 if (!read_string(strReply, valReply))
2626 throw runtime_error("couldn't parse reply from server");
2627 const Object& reply = valReply.get_obj();
2629 throw runtime_error("expected reply to have result, error and id properties");
2637 template<typename T>
2638 void ConvertTo(Value& value)
2640 if (value.type() == str_type)
2642 // reinterpret string as unquoted json value
2644 if (!read_string(value.get_str(), value2))
2645 throw runtime_error("type mismatch");
2646 value = value2.get_value<T>();
2650 value = value.get_value<T>();
2654 int CommandLineRPC(int argc, char *argv[])
2661 while (argc > 1 && IsSwitchChar(argv[1][0]))
2669 throw runtime_error("too few parameters");
2670 string strMethod = argv[1];
2672 // Parameters default to strings
2674 for (int i = 2; i < argc; i++)
2675 params.push_back(argv[i]);
2676 int n = params.size();
2679 // Special case non-string parameter types
2681 if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
2682 if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2683 if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
2684 if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]);
2685 if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2686 if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2687 if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2688 if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
2689 if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2690 if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
2691 if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2692 if (strMethod == "getblockhash" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2693 if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]);
2694 if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2695 if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]);
2696 if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2697 if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2698 if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2699 if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2700 if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2701 if (strMethod == "listsinceblock" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2702 if (strMethod == "sendmany" && n > 1)
2704 string s = params[1].get_str();
2706 if (!read_string(s, v) || v.type() != obj_type)
2707 throw runtime_error("type mismatch");
2708 params[1] = v.get_obj();
2710 if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2711 if (strMethod == "addmultisigaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2712 if (strMethod == "addmultisigaddress" && n > 1)
2714 string s = params[1].get_str();
2716 if (!read_string(s, v) || v.type() != array_type)
2717 throw runtime_error("type mismatch "+s);
2718 params[1] = v.get_array();
2722 Object reply = CallRPC(strMethod, params);
2725 const Value& result = find_value(reply, "result");
2726 const Value& error = find_value(reply, "error");
2728 if (error.type() != null_type)
2731 strPrint = "error: " + write_string(error, false);
2732 int code = find_value(error.get_obj(), "code").get_int();
2738 if (result.type() == null_type)
2740 else if (result.type() == str_type)
2741 strPrint = result.get_str();
2743 strPrint = write_string(result, true);
2746 catch (std::exception& e)
2748 strPrint = string("error: ") + e.what();
2753 PrintException(NULL, "CommandLineRPC()");
2758 fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
2767 int main(int argc, char *argv[])
2770 // Turn off microsoft heap dump noise
2771 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
2772 _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
2774 setbuf(stdin, NULL);
2775 setbuf(stdout, NULL);
2776 setbuf(stderr, NULL);
2780 if (argc >= 2 && string(argv[1]) == "-server")
2782 printf("server ready\n");
2783 ThreadRPCServer(NULL);
2787 return CommandLineRPC(argc, argv);
2790 catch (std::exception& e) {
2791 PrintException(&e, "main()");
2793 PrintException(NULL, "main()");