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.
12 #include "ui_interface.h"
15 #include <boost/asio.hpp>
16 #include <boost/filesystem.hpp>
17 #include <boost/iostreams/concepts.hpp>
18 #include <boost/iostreams/stream.hpp>
19 #include <boost/algorithm/string.hpp>
20 #include <boost/lexical_cast.hpp>
21 #include <boost/asio/ssl.hpp>
22 #include <boost/filesystem/fstream.hpp>
23 typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> SSLStream;
25 #include "json/json_spirit_reader_template.h"
26 #include "json/json_spirit_writer_template.h"
27 #include "json/json_spirit_utils.h"
28 #define printf OutputDebugStringF
29 // MinGW 3.4.5 gets "fatal error: had to relocate PCH" if the json headers are
30 // precompiled in headers.h. The problem might be when the pch file goes over
31 // a certain size around 145MB. If we need access to json_spirit outside this
32 // file, we could use the compiled json_spirit option.
35 using namespace boost;
36 using namespace boost::asio;
37 using namespace json_spirit;
39 void ThreadRPCServer2(void* parg);
40 typedef Value(*rpcfn_type)(const Array& params, bool fHelp);
53 map<string, const CRPCCommand*> mapCommands;
56 const CRPCCommand* operator[](string name) const;
57 string help(string name) const;
60 const CRPCTable tableRPC;
62 static std::string strRPCUserColonPass;
64 static int64 nWalletUnlockTime;
65 static CCriticalSection cs_nWalletUnlockTime;
67 extern Value dumpprivkey(const Array& params, bool fHelp);
68 extern Value importprivkey(const Array& params, bool fHelp);
70 Object JSONRPCError(int code, const string& message)
73 error.push_back(Pair("code", code));
74 error.push_back(Pair("message", message));
78 double GetDifficulty(const CBlockIndex* blockindex = NULL)
80 // Floating point number that is a multiple of the minimum difficulty,
81 // minimum difficulty = 1.0.
82 if (blockindex == NULL)
84 if (pindexBest == NULL)
87 blockindex = pindexBest;
90 int nShift = (blockindex->nBits >> 24) & 0xff;
93 (double)0x0000ffff / (double)(blockindex->nBits & 0x00ffffff);
110 int64 AmountFromValue(const Value& value)
112 double dAmount = value.get_real();
113 if (dAmount <= 0.0 || dAmount > 21000000.0)
114 throw JSONRPCError(-3, "Invalid amount");
115 int64 nAmount = roundint64(dAmount * COIN);
116 if (!MoneyRange(nAmount))
117 throw JSONRPCError(-3, "Invalid amount");
121 Value ValueFromAmount(int64 amount)
123 return (double)amount / (double)COIN;
127 HexBits(unsigned int nBits)
133 uBits.nBits = htonl((int32_t)nBits);
134 return HexStr(BEGIN(uBits.cBits), END(uBits.cBits));
137 void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
139 int confirms = wtx.GetDepthInMainChain();
140 entry.push_back(Pair("confirmations", confirms));
143 entry.push_back(Pair("blockhash", wtx.hashBlock.GetHex()));
144 entry.push_back(Pair("blockindex", wtx.nIndex));
146 entry.push_back(Pair("txid", wtx.GetHash().GetHex()));
147 entry.push_back(Pair("time", (boost::int64_t)wtx.GetTxTime()));
148 BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
149 entry.push_back(Pair(item.first, item.second));
152 string AccountFromValue(const Value& value)
154 string strAccount = value.get_str();
155 if (strAccount == "*")
156 throw JSONRPCError(-11, "Invalid account name");
160 Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex)
163 result.push_back(Pair("hash", block.GetHash().GetHex()));
164 result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION)));
165 result.push_back(Pair("height", blockindex->nHeight));
166 result.push_back(Pair("version", block.nVersion));
167 result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex()));
168 result.push_back(Pair("time", (boost::int64_t)block.GetBlockTime()));
169 result.push_back(Pair("nonce", (boost::uint64_t)block.nNonce));
170 result.push_back(Pair("bits", HexBits(block.nBits)));
171 result.push_back(Pair("difficulty", GetDifficulty(blockindex)));
173 BOOST_FOREACH (const CTransaction&tx, block.vtx)
174 txhashes.push_back(tx.GetHash().GetHex());
175 result.push_back(Pair("tx", txhashes));
177 if (blockindex->pprev)
178 result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex()));
179 if (blockindex->pnext)
180 result.push_back(Pair("nextblockhash", blockindex->pnext->GetBlockHash().GetHex()));
187 /// Note: This interface may still be subject to change.
190 string CRPCTable::help(string strCommand) const
193 set<rpcfn_type> setDone;
194 for (map<string, const CRPCCommand*>::const_iterator mi = mapCommands.begin(); mi != mapCommands.end(); ++mi)
196 const CRPCCommand *pcmd = mi->second;
197 string strMethod = mi->first;
198 // We already filter duplicates, but these deprecated screw up the sort order
199 if (strMethod == "getamountreceived" ||
200 strMethod == "getallreceived" ||
201 strMethod == "getblocknumber" || // deprecated
202 (strMethod.find("label") != string::npos))
204 if (strCommand != "" && strMethod != strCommand)
209 rpcfn_type pfn = pcmd->actor;
210 if (setDone.insert(pfn).second)
211 (*pfn)(params, true);
213 catch (std::exception& e)
215 // Help text is returned in an exception
216 string strHelp = string(e.what());
217 if (strCommand == "")
218 if (strHelp.find('\n') != string::npos)
219 strHelp = strHelp.substr(0, strHelp.find('\n'));
220 strRet += strHelp + "\n";
224 strRet = strprintf("help: unknown command: %s\n", strCommand.c_str());
225 strRet = strRet.substr(0,strRet.size()-1);
229 Value help(const Array& params, bool fHelp)
231 if (fHelp || params.size() > 1)
234 "List commands, or get help for a command.");
237 if (params.size() > 0)
238 strCommand = params[0].get_str();
240 return tableRPC.help(strCommand);
244 Value stop(const Array& params, bool fHelp)
246 if (fHelp || params.size() != 0)
249 "Stop bitcoin server.");
250 // Shutdown will take long enough that the response should get back
252 return "bitcoin server stopping";
256 Value getblockcount(const Array& params, bool fHelp)
258 if (fHelp || params.size() != 0)
261 "Returns the number of blocks in the longest block chain.");
268 Value getblocknumber(const Array& params, bool fHelp)
270 if (fHelp || params.size() != 0)
273 "Deprecated. Use getblockcount.");
279 Value getconnectioncount(const Array& params, bool fHelp)
281 if (fHelp || params.size() != 0)
283 "getconnectioncount\n"
284 "Returns the number of connections to other nodes.");
286 return (int)vNodes.size();
290 Value getdifficulty(const Array& params, bool fHelp)
292 if (fHelp || params.size() != 0)
295 "Returns the proof-of-work difficulty as a multiple of the minimum difficulty.");
297 return GetDifficulty();
301 Value getgenerate(const Array& params, bool fHelp)
303 if (fHelp || params.size() != 0)
306 "Returns true or false.");
308 return GetBoolArg("-gen");
312 Value setgenerate(const Array& params, bool fHelp)
314 if (fHelp || params.size() < 1 || params.size() > 2)
316 "setgenerate <generate> [genproclimit]\n"
317 "<generate> is true or false to turn generation on or off.\n"
318 "Generation is limited to [genproclimit] processors, -1 is unlimited.");
320 bool fGenerate = true;
321 if (params.size() > 0)
322 fGenerate = params[0].get_bool();
324 if (params.size() > 1)
326 int nGenProcLimit = params[1].get_int();
327 mapArgs["-genproclimit"] = itostr(nGenProcLimit);
328 if (nGenProcLimit == 0)
331 mapArgs["-gen"] = (fGenerate ? "1" : "0");
333 GenerateBitcoins(fGenerate, pwalletMain);
338 Value gethashespersec(const Array& params, bool fHelp)
340 if (fHelp || params.size() != 0)
343 "Returns a recent hashes per second performance measurement while generating.");
345 if (GetTimeMillis() - nHPSTimerStart > 8000)
346 return (boost::int64_t)0;
347 return (boost::int64_t)dHashesPerSec;
351 Value getinfo(const Array& params, bool fHelp)
353 if (fHelp || params.size() != 0)
356 "Returns an object containing various state info.");
359 obj.push_back(Pair("version", (int)CLIENT_VERSION));
360 obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION));
361 obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
362 obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
363 obj.push_back(Pair("blocks", (int)nBestHeight));
364 obj.push_back(Pair("connections", (int)vNodes.size()));
365 obj.push_back(Pair("proxy", (fUseProxy ? addrProxy.ToStringIPPort() : string())));
366 obj.push_back(Pair("difficulty", (double)GetDifficulty()));
367 obj.push_back(Pair("testnet", fTestNet));
368 obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));
369 obj.push_back(Pair("keypoolsize", pwalletMain->GetKeyPoolSize()));
370 obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee)));
371 if (pwalletMain->IsCrypted())
372 obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime / 1000));
373 obj.push_back(Pair("errors", GetWarnings("statusbar")));
378 Value getmininginfo(const Array& params, bool fHelp)
380 if (fHelp || params.size() != 0)
383 "Returns an object containing mining-related information.");
386 obj.push_back(Pair("blocks", (int)nBestHeight));
387 obj.push_back(Pair("currentblocksize",(uint64_t)nLastBlockSize));
388 obj.push_back(Pair("currentblocktx",(uint64_t)nLastBlockTx));
389 obj.push_back(Pair("difficulty", (double)GetDifficulty()));
390 obj.push_back(Pair("errors", GetWarnings("statusbar")));
391 obj.push_back(Pair("generate", GetBoolArg("-gen")));
392 obj.push_back(Pair("genproclimit", (int)GetArg("-genproclimit", -1)));
393 obj.push_back(Pair("hashespersec", gethashespersec(params, false)));
394 obj.push_back(Pair("pooledtx", (uint64_t)mempool.size()));
395 obj.push_back(Pair("testnet", fTestNet));
400 Value getnewaddress(const Array& params, bool fHelp)
402 if (fHelp || params.size() > 1)
404 "getnewaddress [account]\n"
405 "Returns a new bitcoin address for receiving payments. "
406 "If [account] is specified (recommended), it is added to the address book "
407 "so payments received with the address will be credited to [account].");
409 // Parse the account first so we don't generate a key if there's an error
411 if (params.size() > 0)
412 strAccount = AccountFromValue(params[0]);
414 if (!pwalletMain->IsLocked())
415 pwalletMain->TopUpKeyPool();
417 // Generate a new key that is added to wallet
418 std::vector<unsigned char> newKey;
419 if (!pwalletMain->GetKeyFromPool(newKey, false))
420 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
421 CBitcoinAddress address(newKey);
423 pwalletMain->SetAddressBookName(address, strAccount);
425 return address.ToString();
429 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
431 CWalletDB walletdb(pwalletMain->strWalletFile);
434 walletdb.ReadAccount(strAccount, account);
436 bool bKeyUsed = false;
438 // Check if the current key has been used
439 if (!account.vchPubKey.empty())
441 CScript scriptPubKey;
442 scriptPubKey.SetBitcoinAddress(account.vchPubKey);
443 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
444 it != pwalletMain->mapWallet.end() && !account.vchPubKey.empty();
447 const CWalletTx& wtx = (*it).second;
448 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
449 if (txout.scriptPubKey == scriptPubKey)
454 // Generate a new key
455 if (account.vchPubKey.empty() || bForceNew || bKeyUsed)
457 if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false))
458 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
460 pwalletMain->SetAddressBookName(CBitcoinAddress(account.vchPubKey), strAccount);
461 walletdb.WriteAccount(strAccount, account);
464 return CBitcoinAddress(account.vchPubKey);
467 Value getaccountaddress(const Array& params, bool fHelp)
469 if (fHelp || params.size() != 1)
471 "getaccountaddress <account>\n"
472 "Returns the current bitcoin address for receiving payments to this account.");
474 // Parse the account first so we don't generate a key if there's an error
475 string strAccount = AccountFromValue(params[0]);
479 ret = GetAccountAddress(strAccount).ToString();
486 Value setaccount(const Array& params, bool fHelp)
488 if (fHelp || params.size() < 1 || params.size() > 2)
490 "setaccount <bitcoinaddress> <account>\n"
491 "Sets the account associated with the given address.");
493 CBitcoinAddress address(params[0].get_str());
494 if (!address.IsValid())
495 throw JSONRPCError(-5, "Invalid bitcoin address");
499 if (params.size() > 1)
500 strAccount = AccountFromValue(params[1]);
502 // Detect when changing the account of an address that is the 'unused current key' of another account:
503 if (pwalletMain->mapAddressBook.count(address))
505 string strOldAccount = pwalletMain->mapAddressBook[address];
506 if (address == GetAccountAddress(strOldAccount))
507 GetAccountAddress(strOldAccount, true);
510 pwalletMain->SetAddressBookName(address, strAccount);
516 Value getaccount(const Array& params, bool fHelp)
518 if (fHelp || params.size() != 1)
520 "getaccount <bitcoinaddress>\n"
521 "Returns the account associated with the given address.");
523 CBitcoinAddress address(params[0].get_str());
524 if (!address.IsValid())
525 throw JSONRPCError(-5, "Invalid bitcoin address");
528 map<CBitcoinAddress, string>::iterator mi = pwalletMain->mapAddressBook.find(address);
529 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
530 strAccount = (*mi).second;
535 Value getaddressesbyaccount(const Array& params, bool fHelp)
537 if (fHelp || params.size() != 1)
539 "getaddressesbyaccount <account>\n"
540 "Returns the list of addresses for the given account.");
542 string strAccount = AccountFromValue(params[0]);
544 // Find all addresses that have the given account
546 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
548 const CBitcoinAddress& address = item.first;
549 const string& strName = item.second;
550 if (strName == strAccount)
551 ret.push_back(address.ToString());
556 Value settxfee(const Array& params, bool fHelp)
558 if (fHelp || params.size() < 1 || params.size() > 1)
560 "settxfee <amount>\n"
561 "<amount> is a real and is rounded to the nearest 0.00000001");
565 if (params[0].get_real() != 0.0)
566 nAmount = AmountFromValue(params[0]); // rejects 0.0 amounts
568 nTransactionFee = nAmount;
572 Value sendtoaddress(const Array& params, bool fHelp)
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\n"
578 "requires wallet passphrase to be set with walletpassphrase first");
579 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
581 "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
582 "<amount> is a real and is rounded to the nearest 0.00000001");
584 CBitcoinAddress address(params[0].get_str());
585 if (!address.IsValid())
586 throw JSONRPCError(-5, "Invalid bitcoin address");
589 int64 nAmount = AmountFromValue(params[1]);
593 if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
594 wtx.mapValue["comment"] = params[2].get_str();
595 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
596 wtx.mapValue["to"] = params[3].get_str();
598 if (pwalletMain->IsLocked())
599 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
601 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
603 throw JSONRPCError(-4, strError);
605 return wtx.GetHash().GetHex();
608 Value signmessage(const Array& params, bool fHelp)
610 if (fHelp || params.size() != 2)
612 "signmessage <bitcoinaddress> <message>\n"
613 "Sign a message with the private key of an address");
615 if (pwalletMain->IsLocked())
616 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
618 string strAddress = params[0].get_str();
619 string strMessage = params[1].get_str();
621 CBitcoinAddress addr(strAddress);
623 throw JSONRPCError(-3, "Invalid address");
626 if (!pwalletMain->GetKey(addr, key))
627 throw JSONRPCError(-4, "Private key not available");
629 CDataStream ss(SER_GETHASH, 0);
630 ss << strMessageMagic;
633 vector<unsigned char> vchSig;
634 if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig))
635 throw JSONRPCError(-5, "Sign failed");
637 return EncodeBase64(&vchSig[0], vchSig.size());
640 Value verifymessage(const Array& params, bool fHelp)
642 if (fHelp || params.size() != 3)
644 "verifymessage <bitcoinaddress> <signature> <message>\n"
645 "Verify a signed message");
647 string strAddress = params[0].get_str();
648 string strSign = params[1].get_str();
649 string strMessage = params[2].get_str();
651 CBitcoinAddress addr(strAddress);
653 throw JSONRPCError(-3, "Invalid address");
655 bool fInvalid = false;
656 vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
659 throw JSONRPCError(-5, "Malformed base64 encoding");
661 CDataStream ss(SER_GETHASH, 0);
662 ss << strMessageMagic;
666 if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
669 return (CBitcoinAddress(key.GetPubKey()) == addr);
673 Value getreceivedbyaddress(const Array& params, bool fHelp)
675 if (fHelp || params.size() < 1 || params.size() > 2)
677 "getreceivedbyaddress <bitcoinaddress> [minconf=1]\n"
678 "Returns the total amount received by <bitcoinaddress> in transactions with at least [minconf] confirmations.");
681 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
682 CScript scriptPubKey;
683 if (!address.IsValid())
684 throw JSONRPCError(-5, "Invalid bitcoin address");
685 scriptPubKey.SetBitcoinAddress(address);
686 if (!IsMine(*pwalletMain,scriptPubKey))
689 // Minimum confirmations
691 if (params.size() > 1)
692 nMinDepth = params[1].get_int();
696 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
698 const CWalletTx& wtx = (*it).second;
699 if (wtx.IsCoinBase() || !wtx.IsFinal())
702 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
703 if (txout.scriptPubKey == scriptPubKey)
704 if (wtx.GetDepthInMainChain() >= nMinDepth)
705 nAmount += txout.nValue;
708 return ValueFromAmount(nAmount);
712 void GetAccountAddresses(string strAccount, set<CBitcoinAddress>& setAddress)
714 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
716 const CBitcoinAddress& address = item.first;
717 const string& strName = item.second;
718 if (strName == strAccount)
719 setAddress.insert(address);
724 Value getreceivedbyaccount(const Array& params, bool fHelp)
726 if (fHelp || params.size() < 1 || params.size() > 2)
728 "getreceivedbyaccount <account> [minconf=1]\n"
729 "Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.");
731 // Minimum confirmations
733 if (params.size() > 1)
734 nMinDepth = params[1].get_int();
736 // Get the set of pub keys assigned to account
737 string strAccount = AccountFromValue(params[0]);
738 set<CBitcoinAddress> setAddress;
739 GetAccountAddresses(strAccount, setAddress);
743 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
745 const CWalletTx& wtx = (*it).second;
746 if (wtx.IsCoinBase() || !wtx.IsFinal())
749 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
751 CBitcoinAddress address;
752 if (ExtractAddress(txout.scriptPubKey, address) && pwalletMain->HaveKey(address) && setAddress.count(address))
753 if (wtx.GetDepthInMainChain() >= nMinDepth)
754 nAmount += txout.nValue;
758 return (double)nAmount / (double)COIN;
762 int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth)
766 // Tally wallet transactions
767 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
769 const CWalletTx& wtx = (*it).second;
773 int64 nGenerated, nReceived, nSent, nFee;
774 wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee);
776 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
777 nBalance += nReceived;
778 nBalance += nGenerated - nSent - nFee;
781 // Tally internal accounting entries
782 nBalance += walletdb.GetAccountCreditDebit(strAccount);
787 int64 GetAccountBalance(const string& strAccount, int nMinDepth)
789 CWalletDB walletdb(pwalletMain->strWalletFile);
790 return GetAccountBalance(walletdb, strAccount, nMinDepth);
794 Value getbalance(const Array& params, bool fHelp)
796 if (fHelp || params.size() > 2)
798 "getbalance [account] [minconf=1]\n"
799 "If [account] is not specified, returns the server's total available balance.\n"
800 "If [account] is specified, returns the balance in the account.");
802 if (params.size() == 0)
803 return ValueFromAmount(pwalletMain->GetBalance());
806 if (params.size() > 1)
807 nMinDepth = params[1].get_int();
809 if (params[0].get_str() == "*") {
810 // Calculate total balance a different way from GetBalance()
811 // (GetBalance() sums up all unspent TxOuts)
812 // getbalance and getbalance '*' should always return the same number.
814 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
816 const CWalletTx& wtx = (*it).second;
820 int64 allGeneratedImmature, allGeneratedMature, allFee;
821 allGeneratedImmature = allGeneratedMature = allFee = 0;
822 string strSentAccount;
823 list<pair<CBitcoinAddress, int64> > listReceived;
824 list<pair<CBitcoinAddress, int64> > listSent;
825 wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
826 if (wtx.GetDepthInMainChain() >= nMinDepth)
828 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listReceived)
829 nBalance += r.second;
831 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listSent)
832 nBalance -= r.second;
834 nBalance += allGeneratedMature;
836 return ValueFromAmount(nBalance);
839 string strAccount = AccountFromValue(params[0]);
841 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
843 return ValueFromAmount(nBalance);
847 Value movecmd(const Array& params, bool fHelp)
849 if (fHelp || params.size() < 3 || params.size() > 5)
851 "move <fromaccount> <toaccount> <amount> [minconf=1] [comment]\n"
852 "Move from one account in your wallet to another.");
854 string strFrom = AccountFromValue(params[0]);
855 string strTo = AccountFromValue(params[1]);
856 int64 nAmount = AmountFromValue(params[2]);
857 if (params.size() > 3)
858 // unused parameter, used to be nMinDepth, keep type-checking it though
859 (void)params[3].get_int();
861 if (params.size() > 4)
862 strComment = params[4].get_str();
864 CWalletDB walletdb(pwalletMain->strWalletFile);
867 int64 nNow = GetAdjustedTime();
870 CAccountingEntry debit;
871 debit.strAccount = strFrom;
872 debit.nCreditDebit = -nAmount;
874 debit.strOtherAccount = strTo;
875 debit.strComment = strComment;
876 walletdb.WriteAccountingEntry(debit);
879 CAccountingEntry credit;
880 credit.strAccount = strTo;
881 credit.nCreditDebit = nAmount;
883 credit.strOtherAccount = strFrom;
884 credit.strComment = strComment;
885 walletdb.WriteAccountingEntry(credit);
887 walletdb.TxnCommit();
893 Value sendfrom(const Array& params, bool fHelp)
895 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
897 "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
898 "<amount> is a real and is rounded to the nearest 0.00000001\n"
899 "requires wallet passphrase to be set with walletpassphrase first");
900 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
902 "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
903 "<amount> is a real and is rounded to the nearest 0.00000001");
905 string strAccount = AccountFromValue(params[0]);
906 CBitcoinAddress address(params[1].get_str());
907 if (!address.IsValid())
908 throw JSONRPCError(-5, "Invalid bitcoin address");
909 int64 nAmount = AmountFromValue(params[2]);
911 if (params.size() > 3)
912 nMinDepth = params[3].get_int();
915 wtx.strFromAccount = strAccount;
916 if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
917 wtx.mapValue["comment"] = params[4].get_str();
918 if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
919 wtx.mapValue["to"] = params[5].get_str();
921 if (pwalletMain->IsLocked())
922 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
925 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
926 if (nAmount > nBalance)
927 throw JSONRPCError(-6, "Account has insufficient funds");
930 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
932 throw JSONRPCError(-4, strError);
934 return wtx.GetHash().GetHex();
938 Value sendmany(const Array& params, bool fHelp)
940 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
942 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
943 "amounts are double-precision floating point numbers\n"
944 "requires wallet passphrase to be set with walletpassphrase first");
945 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
947 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
948 "amounts are double-precision floating point numbers");
950 string strAccount = AccountFromValue(params[0]);
951 Object sendTo = params[1].get_obj();
953 if (params.size() > 2)
954 nMinDepth = params[2].get_int();
957 wtx.strFromAccount = strAccount;
958 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
959 wtx.mapValue["comment"] = params[3].get_str();
961 set<CBitcoinAddress> setAddress;
962 vector<pair<CScript, int64> > vecSend;
964 int64 totalAmount = 0;
965 BOOST_FOREACH(const Pair& s, sendTo)
967 CBitcoinAddress address(s.name_);
968 if (!address.IsValid())
969 throw JSONRPCError(-5, string("Invalid bitcoin address:")+s.name_);
971 if (setAddress.count(address))
972 throw JSONRPCError(-8, string("Invalid parameter, duplicated address: ")+s.name_);
973 setAddress.insert(address);
975 CScript scriptPubKey;
976 scriptPubKey.SetBitcoinAddress(address);
977 int64 nAmount = AmountFromValue(s.value_);
978 totalAmount += nAmount;
980 vecSend.push_back(make_pair(scriptPubKey, nAmount));
983 if (pwalletMain->IsLocked())
984 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
987 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
988 if (totalAmount > nBalance)
989 throw JSONRPCError(-6, "Account has insufficient funds");
992 CReserveKey keyChange(pwalletMain);
993 int64 nFeeRequired = 0;
994 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
997 if (totalAmount + nFeeRequired > pwalletMain->GetBalance())
998 throw JSONRPCError(-6, "Insufficient funds");
999 throw JSONRPCError(-4, "Transaction creation failed");
1001 if (!pwalletMain->CommitTransaction(wtx, keyChange))
1002 throw JSONRPCError(-4, "Transaction commit failed");
1004 return wtx.GetHash().GetHex();
1007 Value addmultisigaddress(const Array& params, bool fHelp)
1009 if (fHelp || params.size() < 2 || params.size() > 3)
1011 string msg = "addmultisigaddress <nrequired> <'[\"key\",\"key\"]'> [account]\n"
1012 "Add a nrequired-to-sign multisignature address to the wallet\"\n"
1013 "each key is a bitcoin address or hex-encoded public key\n"
1014 "If [account] is specified, assign address to [account].";
1015 throw runtime_error(msg);
1018 int nRequired = params[0].get_int();
1019 const Array& keys = params[1].get_array();
1021 if (params.size() > 2)
1022 strAccount = AccountFromValue(params[2]);
1024 // Gather public keys
1025 if (nRequired < 1 || keys.size() < nRequired)
1026 throw runtime_error(
1027 strprintf("wrong number of keys"
1028 "(got %d, need at least %d)", keys.size(), nRequired));
1029 std::vector<CKey> pubkeys;
1030 pubkeys.resize(keys.size());
1031 for (unsigned int i = 0; i < keys.size(); i++)
1033 const std::string& ks = keys[i].get_str();
1035 // Case 1: bitcoin address and we have full public key:
1036 CBitcoinAddress address(ks);
1037 if (address.IsValid())
1039 if (address.IsScript())
1040 throw runtime_error(
1041 strprintf("%s is a pay-to-script address",ks.c_str()));
1042 std::vector<unsigned char> vchPubKey;
1043 if (!pwalletMain->GetPubKey(address, vchPubKey))
1044 throw runtime_error(
1045 strprintf("no full public key for address %s",ks.c_str()));
1046 if (vchPubKey.empty() || !pubkeys[i].SetPubKey(vchPubKey))
1047 throw runtime_error(" Invalid public key: "+ks);
1050 // Case 2: hex public key
1053 vector<unsigned char> vchPubKey = ParseHex(ks);
1054 if (vchPubKey.empty() || !pubkeys[i].SetPubKey(vchPubKey))
1055 throw runtime_error(" Invalid public key: "+ks);
1059 throw runtime_error(" Invalid public key: "+ks);
1063 // Construct using pay-to-script-hash:
1065 inner.SetMultisig(nRequired, pubkeys);
1067 uint160 scriptHash = Hash160(inner);
1068 CScript scriptPubKey;
1069 scriptPubKey.SetPayToScriptHash(inner);
1070 pwalletMain->AddCScript(inner);
1071 CBitcoinAddress address;
1072 address.SetScriptHash160(scriptHash);
1074 pwalletMain->SetAddressBookName(address, strAccount);
1075 return address.ToString();
1086 nConf = std::numeric_limits<int>::max();
1090 Value ListReceived(const Array& params, bool fByAccounts)
1092 // Minimum confirmations
1094 if (params.size() > 0)
1095 nMinDepth = params[0].get_int();
1097 // Whether to include empty accounts
1098 bool fIncludeEmpty = false;
1099 if (params.size() > 1)
1100 fIncludeEmpty = params[1].get_bool();
1103 map<CBitcoinAddress, tallyitem> mapTally;
1104 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1106 const CWalletTx& wtx = (*it).second;
1108 if (wtx.IsCoinBase() || !wtx.IsFinal())
1111 int nDepth = wtx.GetDepthInMainChain();
1112 if (nDepth < nMinDepth)
1115 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
1117 CBitcoinAddress address;
1118 if (!ExtractAddress(txout.scriptPubKey, address) || !pwalletMain->HaveKey(address) || !address.IsValid())
1121 tallyitem& item = mapTally[address];
1122 item.nAmount += txout.nValue;
1123 item.nConf = min(item.nConf, nDepth);
1129 map<string, tallyitem> mapAccountTally;
1130 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
1132 const CBitcoinAddress& address = item.first;
1133 const string& strAccount = item.second;
1134 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
1135 if (it == mapTally.end() && !fIncludeEmpty)
1139 int nConf = std::numeric_limits<int>::max();
1140 if (it != mapTally.end())
1142 nAmount = (*it).second.nAmount;
1143 nConf = (*it).second.nConf;
1148 tallyitem& item = mapAccountTally[strAccount];
1149 item.nAmount += nAmount;
1150 item.nConf = min(item.nConf, nConf);
1155 obj.push_back(Pair("address", address.ToString()));
1156 obj.push_back(Pair("account", strAccount));
1157 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1158 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1165 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
1167 int64 nAmount = (*it).second.nAmount;
1168 int nConf = (*it).second.nConf;
1170 obj.push_back(Pair("account", (*it).first));
1171 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1172 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1180 Value listreceivedbyaddress(const Array& params, bool fHelp)
1182 if (fHelp || params.size() > 2)
1183 throw runtime_error(
1184 "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
1185 "[minconf] is the minimum number of confirmations before payments are included.\n"
1186 "[includeempty] whether to include addresses that haven't received any payments.\n"
1187 "Returns an array of objects containing:\n"
1188 " \"address\" : receiving address\n"
1189 " \"account\" : the account of the receiving address\n"
1190 " \"amount\" : total amount received by the address\n"
1191 " \"confirmations\" : number of confirmations of the most recent transaction included");
1193 return ListReceived(params, false);
1196 Value listreceivedbyaccount(const Array& params, bool fHelp)
1198 if (fHelp || params.size() > 2)
1199 throw runtime_error(
1200 "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
1201 "[minconf] is the minimum number of confirmations before payments are included.\n"
1202 "[includeempty] whether to include accounts that haven't received any payments.\n"
1203 "Returns an array of objects containing:\n"
1204 " \"account\" : the account of the receiving addresses\n"
1205 " \"amount\" : total amount received by addresses with this account\n"
1206 " \"confirmations\" : number of confirmations of the most recent transaction included");
1208 return ListReceived(params, true);
1211 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret)
1213 int64 nGeneratedImmature, nGeneratedMature, nFee;
1214 string strSentAccount;
1215 list<pair<CBitcoinAddress, int64> > listReceived;
1216 list<pair<CBitcoinAddress, int64> > listSent;
1218 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1220 bool fAllAccounts = (strAccount == string("*"));
1222 // Generated blocks assigned to account ""
1223 if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == ""))
1226 entry.push_back(Pair("account", string("")));
1227 if (nGeneratedImmature)
1229 entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
1230 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
1234 entry.push_back(Pair("category", "generate"));
1235 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
1238 WalletTxToJSON(wtx, entry);
1239 ret.push_back(entry);
1243 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1245 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1248 entry.push_back(Pair("account", strSentAccount));
1249 entry.push_back(Pair("address", s.first.ToString()));
1250 entry.push_back(Pair("category", "send"));
1251 entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1252 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1254 WalletTxToJSON(wtx, entry);
1255 ret.push_back(entry);
1260 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1262 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1265 if (pwalletMain->mapAddressBook.count(r.first))
1266 account = pwalletMain->mapAddressBook[r.first];
1267 if (fAllAccounts || (account == strAccount))
1270 entry.push_back(Pair("account", account));
1271 entry.push_back(Pair("address", r.first.ToString()));
1272 entry.push_back(Pair("category", "receive"));
1273 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1275 WalletTxToJSON(wtx, entry);
1276 ret.push_back(entry);
1282 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1284 bool fAllAccounts = (strAccount == string("*"));
1286 if (fAllAccounts || acentry.strAccount == strAccount)
1289 entry.push_back(Pair("account", acentry.strAccount));
1290 entry.push_back(Pair("category", "move"));
1291 entry.push_back(Pair("time", (boost::int64_t)acentry.nTime));
1292 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1293 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1294 entry.push_back(Pair("comment", acentry.strComment));
1295 ret.push_back(entry);
1299 Value listtransactions(const Array& params, bool fHelp)
1301 if (fHelp || params.size() > 3)
1302 throw runtime_error(
1303 "listtransactions [account] [count=10] [from=0]\n"
1304 "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1306 string strAccount = "*";
1307 if (params.size() > 0)
1308 strAccount = params[0].get_str();
1310 if (params.size() > 1)
1311 nCount = params[1].get_int();
1313 if (params.size() > 2)
1314 nFrom = params[2].get_int();
1317 throw JSONRPCError(-8, "Negative count");
1319 throw JSONRPCError(-8, "Negative from");
1322 CWalletDB walletdb(pwalletMain->strWalletFile);
1324 // First: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap.
1325 typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
1326 typedef multimap<int64, TxPair > TxItems;
1329 // Note: maintaining indices in the database of (account,time) --> txid and (account, time) --> acentry
1330 // would make this much faster for applications that do this a lot.
1331 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1333 CWalletTx* wtx = &((*it).second);
1334 txByTime.insert(make_pair(wtx->GetTxTime(), TxPair(wtx, (CAccountingEntry*)0)));
1336 list<CAccountingEntry> acentries;
1337 walletdb.ListAccountCreditDebit(strAccount, acentries);
1338 BOOST_FOREACH(CAccountingEntry& entry, acentries)
1340 txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
1343 // iterate backwards until we have nCount items to return:
1344 for (TxItems::reverse_iterator it = txByTime.rbegin(); it != txByTime.rend(); ++it)
1346 CWalletTx *const pwtx = (*it).second.first;
1348 ListTransactions(*pwtx, strAccount, 0, true, ret);
1349 CAccountingEntry *const pacentry = (*it).second.second;
1351 AcentryToJSON(*pacentry, strAccount, ret);
1353 if (ret.size() >= (nCount+nFrom)) break;
1355 // ret is newest to oldest
1357 if (nFrom > ret.size()) nFrom = ret.size();
1358 if (nFrom+nCount > ret.size()) nCount = ret.size()-nFrom;
1359 Array::iterator first = ret.begin();
1360 std::advance(first, nFrom);
1361 Array::iterator last = ret.begin();
1362 std::advance(last, nFrom+nCount);
1364 if (last != ret.end()) ret.erase(last, ret.end());
1365 if (first != ret.begin()) ret.erase(ret.begin(), first);
1367 std::reverse(ret.begin(), ret.end()); // Return oldest to newest
1372 Value listaccounts(const Array& params, bool fHelp)
1374 if (fHelp || params.size() > 1)
1375 throw runtime_error(
1376 "listaccounts [minconf=1]\n"
1377 "Returns Object that has account names as keys, account balances as values.");
1380 if (params.size() > 0)
1381 nMinDepth = params[0].get_int();
1383 map<string, int64> mapAccountBalances;
1384 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& entry, pwalletMain->mapAddressBook) {
1385 if (pwalletMain->HaveKey(entry.first)) // This address belongs to me
1386 mapAccountBalances[entry.second] = 0;
1389 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1391 const CWalletTx& wtx = (*it).second;
1392 int64 nGeneratedImmature, nGeneratedMature, nFee;
1393 string strSentAccount;
1394 list<pair<CBitcoinAddress, int64> > listReceived;
1395 list<pair<CBitcoinAddress, int64> > listSent;
1396 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1397 mapAccountBalances[strSentAccount] -= nFee;
1398 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1399 mapAccountBalances[strSentAccount] -= s.second;
1400 if (wtx.GetDepthInMainChain() >= nMinDepth)
1402 mapAccountBalances[""] += nGeneratedMature;
1403 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1404 if (pwalletMain->mapAddressBook.count(r.first))
1405 mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1407 mapAccountBalances[""] += r.second;
1411 list<CAccountingEntry> acentries;
1412 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1413 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1414 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1417 BOOST_FOREACH(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) {
1418 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1423 Value listsinceblock(const Array& params, bool fHelp)
1426 throw runtime_error(
1427 "listsinceblock [blockid] [target-confirmations]\n"
1428 "Get all transactions in blocks since block [blockid], or all transactions if omitted");
1430 CBlockIndex *pindex = NULL;
1431 int target_confirms = 1;
1433 if (params.size() > 0)
1435 uint256 blockId = 0;
1437 blockId.SetHex(params[0].get_str());
1438 pindex = CBlockLocator(blockId).GetBlockIndex();
1441 if (params.size() > 1)
1443 target_confirms = params[1].get_int();
1445 if (target_confirms < 1)
1446 throw JSONRPCError(-8, "Invalid parameter");
1449 int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1;
1453 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1455 CWalletTx tx = (*it).second;
1457 if (depth == -1 || tx.GetDepthInMainChain() < depth)
1458 ListTransactions(tx, "*", 0, true, transactions);
1463 if (target_confirms == 1)
1466 lastblock = hashBestChain;
1470 int target_height = pindexBest->nHeight + 1 - target_confirms;
1473 for (block = pindexBest;
1474 block && block->nHeight > target_height;
1475 block = block->pprev) { }
1477 lastblock = block ? block->GetBlockHash() : 0;
1481 ret.push_back(Pair("transactions", transactions));
1482 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1487 Value gettransaction(const Array& params, bool fHelp)
1489 if (fHelp || params.size() != 1)
1490 throw runtime_error(
1491 "gettransaction <txid>\n"
1492 "Get detailed information about <txid>");
1495 hash.SetHex(params[0].get_str());
1499 if (!pwalletMain->mapWallet.count(hash))
1500 throw JSONRPCError(-5, "Invalid or non-wallet transaction id");
1501 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1503 int64 nCredit = wtx.GetCredit();
1504 int64 nDebit = wtx.GetDebit();
1505 int64 nNet = nCredit - nDebit;
1506 int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
1508 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1510 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1512 WalletTxToJSON(pwalletMain->mapWallet[hash], entry);
1515 ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
1516 entry.push_back(Pair("details", details));
1522 Value backupwallet(const Array& params, bool fHelp)
1524 if (fHelp || params.size() != 1)
1525 throw runtime_error(
1526 "backupwallet <destination>\n"
1527 "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1529 string strDest = params[0].get_str();
1530 BackupWallet(*pwalletMain, strDest);
1536 Value keypoolrefill(const Array& params, bool fHelp)
1538 if (pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1539 throw runtime_error(
1541 "Fills the keypool, requires wallet passphrase to be set.");
1542 if (!pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1543 throw runtime_error(
1545 "Fills the keypool.");
1547 if (pwalletMain->IsLocked())
1548 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
1550 pwalletMain->TopUpKeyPool();
1552 if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100))
1553 throw JSONRPCError(-4, "Error refreshing keypool.");
1559 void ThreadTopUpKeyPool(void* parg)
1561 pwalletMain->TopUpKeyPool();
1564 void ThreadCleanWalletPassphrase(void* parg)
1566 int64 nMyWakeTime = GetTimeMillis() + *((int64*)parg) * 1000;
1568 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1570 if (nWalletUnlockTime == 0)
1572 nWalletUnlockTime = nMyWakeTime;
1576 if (nWalletUnlockTime==0)
1578 int64 nToSleep = nWalletUnlockTime - GetTimeMillis();
1582 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1584 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1588 if (nWalletUnlockTime)
1590 nWalletUnlockTime = 0;
1591 pwalletMain->Lock();
1596 if (nWalletUnlockTime < nMyWakeTime)
1597 nWalletUnlockTime = nMyWakeTime;
1600 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1602 delete (int64*)parg;
1605 Value walletpassphrase(const Array& params, bool fHelp)
1607 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1608 throw runtime_error(
1609 "walletpassphrase <passphrase> <timeout>\n"
1610 "Stores the wallet decryption key in memory for <timeout> seconds.");
1613 if (!pwalletMain->IsCrypted())
1614 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1616 if (!pwalletMain->IsLocked())
1617 throw JSONRPCError(-17, "Error: Wallet is already unlocked.");
1619 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1620 SecureString strWalletPass;
1621 strWalletPass.reserve(100);
1622 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1623 // Alternately, find a way to make params[0] mlock()'d to begin with.
1624 strWalletPass = params[0].get_str().c_str();
1626 if (strWalletPass.length() > 0)
1628 if (!pwalletMain->Unlock(strWalletPass))
1629 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1632 throw runtime_error(
1633 "walletpassphrase <passphrase> <timeout>\n"
1634 "Stores the wallet decryption key in memory for <timeout> seconds.");
1636 CreateThread(ThreadTopUpKeyPool, NULL);
1637 int64* pnSleepTime = new int64(params[1].get_int64());
1638 CreateThread(ThreadCleanWalletPassphrase, pnSleepTime);
1644 Value walletpassphrasechange(const Array& params, bool fHelp)
1646 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1647 throw runtime_error(
1648 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1649 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1652 if (!pwalletMain->IsCrypted())
1653 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1655 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1656 // Alternately, find a way to make params[0] mlock()'d to begin with.
1657 SecureString strOldWalletPass;
1658 strOldWalletPass.reserve(100);
1659 strOldWalletPass = params[0].get_str().c_str();
1661 SecureString strNewWalletPass;
1662 strNewWalletPass.reserve(100);
1663 strNewWalletPass = params[1].get_str().c_str();
1665 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1666 throw runtime_error(
1667 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1668 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1670 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1671 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1677 Value walletlock(const Array& params, bool fHelp)
1679 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1680 throw runtime_error(
1682 "Removes the wallet encryption key from memory, locking the wallet.\n"
1683 "After calling this method, you will need to call walletpassphrase again\n"
1684 "before being able to call any methods which require the wallet to be unlocked.");
1687 if (!pwalletMain->IsCrypted())
1688 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called.");
1691 LOCK(cs_nWalletUnlockTime);
1692 pwalletMain->Lock();
1693 nWalletUnlockTime = 0;
1700 Value encryptwallet(const Array& params, bool fHelp)
1702 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1703 throw runtime_error(
1704 "encryptwallet <passphrase>\n"
1705 "Encrypts the wallet with <passphrase>.");
1708 if (pwalletMain->IsCrypted())
1709 throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
1711 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1712 // Alternately, find a way to make params[0] mlock()'d to begin with.
1713 SecureString strWalletPass;
1714 strWalletPass.reserve(100);
1715 strWalletPass = params[0].get_str().c_str();
1717 if (strWalletPass.length() < 1)
1718 throw runtime_error(
1719 "encryptwallet <passphrase>\n"
1720 "Encrypts the wallet with <passphrase>.");
1722 if (!pwalletMain->EncryptWallet(strWalletPass))
1723 throw JSONRPCError(-16, "Error: Failed to encrypt the wallet.");
1725 // BDB seems to have a bad habit of writing old data into
1726 // slack space in .dat files; that is bad if the old data is
1727 // unencrypted private keys. So:
1729 return "wallet encrypted; bitcoin server stopping, restart to run with encrypted wallet";
1733 Value validateaddress(const Array& params, bool fHelp)
1735 if (fHelp || params.size() != 1)
1736 throw runtime_error(
1737 "validateaddress <bitcoinaddress>\n"
1738 "Return information about <bitcoinaddress>.");
1740 CBitcoinAddress address(params[0].get_str());
1741 bool isValid = address.IsValid();
1744 ret.push_back(Pair("isvalid", isValid));
1747 // Call Hash160ToAddress() so we always return current ADDRESSVERSION
1748 // version of the address:
1749 string currentAddress = address.ToString();
1750 ret.push_back(Pair("address", currentAddress));
1751 if (pwalletMain->HaveKey(address))
1753 ret.push_back(Pair("ismine", true));
1754 std::vector<unsigned char> vchPubKey;
1755 pwalletMain->GetPubKey(address, vchPubKey);
1756 ret.push_back(Pair("pubkey", HexStr(vchPubKey)));
1758 key.SetPubKey(vchPubKey);
1759 ret.push_back(Pair("iscompressed", key.IsCompressed()));
1761 else if (pwalletMain->HaveCScript(address.GetHash160()))
1763 ret.push_back(Pair("isscript", true));
1765 pwalletMain->GetCScript(address.GetHash160(), subscript);
1766 ret.push_back(Pair("ismine", ::IsMine(*pwalletMain, subscript)));
1767 std::vector<CBitcoinAddress> addresses;
1768 txnouttype whichType;
1770 ExtractAddresses(subscript, whichType, addresses, nRequired);
1771 ret.push_back(Pair("script", GetTxnOutputType(whichType)));
1773 BOOST_FOREACH(const CBitcoinAddress& addr, addresses)
1774 a.push_back(addr.ToString());
1775 ret.push_back(Pair("addresses", a));
1776 if (whichType == TX_MULTISIG)
1777 ret.push_back(Pair("sigsrequired", nRequired));
1780 ret.push_back(Pair("ismine", false));
1781 if (pwalletMain->mapAddressBook.count(address))
1782 ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
1787 Value getwork(const Array& params, bool fHelp)
1789 if (fHelp || params.size() > 1)
1790 throw runtime_error(
1792 "If [data] is not specified, returns formatted hash data to work on:\n"
1793 " \"midstate\" : precomputed hash state after hashing the first half of the data (DEPRECATED)\n" // deprecated
1794 " \"data\" : block data\n"
1795 " \"hash1\" : formatted hash buffer for second hash (DEPRECATED)\n" // deprecated
1796 " \"target\" : little endian hash target\n"
1797 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1800 throw JSONRPCError(-9, "Bitcoin is not connected!");
1802 if (IsInitialBlockDownload())
1803 throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
1805 typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
1806 static mapNewBlock_t mapNewBlock;
1807 static vector<CBlock*> vNewBlock;
1808 static CReserveKey reservekey(pwalletMain);
1810 if (params.size() == 0)
1813 static unsigned int nTransactionsUpdatedLast;
1814 static CBlockIndex* pindexPrev;
1815 static int64 nStart;
1816 static CBlock* pblock;
1817 if (pindexPrev != pindexBest ||
1818 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
1820 if (pindexPrev != pindexBest)
1822 // Deallocate old blocks since they're obsolete now
1823 mapNewBlock.clear();
1824 BOOST_FOREACH(CBlock* pblock, vNewBlock)
1828 nTransactionsUpdatedLast = nTransactionsUpdated;
1829 pindexPrev = pindexBest;
1833 pblock = CreateNewBlock(reservekey);
1835 throw JSONRPCError(-7, "Out of memory");
1836 vNewBlock.push_back(pblock);
1840 pblock->UpdateTime(pindexPrev);
1843 // Update nExtraNonce
1844 static unsigned int nExtraNonce = 0;
1845 IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
1848 mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
1850 // Prebuild hash buffers
1854 FormatHashBuffers(pblock, pmidstate, pdata, phash1);
1856 uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
1859 result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate)))); // deprecated
1860 result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata))));
1861 result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1)))); // deprecated
1862 result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
1868 vector<unsigned char> vchData = ParseHex(params[0].get_str());
1869 if (vchData.size() != 128)
1870 throw JSONRPCError(-8, "Invalid parameter");
1871 CBlock* pdata = (CBlock*)&vchData[0];
1874 for (int i = 0; i < 128/4; i++)
1875 ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]);
1878 if (!mapNewBlock.count(pdata->hashMerkleRoot))
1880 CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
1882 pblock->nTime = pdata->nTime;
1883 pblock->nNonce = pdata->nNonce;
1884 pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
1885 pblock->hashMerkleRoot = pblock->BuildMerkleTree();
1887 return CheckWork(pblock, *pwalletMain, reservekey);
1892 Value getmemorypool(const Array& params, bool fHelp)
1894 if (fHelp || params.size() > 1)
1895 throw runtime_error(
1896 "getmemorypool [data]\n"
1897 "If [data] is not specified, returns data needed to construct a block to work on:\n"
1898 " \"version\" : block version\n"
1899 " \"previousblockhash\" : hash of current highest block\n"
1900 " \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
1901 " \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
1902 " \"coinbaseflags\" : data that should be included in coinbase so support for new features can be judged\n"
1903 " \"time\" : timestamp appropriate for next block\n"
1904 " \"mintime\" : minimum timestamp appropriate for next block\n"
1905 " \"curtime\" : current timestamp\n"
1906 " \"bits\" : compressed target of next block\n"
1907 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1909 if (params.size() == 0)
1912 throw JSONRPCError(-9, "Bitcoin is not connected!");
1914 if (IsInitialBlockDownload())
1915 throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
1917 static CReserveKey reservekey(pwalletMain);
1920 static unsigned int nTransactionsUpdatedLast;
1921 static CBlockIndex* pindexPrev;
1922 static int64 nStart;
1923 static CBlock* pblock;
1924 if (pindexPrev != pindexBest ||
1925 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5))
1927 nTransactionsUpdatedLast = nTransactionsUpdated;
1928 pindexPrev = pindexBest;
1934 pblock = CreateNewBlock(reservekey);
1936 throw JSONRPCError(-7, "Out of memory");
1940 pblock->UpdateTime(pindexPrev);
1944 BOOST_FOREACH(CTransaction tx, pblock->vtx) {
1948 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
1951 transactions.push_back(HexStr(ssTx.begin(), ssTx.end()));
1955 result.push_back(Pair("version", pblock->nVersion));
1956 result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
1957 result.push_back(Pair("transactions", transactions));
1958 result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
1959 result.push_back(Pair("coinbaseflags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end())));
1960 result.push_back(Pair("time", (int64_t)pblock->nTime));
1961 result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1));
1962 result.push_back(Pair("curtime", (int64_t)GetAdjustedTime()));
1963 result.push_back(Pair("bits", HexBits(pblock->nBits)));
1970 CDataStream ssBlock(ParseHex(params[0].get_str()), SER_NETWORK, PROTOCOL_VERSION);
1974 return ProcessBlock(NULL, &pblock);
1978 Value getblockhash(const Array& params, bool fHelp)
1980 if (fHelp || params.size() != 1)
1981 throw runtime_error(
1982 "getblockhash <index>\n"
1983 "Returns hash of block in best-block-chain at <index>.");
1985 int nHeight = params[0].get_int();
1986 if (nHeight < 0 || nHeight > nBestHeight)
1987 throw runtime_error("Block number out of range.");
1990 CBlockIndex* pblockindex = mapBlockIndex[hashBestChain];
1991 while (pblockindex->nHeight > nHeight)
1992 pblockindex = pblockindex->pprev;
1993 return pblockindex->phashBlock->GetHex();
1996 Value getblock(const Array& params, bool fHelp)
1998 if (fHelp || params.size() != 1)
1999 throw runtime_error(
2001 "Returns details of a block with given block-hash.");
2003 std::string strHash = params[0].get_str();
2004 uint256 hash(strHash);
2006 if (mapBlockIndex.count(hash) == 0)
2007 throw JSONRPCError(-5, "Block not found");
2010 CBlockIndex* pblockindex = mapBlockIndex[hash];
2011 block.ReadFromDisk(pblockindex, true);
2013 return blockToJSON(block, pblockindex);
2031 static CRPCCommand vRPCCommands[] =
2032 { // name function safe mode?
2033 // ------------------------ ----------------------- ----------
2034 { "help", &help, true },
2035 { "stop", &stop, true },
2036 { "getblockcount", &getblockcount, true },
2037 { "getblocknumber", &getblocknumber, true },
2038 { "getconnectioncount", &getconnectioncount, true },
2039 { "getdifficulty", &getdifficulty, true },
2040 { "getgenerate", &getgenerate, true },
2041 { "setgenerate", &setgenerate, true },
2042 { "gethashespersec", &gethashespersec, true },
2043 { "getinfo", &getinfo, true },
2044 { "getmininginfo", &getmininginfo, true },
2045 { "getnewaddress", &getnewaddress, true },
2046 { "getaccountaddress", &getaccountaddress, true },
2047 { "setaccount", &setaccount, true },
2048 { "getaccount", &getaccount, false },
2049 { "getaddressesbyaccount", &getaddressesbyaccount, true },
2050 { "sendtoaddress", &sendtoaddress, false },
2051 { "getreceivedbyaddress", &getreceivedbyaddress, false },
2052 { "getreceivedbyaccount", &getreceivedbyaccount, false },
2053 { "listreceivedbyaddress", &listreceivedbyaddress, false },
2054 { "listreceivedbyaccount", &listreceivedbyaccount, false },
2055 { "backupwallet", &backupwallet, true },
2056 { "keypoolrefill", &keypoolrefill, true },
2057 { "walletpassphrase", &walletpassphrase, true },
2058 { "walletpassphrasechange", &walletpassphrasechange, false },
2059 { "walletlock", &walletlock, true },
2060 { "encryptwallet", &encryptwallet, false },
2061 { "validateaddress", &validateaddress, true },
2062 { "getbalance", &getbalance, false },
2063 { "move", &movecmd, false },
2064 { "sendfrom", &sendfrom, false },
2065 { "sendmany", &sendmany, false },
2066 { "addmultisigaddress", &addmultisigaddress, false },
2067 { "getblock", &getblock, false },
2068 { "getblockhash", &getblockhash, false },
2069 { "gettransaction", &gettransaction, false },
2070 { "listtransactions", &listtransactions, false },
2071 { "signmessage", &signmessage, false },
2072 { "verifymessage", &verifymessage, false },
2073 { "getwork", &getwork, true },
2074 { "listaccounts", &listaccounts, false },
2075 { "settxfee", &settxfee, false },
2076 { "getmemorypool", &getmemorypool, true },
2077 { "listsinceblock", &listsinceblock, false },
2078 { "dumpprivkey", &dumpprivkey, false },
2079 { "importprivkey", &importprivkey, false },
2082 CRPCTable::CRPCTable()
2085 for (vcidx = 0; vcidx < (sizeof(vRPCCommands) / sizeof(vRPCCommands[0])); vcidx++)
2089 pcmd = &vRPCCommands[vcidx];
2090 mapCommands[pcmd->name] = pcmd;
2094 const CRPCCommand *CRPCTable::operator[](string name) const
2096 map<string, const CRPCCommand*>::const_iterator it = mapCommands.find(name);
2097 if (it == mapCommands.end())
2099 return (*it).second;
2105 // This ain't Apache. We're just using HTTP header for the length field
2106 // and to be compatible with other JSON-RPC implementations.
2109 string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
2112 s << "POST / HTTP/1.1\r\n"
2113 << "User-Agent: bitcoin-json-rpc/" << FormatFullVersion() << "\r\n"
2114 << "Host: 127.0.0.1\r\n"
2115 << "Content-Type: application/json\r\n"
2116 << "Content-Length: " << strMsg.size() << "\r\n"
2117 << "Connection: close\r\n"
2118 << "Accept: application/json\r\n";
2119 BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
2120 s << item.first << ": " << item.second << "\r\n";
2121 s << "\r\n" << strMsg;
2126 string rfc1123Time()
2131 struct tm* now_gmt = gmtime(&now);
2132 string locale(setlocale(LC_TIME, NULL));
2133 setlocale(LC_TIME, "C"); // we want posix (aka "C") weekday/month strings
2134 strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt);
2135 setlocale(LC_TIME, locale.c_str());
2136 return string(buffer);
2139 static string HTTPReply(int nStatus, const string& strMsg)
2142 return strprintf("HTTP/1.0 401 Authorization Required\r\n"
2144 "Server: bitcoin-json-rpc/%s\r\n"
2145 "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
2146 "Content-Type: text/html\r\n"
2147 "Content-Length: 296\r\n"
2149 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
2150 "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
2153 "<TITLE>Error</TITLE>\r\n"
2154 "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
2156 "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
2157 "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
2158 const char *cStatus;
2159 if (nStatus == 200) cStatus = "OK";
2160 else if (nStatus == 400) cStatus = "Bad Request";
2161 else if (nStatus == 403) cStatus = "Forbidden";
2162 else if (nStatus == 404) cStatus = "Not Found";
2163 else if (nStatus == 500) cStatus = "Internal Server Error";
2166 "HTTP/1.1 %d %s\r\n"
2168 "Connection: close\r\n"
2169 "Content-Length: %d\r\n"
2170 "Content-Type: application/json\r\n"
2171 "Server: bitcoin-json-rpc/%s\r\n"
2176 rfc1123Time().c_str(),
2178 FormatFullVersion().c_str(),
2182 int ReadHTTPStatus(std::basic_istream<char>& stream)
2185 getline(stream, str);
2186 vector<string> vWords;
2187 boost::split(vWords, str, boost::is_any_of(" "));
2188 if (vWords.size() < 2)
2190 return atoi(vWords[1].c_str());
2193 int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
2199 std::getline(stream, str);
2200 if (str.empty() || str == "\r")
2202 string::size_type nColon = str.find(":");
2203 if (nColon != string::npos)
2205 string strHeader = str.substr(0, nColon);
2206 boost::trim(strHeader);
2207 boost::to_lower(strHeader);
2208 string strValue = str.substr(nColon+1);
2209 boost::trim(strValue);
2210 mapHeadersRet[strHeader] = strValue;
2211 if (strHeader == "content-length")
2212 nLen = atoi(strValue.c_str());
2218 int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
2220 mapHeadersRet.clear();
2224 int nStatus = ReadHTTPStatus(stream);
2227 int nLen = ReadHTTPHeader(stream, mapHeadersRet);
2228 if (nLen < 0 || nLen > MAX_SIZE)
2234 vector<char> vch(nLen);
2235 stream.read(&vch[0], nLen);
2236 strMessageRet = string(vch.begin(), vch.end());
2242 bool HTTPAuthorized(map<string, string>& mapHeaders)
2244 string strAuth = mapHeaders["authorization"];
2245 if (strAuth.substr(0,6) != "Basic ")
2247 string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
2248 string strUserPass = DecodeBase64(strUserPass64);
2249 return strUserPass == strRPCUserColonPass;
2253 // JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
2254 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
2255 // unspecified (HTTP errors and contents of 'error').
2257 // 1.0 spec: http://json-rpc.org/wiki/specification
2258 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
2259 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
2262 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
2265 request.push_back(Pair("method", strMethod));
2266 request.push_back(Pair("params", params));
2267 request.push_back(Pair("id", id));
2268 return write_string(Value(request), false) + "\n";
2271 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
2274 if (error.type() != null_type)
2275 reply.push_back(Pair("result", Value::null));
2277 reply.push_back(Pair("result", result));
2278 reply.push_back(Pair("error", error));
2279 reply.push_back(Pair("id", id));
2280 return write_string(Value(reply), false) + "\n";
2283 void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
2285 // Send error reply from json-rpc error object
2287 int code = find_value(objError, "code").get_int();
2288 if (code == -32600) nStatus = 400;
2289 else if (code == -32601) nStatus = 404;
2290 string strReply = JSONRPCReply(Value::null, objError, id);
2291 stream << HTTPReply(nStatus, strReply) << std::flush;
2294 bool ClientAllowed(const string& strAddress)
2296 if (strAddress == asio::ip::address_v4::loopback().to_string())
2298 const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
2299 BOOST_FOREACH(string strAllow, vAllow)
2300 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;
2357 void ThreadRPCServer(void* parg)
2359 IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
2362 vnThreadsRunning[THREAD_RPCSERVER]++;
2363 ThreadRPCServer2(parg);
2364 vnThreadsRunning[THREAD_RPCSERVER]--;
2366 catch (std::exception& e) {
2367 vnThreadsRunning[THREAD_RPCSERVER]--;
2368 PrintException(&e, "ThreadRPCServer()");
2370 vnThreadsRunning[THREAD_RPCSERVER]--;
2371 PrintException(NULL, "ThreadRPCServer()");
2373 printf("ThreadRPCServer exiting\n");
2376 void ThreadRPCServer2(void* parg)
2378 printf("ThreadRPCServer started\n");
2380 strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
2381 if (mapArgs["-rpcpassword"] == "")
2383 unsigned char rand_pwd[32];
2384 RAND_bytes(rand_pwd, 32);
2385 string strWhatAmI = "To use bitcoind";
2386 if (mapArgs.count("-server"))
2387 strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
2388 else if (mapArgs.count("-daemon"))
2389 strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
2390 ThreadSafeMessageBox(strprintf(
2391 _("%s, you must set a rpcpassword in the configuration file:\n %s\n"
2392 "It is recommended you use the following random password:\n"
2393 "rpcuser=bitcoinrpc\n"
2395 "(you do not need to remember this password)\n"
2396 "If the file does not exist, create it with owner-readable-only file permissions.\n"),
2398 GetConfigFile().string().c_str(),
2399 EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str()),
2400 _("Error"), wxOK | wxMODAL);
2405 bool fUseSSL = GetBoolArg("-rpcssl");
2406 asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
2408 asio::io_service io_service;
2409 ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", 8332));
2410 ip::tcp::acceptor acceptor(io_service);
2413 acceptor.open(endpoint.protocol());
2414 acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
2415 acceptor.bind(endpoint);
2416 acceptor.listen(socket_base::max_connections);
2418 catch(boost::system::system_error &e)
2420 ThreadSafeMessageBox(strprintf(_("An error occured while setting up the RPC port %i for listening: %s"), endpoint.port(), e.what()),
2421 _("Error"), wxOK | wxMODAL);
2426 ssl::context context(io_service, ssl::context::sslv23);
2429 context.set_options(ssl::context::no_sslv2);
2431 filesystem::path pathCertFile(GetArg("-rpcsslcertificatechainfile", "server.cert"));
2432 if (!pathCertFile.is_complete()) pathCertFile = filesystem::path(GetDataDir()) / pathCertFile;
2433 if (filesystem::exists(pathCertFile)) context.use_certificate_chain_file(pathCertFile.string());
2434 else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", pathCertFile.string().c_str());
2436 filesystem::path pathPKFile(GetArg("-rpcsslprivatekeyfile", "server.pem"));
2437 if (!pathPKFile.is_complete()) pathPKFile = filesystem::path(GetDataDir()) / pathPKFile;
2438 if (filesystem::exists(pathPKFile)) context.use_private_key_file(pathPKFile.string(), ssl::context::pem);
2439 else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pathPKFile.string().c_str());
2441 string strCiphers = GetArg("-rpcsslciphers", "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
2442 SSL_CTX_set_cipher_list(context.impl(), strCiphers.c_str());
2447 // Accept connection
2448 SSLStream sslStream(io_service, context);
2449 SSLIOStreamDevice d(sslStream, fUseSSL);
2450 iostreams::stream<SSLIOStreamDevice> stream(d);
2452 ip::tcp::endpoint peer;
2453 vnThreadsRunning[THREAD_RPCSERVER]--;
2454 acceptor.accept(sslStream.lowest_layer(), peer);
2455 vnThreadsRunning[4]++;
2459 // Restrict callers by IP
2460 if (!ClientAllowed(peer.address().to_string()))
2462 // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
2464 stream << HTTPReply(403, "") << std::flush;
2468 map<string, string> mapHeaders;
2471 boost::thread api_caller(ReadHTTP, boost::ref(stream), boost::ref(mapHeaders), boost::ref(strRequest));
2472 if (!api_caller.timed_join(boost::posix_time::seconds(GetArg("-rpctimeout", 30))))
2475 printf("ThreadRPCServer ReadHTTP timeout\n");
2479 // Check authorization
2480 if (mapHeaders.count("authorization") == 0)
2482 stream << HTTPReply(401, "") << std::flush;
2485 if (!HTTPAuthorized(mapHeaders))
2487 printf("ThreadRPCServer incorrect password attempt from %s\n",peer.address().to_string().c_str());
2488 /* Deter brute-forcing short passwords.
2489 If this results in a DOS the user really
2490 shouldn't have their RPC port exposed.*/
2491 if (mapArgs["-rpcpassword"].size() < 20)
2494 stream << HTTPReply(401, "") << std::flush;
2498 Value id = Value::null;
2503 if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
2504 throw JSONRPCError(-32700, "Parse error");
2505 const Object& request = valRequest.get_obj();
2507 // Parse id now so errors from here on will have the id
2508 id = find_value(request, "id");
2511 Value valMethod = find_value(request, "method");
2512 if (valMethod.type() == null_type)
2513 throw JSONRPCError(-32600, "Missing method");
2514 if (valMethod.type() != str_type)
2515 throw JSONRPCError(-32600, "Method must be a string");
2516 string strMethod = valMethod.get_str();
2517 if (strMethod != "getwork" && strMethod != "getmemorypool")
2518 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
2521 Value valParams = find_value(request, "params");
2523 if (valParams.type() == array_type)
2524 params = valParams.get_array();
2525 else if (valParams.type() == null_type)
2528 throw JSONRPCError(-32600, "Params must be an array");
2531 const CRPCCommand *pcmd = tableRPC[strMethod];
2533 throw JSONRPCError(-32601, "Method not found");
2535 // Observe safe mode
2536 string strWarning = GetWarnings("rpc");
2537 if (strWarning != "" && !GetBoolArg("-disablesafemode") &&
2539 throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
2546 LOCK2(cs_main, pwalletMain->cs_wallet);
2547 result = pcmd->actor(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().string().c_str()));
2581 // Connect to localhost
2582 bool fUseSSL = GetBoolArg("-rpcssl");
2583 asio::io_service io_service;
2584 ssl::context context(io_service, ssl::context::sslv23);
2585 context.set_options(ssl::context::no_sslv2);
2586 SSLStream sslStream(io_service, context);
2587 SSLIOStreamDevice d(sslStream, fUseSSL);
2588 iostreams::stream<SSLIOStreamDevice> stream(d);
2589 if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332")))
2590 throw runtime_error("couldn't connect to server");
2592 // HTTP basic authentication
2593 string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
2594 map<string, string> mapRequestHeaders;
2595 mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
2598 string strRequest = JSONRPCRequest(strMethod, params, 1);
2599 string strPost = HTTPPost(strRequest, mapRequestHeaders);
2600 stream << strPost << std::flush;
2603 map<string, string> mapHeaders;
2605 int nStatus = ReadHTTP(stream, mapHeaders, strReply);
2607 throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
2608 else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
2609 throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
2610 else if (strReply.empty())
2611 throw runtime_error("no response from server");
2615 if (!read_string(strReply, valReply))
2616 throw runtime_error("couldn't parse reply from server");
2617 const Object& reply = valReply.get_obj();
2619 throw runtime_error("expected reply to have result, error and id properties");
2627 template<typename T>
2628 void ConvertTo(Value& value)
2630 if (value.type() == str_type)
2632 // reinterpret string as unquoted json value
2634 if (!read_string(value.get_str(), value2))
2635 throw runtime_error("type mismatch");
2636 value = value2.get_value<T>();
2640 value = value.get_value<T>();
2644 int CommandLineRPC(int argc, char *argv[])
2651 while (argc > 1 && IsSwitchChar(argv[1][0]))
2659 throw runtime_error("too few parameters");
2660 string strMethod = argv[1];
2662 // Parameters default to strings
2664 for (int i = 2; i < argc; i++)
2665 params.push_back(argv[i]);
2666 int n = params.size();
2669 // Special case non-string parameter types
2671 if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
2672 if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2673 if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
2674 if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]);
2675 if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2676 if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2677 if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2678 if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
2679 if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2680 if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
2681 if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2682 if (strMethod == "getblockhash" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2683 if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]);
2684 if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2685 if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]);
2686 if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2687 if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2688 if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2689 if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2690 if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2691 if (strMethod == "listsinceblock" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2692 if (strMethod == "sendmany" && n > 1)
2694 string s = params[1].get_str();
2696 if (!read_string(s, v) || v.type() != obj_type)
2697 throw runtime_error("type mismatch");
2698 params[1] = v.get_obj();
2700 if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2701 if (strMethod == "addmultisigaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2702 if (strMethod == "addmultisigaddress" && n > 1)
2704 string s = params[1].get_str();
2706 if (!read_string(s, v) || v.type() != array_type)
2707 throw runtime_error("type mismatch "+s);
2708 params[1] = v.get_array();
2712 Object reply = CallRPC(strMethod, params);
2715 const Value& result = find_value(reply, "result");
2716 const Value& error = find_value(reply, "error");
2718 if (error.type() != null_type)
2721 strPrint = "error: " + write_string(error, false);
2722 int code = find_value(error.get_obj(), "code").get_int();
2728 if (result.type() == null_type)
2730 else if (result.type() == str_type)
2731 strPrint = result.get_str();
2733 strPrint = write_string(result, true);
2736 catch (std::exception& e)
2738 strPrint = string("error: ") + e.what();
2743 PrintException(NULL, "CommandLineRPC()");
2748 fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
2757 int main(int argc, char *argv[])
2760 // Turn off microsoft heap dump noise
2761 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
2762 _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
2764 setbuf(stdin, NULL);
2765 setbuf(stdout, NULL);
2766 setbuf(stderr, NULL);
2770 if (argc >= 2 && string(argv[1]) == "-server")
2772 printf("server ready\n");
2773 ThreadRPCServer(NULL);
2777 return CommandLineRPC(argc, argv);
2780 catch (std::exception& e) {
2781 PrintException(&e, "main()");
2783 PrintException(NULL, "main()");