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"
13 #include "bitcoinrpc.h"
16 #include <boost/asio.hpp>
17 #include <boost/filesystem.hpp>
18 #include <boost/iostreams/concepts.hpp>
19 #include <boost/iostreams/stream.hpp>
20 #include <boost/algorithm/string.hpp>
21 #include <boost/lexical_cast.hpp>
22 #include <boost/asio/ssl.hpp>
23 #include <boost/filesystem/fstream.hpp>
24 typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> SSLStream;
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);
39 static std::string strRPCUserColonPass;
41 static int64 nWalletUnlockTime;
42 static CCriticalSection cs_nWalletUnlockTime;
44 extern Value dumpprivkey(const Array& params, bool fHelp);
45 extern Value importprivkey(const Array& params, bool fHelp);
47 Object JSONRPCError(int code, const string& message)
50 error.push_back(Pair("code", code));
51 error.push_back(Pair("message", message));
55 double GetDifficulty(const CBlockIndex* blockindex = NULL)
57 // Floating point number that is a multiple of the minimum difficulty,
58 // minimum difficulty = 1.0.
59 if (blockindex == NULL)
61 if (pindexBest == NULL)
64 blockindex = pindexBest;
67 int nShift = (blockindex->nBits >> 24) & 0xff;
70 (double)0x0000ffff / (double)(blockindex->nBits & 0x00ffffff);
87 int64 AmountFromValue(const Value& value)
89 double dAmount = value.get_real();
90 if (dAmount <= 0.0 || dAmount > 21000000.0)
91 throw JSONRPCError(-3, "Invalid amount");
92 int64 nAmount = roundint64(dAmount * COIN);
93 if (!MoneyRange(nAmount))
94 throw JSONRPCError(-3, "Invalid amount");
98 Value ValueFromAmount(int64 amount)
100 return (double)amount / (double)COIN;
104 HexBits(unsigned int nBits)
110 uBits.nBits = htonl((int32_t)nBits);
111 return HexStr(BEGIN(uBits.cBits), END(uBits.cBits));
114 void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
116 int confirms = wtx.GetDepthInMainChain();
117 entry.push_back(Pair("confirmations", confirms));
120 entry.push_back(Pair("blockhash", wtx.hashBlock.GetHex()));
121 entry.push_back(Pair("blockindex", wtx.nIndex));
123 entry.push_back(Pair("txid", wtx.GetHash().GetHex()));
124 entry.push_back(Pair("time", (boost::int64_t)wtx.GetTxTime()));
125 BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
126 entry.push_back(Pair(item.first, item.second));
129 string AccountFromValue(const Value& value)
131 string strAccount = value.get_str();
132 if (strAccount == "*")
133 throw JSONRPCError(-11, "Invalid account name");
137 Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex)
140 result.push_back(Pair("hash", block.GetHash().GetHex()));
141 result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION)));
142 result.push_back(Pair("height", blockindex->nHeight));
143 result.push_back(Pair("version", block.nVersion));
144 result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex()));
145 result.push_back(Pair("time", (boost::int64_t)block.GetBlockTime()));
146 result.push_back(Pair("nonce", (boost::uint64_t)block.nNonce));
147 result.push_back(Pair("bits", HexBits(block.nBits)));
148 result.push_back(Pair("difficulty", GetDifficulty(blockindex)));
150 BOOST_FOREACH (const CTransaction&tx, block.vtx)
151 txhashes.push_back(tx.GetHash().GetHex());
152 result.push_back(Pair("tx", txhashes));
154 if (blockindex->pprev)
155 result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex()));
156 if (blockindex->pnext)
157 result.push_back(Pair("nextblockhash", blockindex->pnext->GetBlockHash().GetHex()));
164 /// Note: This interface may still be subject to change.
167 string CRPCTable::help(string strCommand) const
170 set<rpcfn_type> setDone;
171 for (map<string, const CRPCCommand*>::const_iterator mi = mapCommands.begin(); mi != mapCommands.end(); ++mi)
173 const CRPCCommand *pcmd = mi->second;
174 string strMethod = mi->first;
175 // We already filter duplicates, but these deprecated screw up the sort order
176 if (strMethod == "getamountreceived" ||
177 strMethod == "getallreceived" ||
178 strMethod == "getblocknumber" || // deprecated
179 (strMethod.find("label") != string::npos))
181 if (strCommand != "" && strMethod != strCommand)
186 rpcfn_type pfn = pcmd->actor;
187 if (setDone.insert(pfn).second)
188 (*pfn)(params, true);
190 catch (std::exception& e)
192 // Help text is returned in an exception
193 string strHelp = string(e.what());
194 if (strCommand == "")
195 if (strHelp.find('\n') != string::npos)
196 strHelp = strHelp.substr(0, strHelp.find('\n'));
197 strRet += strHelp + "\n";
201 strRet = strprintf("help: unknown command: %s\n", strCommand.c_str());
202 strRet = strRet.substr(0,strRet.size()-1);
206 Value help(const Array& params, bool fHelp)
208 if (fHelp || params.size() > 1)
211 "List commands, or get help for a command.");
214 if (params.size() > 0)
215 strCommand = params[0].get_str();
217 return tableRPC.help(strCommand);
221 Value stop(const Array& params, bool fHelp)
223 if (fHelp || params.size() != 0)
226 "Stop bitcoin server.");
227 // Shutdown will take long enough that the response should get back
229 return "bitcoin server stopping";
233 Value getblockcount(const Array& params, bool fHelp)
235 if (fHelp || params.size() != 0)
238 "Returns the number of blocks in the longest block chain.");
245 Value getblocknumber(const Array& params, bool fHelp)
247 if (fHelp || params.size() != 0)
250 "Deprecated. Use getblockcount.");
256 Value getconnectioncount(const Array& params, bool fHelp)
258 if (fHelp || params.size() != 0)
260 "getconnectioncount\n"
261 "Returns the number of connections to other nodes.");
263 return (int)vNodes.size();
267 Value getdifficulty(const Array& params, bool fHelp)
269 if (fHelp || params.size() != 0)
272 "Returns the proof-of-work difficulty as a multiple of the minimum difficulty.");
274 return GetDifficulty();
278 Value getgenerate(const Array& params, bool fHelp)
280 if (fHelp || params.size() != 0)
283 "Returns true or false.");
285 return GetBoolArg("-gen");
289 Value setgenerate(const Array& params, bool fHelp)
291 if (fHelp || params.size() < 1 || params.size() > 2)
293 "setgenerate <generate> [genproclimit]\n"
294 "<generate> is true or false to turn generation on or off.\n"
295 "Generation is limited to [genproclimit] processors, -1 is unlimited.");
297 bool fGenerate = true;
298 if (params.size() > 0)
299 fGenerate = params[0].get_bool();
301 if (params.size() > 1)
303 int nGenProcLimit = params[1].get_int();
304 mapArgs["-genproclimit"] = itostr(nGenProcLimit);
305 if (nGenProcLimit == 0)
308 mapArgs["-gen"] = (fGenerate ? "1" : "0");
310 GenerateBitcoins(fGenerate, pwalletMain);
315 Value gethashespersec(const Array& params, bool fHelp)
317 if (fHelp || params.size() != 0)
320 "Returns a recent hashes per second performance measurement while generating.");
322 if (GetTimeMillis() - nHPSTimerStart > 8000)
323 return (boost::int64_t)0;
324 return (boost::int64_t)dHashesPerSec;
328 Value getinfo(const Array& params, bool fHelp)
330 if (fHelp || params.size() != 0)
333 "Returns an object containing various state info.");
336 obj.push_back(Pair("version", (int)CLIENT_VERSION));
337 obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION));
338 obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
339 obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
340 obj.push_back(Pair("blocks", (int)nBestHeight));
341 obj.push_back(Pair("connections", (int)vNodes.size()));
342 obj.push_back(Pair("proxy", (fUseProxy ? addrProxy.ToStringIPPort() : string())));
343 obj.push_back(Pair("difficulty", (double)GetDifficulty()));
344 obj.push_back(Pair("testnet", fTestNet));
345 obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));
346 obj.push_back(Pair("keypoolsize", pwalletMain->GetKeyPoolSize()));
347 obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee)));
348 if (pwalletMain->IsCrypted())
349 obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime / 1000));
350 obj.push_back(Pair("errors", GetWarnings("statusbar")));
355 Value getmininginfo(const Array& params, bool fHelp)
357 if (fHelp || params.size() != 0)
360 "Returns an object containing mining-related information.");
363 obj.push_back(Pair("blocks", (int)nBestHeight));
364 obj.push_back(Pair("currentblocksize",(uint64_t)nLastBlockSize));
365 obj.push_back(Pair("currentblocktx",(uint64_t)nLastBlockTx));
366 obj.push_back(Pair("difficulty", (double)GetDifficulty()));
367 obj.push_back(Pair("errors", GetWarnings("statusbar")));
368 obj.push_back(Pair("generate", GetBoolArg("-gen")));
369 obj.push_back(Pair("genproclimit", (int)GetArg("-genproclimit", -1)));
370 obj.push_back(Pair("hashespersec", gethashespersec(params, false)));
371 obj.push_back(Pair("pooledtx", (uint64_t)mempool.size()));
372 obj.push_back(Pair("testnet", fTestNet));
377 Value getnewaddress(const Array& params, bool fHelp)
379 if (fHelp || params.size() > 1)
381 "getnewaddress [account]\n"
382 "Returns a new bitcoin address for receiving payments. "
383 "If [account] is specified (recommended), it is added to the address book "
384 "so payments received with the address will be credited to [account].");
386 // Parse the account first so we don't generate a key if there's an error
388 if (params.size() > 0)
389 strAccount = AccountFromValue(params[0]);
391 if (!pwalletMain->IsLocked())
392 pwalletMain->TopUpKeyPool();
394 // Generate a new key that is added to wallet
395 std::vector<unsigned char> newKey;
396 if (!pwalletMain->GetKeyFromPool(newKey, false))
397 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
398 CBitcoinAddress address(newKey);
400 pwalletMain->SetAddressBookName(address, strAccount);
402 return address.ToString();
406 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
408 CWalletDB walletdb(pwalletMain->strWalletFile);
411 walletdb.ReadAccount(strAccount, account);
413 bool bKeyUsed = false;
415 // Check if the current key has been used
416 if (!account.vchPubKey.empty())
418 CScript scriptPubKey;
419 scriptPubKey.SetBitcoinAddress(account.vchPubKey);
420 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
421 it != pwalletMain->mapWallet.end() && !account.vchPubKey.empty();
424 const CWalletTx& wtx = (*it).second;
425 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
426 if (txout.scriptPubKey == scriptPubKey)
431 // Generate a new key
432 if (account.vchPubKey.empty() || bForceNew || bKeyUsed)
434 if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false))
435 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
437 pwalletMain->SetAddressBookName(CBitcoinAddress(account.vchPubKey), strAccount);
438 walletdb.WriteAccount(strAccount, account);
441 return CBitcoinAddress(account.vchPubKey);
444 Value getaccountaddress(const Array& params, bool fHelp)
446 if (fHelp || params.size() != 1)
448 "getaccountaddress <account>\n"
449 "Returns the current bitcoin address for receiving payments to this account.");
451 // Parse the account first so we don't generate a key if there's an error
452 string strAccount = AccountFromValue(params[0]);
456 ret = GetAccountAddress(strAccount).ToString();
463 Value setaccount(const Array& params, bool fHelp)
465 if (fHelp || params.size() < 1 || params.size() > 2)
467 "setaccount <bitcoinaddress> <account>\n"
468 "Sets the account associated with the given address.");
470 CBitcoinAddress address(params[0].get_str());
471 if (!address.IsValid())
472 throw JSONRPCError(-5, "Invalid bitcoin address");
476 if (params.size() > 1)
477 strAccount = AccountFromValue(params[1]);
479 // Detect when changing the account of an address that is the 'unused current key' of another account:
480 if (pwalletMain->mapAddressBook.count(address))
482 string strOldAccount = pwalletMain->mapAddressBook[address];
483 if (address == GetAccountAddress(strOldAccount))
484 GetAccountAddress(strOldAccount, true);
487 pwalletMain->SetAddressBookName(address, strAccount);
493 Value getaccount(const Array& params, bool fHelp)
495 if (fHelp || params.size() != 1)
497 "getaccount <bitcoinaddress>\n"
498 "Returns the account associated with the given address.");
500 CBitcoinAddress address(params[0].get_str());
501 if (!address.IsValid())
502 throw JSONRPCError(-5, "Invalid bitcoin address");
505 map<CBitcoinAddress, string>::iterator mi = pwalletMain->mapAddressBook.find(address);
506 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
507 strAccount = (*mi).second;
512 Value getaddressesbyaccount(const Array& params, bool fHelp)
514 if (fHelp || params.size() != 1)
516 "getaddressesbyaccount <account>\n"
517 "Returns the list of addresses for the given account.");
519 string strAccount = AccountFromValue(params[0]);
521 // Find all addresses that have the given account
523 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
525 const CBitcoinAddress& address = item.first;
526 const string& strName = item.second;
527 if (strName == strAccount)
528 ret.push_back(address.ToString());
533 Value settxfee(const Array& params, bool fHelp)
535 if (fHelp || params.size() < 1 || params.size() > 1)
537 "settxfee <amount>\n"
538 "<amount> is a real and is rounded to the nearest 0.00000001");
542 if (params[0].get_real() != 0.0)
543 nAmount = AmountFromValue(params[0]); // rejects 0.0 amounts
545 nTransactionFee = nAmount;
549 Value sendtoaddress(const Array& params, bool fHelp)
551 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
553 "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
554 "<amount> is a real and is rounded to the nearest 0.00000001\n"
555 "requires wallet passphrase to be set with walletpassphrase first");
556 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
558 "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
559 "<amount> is a real and is rounded to the nearest 0.00000001");
561 CBitcoinAddress address(params[0].get_str());
562 if (!address.IsValid())
563 throw JSONRPCError(-5, "Invalid bitcoin address");
566 int64 nAmount = AmountFromValue(params[1]);
570 if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
571 wtx.mapValue["comment"] = params[2].get_str();
572 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
573 wtx.mapValue["to"] = params[3].get_str();
575 if (pwalletMain->IsLocked())
576 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
578 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
580 throw JSONRPCError(-4, strError);
582 return wtx.GetHash().GetHex();
585 Value signmessage(const Array& params, bool fHelp)
587 if (fHelp || params.size() != 2)
589 "signmessage <bitcoinaddress> <message>\n"
590 "Sign a message with the private key of an address");
592 if (pwalletMain->IsLocked())
593 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
595 string strAddress = params[0].get_str();
596 string strMessage = params[1].get_str();
598 CBitcoinAddress addr(strAddress);
600 throw JSONRPCError(-3, "Invalid address");
603 if (!pwalletMain->GetKey(addr, key))
604 throw JSONRPCError(-4, "Private key not available");
606 CDataStream ss(SER_GETHASH, 0);
607 ss << strMessageMagic;
610 vector<unsigned char> vchSig;
611 if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig))
612 throw JSONRPCError(-5, "Sign failed");
614 return EncodeBase64(&vchSig[0], vchSig.size());
617 Value verifymessage(const Array& params, bool fHelp)
619 if (fHelp || params.size() != 3)
621 "verifymessage <bitcoinaddress> <signature> <message>\n"
622 "Verify a signed message");
624 string strAddress = params[0].get_str();
625 string strSign = params[1].get_str();
626 string strMessage = params[2].get_str();
628 CBitcoinAddress addr(strAddress);
630 throw JSONRPCError(-3, "Invalid address");
632 bool fInvalid = false;
633 vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
636 throw JSONRPCError(-5, "Malformed base64 encoding");
638 CDataStream ss(SER_GETHASH, 0);
639 ss << strMessageMagic;
643 if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
646 return (CBitcoinAddress(key.GetPubKey()) == addr);
650 Value getreceivedbyaddress(const Array& params, bool fHelp)
652 if (fHelp || params.size() < 1 || params.size() > 2)
654 "getreceivedbyaddress <bitcoinaddress> [minconf=1]\n"
655 "Returns the total amount received by <bitcoinaddress> in transactions with at least [minconf] confirmations.");
658 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
659 CScript scriptPubKey;
660 if (!address.IsValid())
661 throw JSONRPCError(-5, "Invalid bitcoin address");
662 scriptPubKey.SetBitcoinAddress(address);
663 if (!IsMine(*pwalletMain,scriptPubKey))
666 // Minimum confirmations
668 if (params.size() > 1)
669 nMinDepth = params[1].get_int();
673 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
675 const CWalletTx& wtx = (*it).second;
676 if (wtx.IsCoinBase() || !wtx.IsFinal())
679 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
680 if (txout.scriptPubKey == scriptPubKey)
681 if (wtx.GetDepthInMainChain() >= nMinDepth)
682 nAmount += txout.nValue;
685 return ValueFromAmount(nAmount);
689 void GetAccountAddresses(string strAccount, set<CBitcoinAddress>& setAddress)
691 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
693 const CBitcoinAddress& address = item.first;
694 const string& strName = item.second;
695 if (strName == strAccount)
696 setAddress.insert(address);
701 Value getreceivedbyaccount(const Array& params, bool fHelp)
703 if (fHelp || params.size() < 1 || params.size() > 2)
705 "getreceivedbyaccount <account> [minconf=1]\n"
706 "Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.");
708 // Minimum confirmations
710 if (params.size() > 1)
711 nMinDepth = params[1].get_int();
713 // Get the set of pub keys assigned to account
714 string strAccount = AccountFromValue(params[0]);
715 set<CBitcoinAddress> setAddress;
716 GetAccountAddresses(strAccount, setAddress);
720 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
722 const CWalletTx& wtx = (*it).second;
723 if (wtx.IsCoinBase() || !wtx.IsFinal())
726 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
728 CBitcoinAddress address;
729 if (ExtractAddress(txout.scriptPubKey, address) && pwalletMain->HaveKey(address) && setAddress.count(address))
730 if (wtx.GetDepthInMainChain() >= nMinDepth)
731 nAmount += txout.nValue;
735 return (double)nAmount / (double)COIN;
739 int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth)
743 // Tally wallet transactions
744 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
746 const CWalletTx& wtx = (*it).second;
750 int64 nGenerated, nReceived, nSent, nFee;
751 wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee);
753 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
754 nBalance += nReceived;
755 nBalance += nGenerated - nSent - nFee;
758 // Tally internal accounting entries
759 nBalance += walletdb.GetAccountCreditDebit(strAccount);
764 int64 GetAccountBalance(const string& strAccount, int nMinDepth)
766 CWalletDB walletdb(pwalletMain->strWalletFile);
767 return GetAccountBalance(walletdb, strAccount, nMinDepth);
771 Value getbalance(const Array& params, bool fHelp)
773 if (fHelp || params.size() > 2)
775 "getbalance [account] [minconf=1]\n"
776 "If [account] is not specified, returns the server's total available balance.\n"
777 "If [account] is specified, returns the balance in the account.");
779 if (params.size() == 0)
780 return ValueFromAmount(pwalletMain->GetBalance());
783 if (params.size() > 1)
784 nMinDepth = params[1].get_int();
786 if (params[0].get_str() == "*") {
787 // Calculate total balance a different way from GetBalance()
788 // (GetBalance() sums up all unspent TxOuts)
789 // getbalance and getbalance '*' should always return the same number.
791 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
793 const CWalletTx& wtx = (*it).second;
797 int64 allGeneratedImmature, allGeneratedMature, allFee;
798 allGeneratedImmature = allGeneratedMature = allFee = 0;
799 string strSentAccount;
800 list<pair<CBitcoinAddress, int64> > listReceived;
801 list<pair<CBitcoinAddress, int64> > listSent;
802 wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
803 if (wtx.GetDepthInMainChain() >= nMinDepth)
805 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listReceived)
806 nBalance += r.second;
808 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listSent)
809 nBalance -= r.second;
811 nBalance += allGeneratedMature;
813 return ValueFromAmount(nBalance);
816 string strAccount = AccountFromValue(params[0]);
818 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
820 return ValueFromAmount(nBalance);
824 Value movecmd(const Array& params, bool fHelp)
826 if (fHelp || params.size() < 3 || params.size() > 5)
828 "move <fromaccount> <toaccount> <amount> [minconf=1] [comment]\n"
829 "Move from one account in your wallet to another.");
831 string strFrom = AccountFromValue(params[0]);
832 string strTo = AccountFromValue(params[1]);
833 int64 nAmount = AmountFromValue(params[2]);
834 if (params.size() > 3)
835 // unused parameter, used to be nMinDepth, keep type-checking it though
836 (void)params[3].get_int();
838 if (params.size() > 4)
839 strComment = params[4].get_str();
841 CWalletDB walletdb(pwalletMain->strWalletFile);
844 int64 nNow = GetAdjustedTime();
847 CAccountingEntry debit;
848 debit.strAccount = strFrom;
849 debit.nCreditDebit = -nAmount;
851 debit.strOtherAccount = strTo;
852 debit.strComment = strComment;
853 walletdb.WriteAccountingEntry(debit);
856 CAccountingEntry credit;
857 credit.strAccount = strTo;
858 credit.nCreditDebit = nAmount;
860 credit.strOtherAccount = strFrom;
861 credit.strComment = strComment;
862 walletdb.WriteAccountingEntry(credit);
864 walletdb.TxnCommit();
870 Value sendfrom(const Array& params, bool fHelp)
872 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
874 "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
875 "<amount> is a real and is rounded to the nearest 0.00000001\n"
876 "requires wallet passphrase to be set with walletpassphrase first");
877 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
879 "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
880 "<amount> is a real and is rounded to the nearest 0.00000001");
882 string strAccount = AccountFromValue(params[0]);
883 CBitcoinAddress address(params[1].get_str());
884 if (!address.IsValid())
885 throw JSONRPCError(-5, "Invalid bitcoin address");
886 int64 nAmount = AmountFromValue(params[2]);
888 if (params.size() > 3)
889 nMinDepth = params[3].get_int();
892 wtx.strFromAccount = strAccount;
893 if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
894 wtx.mapValue["comment"] = params[4].get_str();
895 if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
896 wtx.mapValue["to"] = params[5].get_str();
898 if (pwalletMain->IsLocked())
899 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
902 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
903 if (nAmount > nBalance)
904 throw JSONRPCError(-6, "Account has insufficient funds");
907 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
909 throw JSONRPCError(-4, strError);
911 return wtx.GetHash().GetHex();
915 Value sendmany(const Array& params, bool fHelp)
917 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
919 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
920 "amounts are double-precision floating point numbers\n"
921 "requires wallet passphrase to be set with walletpassphrase first");
922 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
924 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
925 "amounts are double-precision floating point numbers");
927 string strAccount = AccountFromValue(params[0]);
928 Object sendTo = params[1].get_obj();
930 if (params.size() > 2)
931 nMinDepth = params[2].get_int();
934 wtx.strFromAccount = strAccount;
935 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
936 wtx.mapValue["comment"] = params[3].get_str();
938 set<CBitcoinAddress> setAddress;
939 vector<pair<CScript, int64> > vecSend;
941 int64 totalAmount = 0;
942 BOOST_FOREACH(const Pair& s, sendTo)
944 CBitcoinAddress address(s.name_);
945 if (!address.IsValid())
946 throw JSONRPCError(-5, string("Invalid bitcoin address:")+s.name_);
948 if (setAddress.count(address))
949 throw JSONRPCError(-8, string("Invalid parameter, duplicated address: ")+s.name_);
950 setAddress.insert(address);
952 CScript scriptPubKey;
953 scriptPubKey.SetBitcoinAddress(address);
954 int64 nAmount = AmountFromValue(s.value_);
955 totalAmount += nAmount;
957 vecSend.push_back(make_pair(scriptPubKey, nAmount));
960 if (pwalletMain->IsLocked())
961 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
964 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
965 if (totalAmount > nBalance)
966 throw JSONRPCError(-6, "Account has insufficient funds");
969 CReserveKey keyChange(pwalletMain);
970 int64 nFeeRequired = 0;
971 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
974 if (totalAmount + nFeeRequired > pwalletMain->GetBalance())
975 throw JSONRPCError(-6, "Insufficient funds");
976 throw JSONRPCError(-4, "Transaction creation failed");
978 if (!pwalletMain->CommitTransaction(wtx, keyChange))
979 throw JSONRPCError(-4, "Transaction commit failed");
981 return wtx.GetHash().GetHex();
984 Value addmultisigaddress(const Array& params, bool fHelp)
986 if (fHelp || params.size() < 2 || params.size() > 3)
988 string msg = "addmultisigaddress <nrequired> <'[\"key\",\"key\"]'> [account]\n"
989 "Add a nrequired-to-sign multisignature address to the wallet\"\n"
990 "each key is a bitcoin address or hex-encoded public key\n"
991 "If [account] is specified, assign address to [account].";
992 throw runtime_error(msg);
995 int nRequired = params[0].get_int();
996 const Array& keys = params[1].get_array();
998 if (params.size() > 2)
999 strAccount = AccountFromValue(params[2]);
1001 // Gather public keys
1002 if ((nRequired < 1) || ((int)keys.size() < nRequired))
1003 throw runtime_error(
1004 strprintf("wrong number of keys"
1005 "(got %d, need at least %d)", keys.size(), nRequired));
1006 std::vector<CKey> pubkeys;
1007 pubkeys.resize(keys.size());
1008 for (unsigned int i = 0; i < keys.size(); i++)
1010 const std::string& ks = keys[i].get_str();
1012 // Case 1: bitcoin address and we have full public key:
1013 CBitcoinAddress address(ks);
1014 if (address.IsValid())
1016 if (address.IsScript())
1017 throw runtime_error(
1018 strprintf("%s is a pay-to-script address",ks.c_str()));
1019 std::vector<unsigned char> vchPubKey;
1020 if (!pwalletMain->GetPubKey(address, vchPubKey))
1021 throw runtime_error(
1022 strprintf("no full public key for address %s",ks.c_str()));
1023 if (vchPubKey.empty() || !pubkeys[i].SetPubKey(vchPubKey))
1024 throw runtime_error(" Invalid public key: "+ks);
1027 // Case 2: hex public key
1030 vector<unsigned char> vchPubKey = ParseHex(ks);
1031 if (vchPubKey.empty() || !pubkeys[i].SetPubKey(vchPubKey))
1032 throw runtime_error(" Invalid public key: "+ks);
1036 throw runtime_error(" Invalid public key: "+ks);
1040 // Construct using pay-to-script-hash:
1042 inner.SetMultisig(nRequired, pubkeys);
1044 uint160 scriptHash = Hash160(inner);
1045 CScript scriptPubKey;
1046 scriptPubKey.SetPayToScriptHash(inner);
1047 pwalletMain->AddCScript(inner);
1048 CBitcoinAddress address;
1049 address.SetScriptHash160(scriptHash);
1051 pwalletMain->SetAddressBookName(address, strAccount);
1052 return address.ToString();
1063 nConf = std::numeric_limits<int>::max();
1067 Value ListReceived(const Array& params, bool fByAccounts)
1069 // Minimum confirmations
1071 if (params.size() > 0)
1072 nMinDepth = params[0].get_int();
1074 // Whether to include empty accounts
1075 bool fIncludeEmpty = false;
1076 if (params.size() > 1)
1077 fIncludeEmpty = params[1].get_bool();
1080 map<CBitcoinAddress, tallyitem> mapTally;
1081 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1083 const CWalletTx& wtx = (*it).second;
1085 if (wtx.IsCoinBase() || !wtx.IsFinal())
1088 int nDepth = wtx.GetDepthInMainChain();
1089 if (nDepth < nMinDepth)
1092 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
1094 CBitcoinAddress address;
1095 if (!ExtractAddress(txout.scriptPubKey, address) || !pwalletMain->HaveKey(address) || !address.IsValid())
1098 tallyitem& item = mapTally[address];
1099 item.nAmount += txout.nValue;
1100 item.nConf = min(item.nConf, nDepth);
1106 map<string, tallyitem> mapAccountTally;
1107 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
1109 const CBitcoinAddress& address = item.first;
1110 const string& strAccount = item.second;
1111 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
1112 if (it == mapTally.end() && !fIncludeEmpty)
1116 int nConf = std::numeric_limits<int>::max();
1117 if (it != mapTally.end())
1119 nAmount = (*it).second.nAmount;
1120 nConf = (*it).second.nConf;
1125 tallyitem& item = mapAccountTally[strAccount];
1126 item.nAmount += nAmount;
1127 item.nConf = min(item.nConf, nConf);
1132 obj.push_back(Pair("address", address.ToString()));
1133 obj.push_back(Pair("account", strAccount));
1134 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1135 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1142 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
1144 int64 nAmount = (*it).second.nAmount;
1145 int nConf = (*it).second.nConf;
1147 obj.push_back(Pair("account", (*it).first));
1148 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1149 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1157 Value listreceivedbyaddress(const Array& params, bool fHelp)
1159 if (fHelp || params.size() > 2)
1160 throw runtime_error(
1161 "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
1162 "[minconf] is the minimum number of confirmations before payments are included.\n"
1163 "[includeempty] whether to include addresses that haven't received any payments.\n"
1164 "Returns an array of objects containing:\n"
1165 " \"address\" : receiving address\n"
1166 " \"account\" : the account of the receiving address\n"
1167 " \"amount\" : total amount received by the address\n"
1168 " \"confirmations\" : number of confirmations of the most recent transaction included");
1170 return ListReceived(params, false);
1173 Value listreceivedbyaccount(const Array& params, bool fHelp)
1175 if (fHelp || params.size() > 2)
1176 throw runtime_error(
1177 "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
1178 "[minconf] is the minimum number of confirmations before payments are included.\n"
1179 "[includeempty] whether to include accounts that haven't received any payments.\n"
1180 "Returns an array of objects containing:\n"
1181 " \"account\" : the account of the receiving addresses\n"
1182 " \"amount\" : total amount received by addresses with this account\n"
1183 " \"confirmations\" : number of confirmations of the most recent transaction included");
1185 return ListReceived(params, true);
1188 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret)
1190 int64 nGeneratedImmature, nGeneratedMature, nFee;
1191 string strSentAccount;
1192 list<pair<CBitcoinAddress, int64> > listReceived;
1193 list<pair<CBitcoinAddress, int64> > listSent;
1195 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1197 bool fAllAccounts = (strAccount == string("*"));
1199 // Generated blocks assigned to account ""
1200 if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == ""))
1203 entry.push_back(Pair("account", string("")));
1204 if (nGeneratedImmature)
1206 entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
1207 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
1211 entry.push_back(Pair("category", "generate"));
1212 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
1215 WalletTxToJSON(wtx, entry);
1216 ret.push_back(entry);
1220 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1222 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1225 entry.push_back(Pair("account", strSentAccount));
1226 entry.push_back(Pair("address", s.first.ToString()));
1227 entry.push_back(Pair("category", "send"));
1228 entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1229 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1231 WalletTxToJSON(wtx, entry);
1232 ret.push_back(entry);
1237 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1239 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1242 if (pwalletMain->mapAddressBook.count(r.first))
1243 account = pwalletMain->mapAddressBook[r.first];
1244 if (fAllAccounts || (account == strAccount))
1247 entry.push_back(Pair("account", account));
1248 entry.push_back(Pair("address", r.first.ToString()));
1249 entry.push_back(Pair("category", "receive"));
1250 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1252 WalletTxToJSON(wtx, entry);
1253 ret.push_back(entry);
1259 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1261 bool fAllAccounts = (strAccount == string("*"));
1263 if (fAllAccounts || acentry.strAccount == strAccount)
1266 entry.push_back(Pair("account", acentry.strAccount));
1267 entry.push_back(Pair("category", "move"));
1268 entry.push_back(Pair("time", (boost::int64_t)acentry.nTime));
1269 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1270 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1271 entry.push_back(Pair("comment", acentry.strComment));
1272 ret.push_back(entry);
1276 Value listtransactions(const Array& params, bool fHelp)
1278 if (fHelp || params.size() > 3)
1279 throw runtime_error(
1280 "listtransactions [account] [count=10] [from=0]\n"
1281 "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1283 string strAccount = "*";
1284 if (params.size() > 0)
1285 strAccount = params[0].get_str();
1287 if (params.size() > 1)
1288 nCount = params[1].get_int();
1290 if (params.size() > 2)
1291 nFrom = params[2].get_int();
1294 throw JSONRPCError(-8, "Negative count");
1296 throw JSONRPCError(-8, "Negative from");
1299 CWalletDB walletdb(pwalletMain->strWalletFile);
1301 // First: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap.
1302 typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
1303 typedef multimap<int64, TxPair > TxItems;
1306 // Note: maintaining indices in the database of (account,time) --> txid and (account, time) --> acentry
1307 // would make this much faster for applications that do this a lot.
1308 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1310 CWalletTx* wtx = &((*it).second);
1311 txByTime.insert(make_pair(wtx->GetTxTime(), TxPair(wtx, (CAccountingEntry*)0)));
1313 list<CAccountingEntry> acentries;
1314 walletdb.ListAccountCreditDebit(strAccount, acentries);
1315 BOOST_FOREACH(CAccountingEntry& entry, acentries)
1317 txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
1320 // iterate backwards until we have nCount items to return:
1321 for (TxItems::reverse_iterator it = txByTime.rbegin(); it != txByTime.rend(); ++it)
1323 CWalletTx *const pwtx = (*it).second.first;
1325 ListTransactions(*pwtx, strAccount, 0, true, ret);
1326 CAccountingEntry *const pacentry = (*it).second.second;
1328 AcentryToJSON(*pacentry, strAccount, ret);
1330 if (ret.size() >= (nCount+nFrom)) break;
1332 // ret is newest to oldest
1334 if (nFrom > (int)ret.size())
1336 if ((nFrom + nCount) > (int)ret.size())
1337 nCount = ret.size() - nFrom;
1338 Array::iterator first = ret.begin();
1339 std::advance(first, nFrom);
1340 Array::iterator last = ret.begin();
1341 std::advance(last, nFrom+nCount);
1343 if (last != ret.end()) ret.erase(last, ret.end());
1344 if (first != ret.begin()) ret.erase(ret.begin(), first);
1346 std::reverse(ret.begin(), ret.end()); // Return oldest to newest
1351 Value listaccounts(const Array& params, bool fHelp)
1353 if (fHelp || params.size() > 1)
1354 throw runtime_error(
1355 "listaccounts [minconf=1]\n"
1356 "Returns Object that has account names as keys, account balances as values.");
1359 if (params.size() > 0)
1360 nMinDepth = params[0].get_int();
1362 map<string, int64> mapAccountBalances;
1363 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& entry, pwalletMain->mapAddressBook) {
1364 if (pwalletMain->HaveKey(entry.first)) // This address belongs to me
1365 mapAccountBalances[entry.second] = 0;
1368 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1370 const CWalletTx& wtx = (*it).second;
1371 int64 nGeneratedImmature, nGeneratedMature, nFee;
1372 string strSentAccount;
1373 list<pair<CBitcoinAddress, int64> > listReceived;
1374 list<pair<CBitcoinAddress, int64> > listSent;
1375 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1376 mapAccountBalances[strSentAccount] -= nFee;
1377 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1378 mapAccountBalances[strSentAccount] -= s.second;
1379 if (wtx.GetDepthInMainChain() >= nMinDepth)
1381 mapAccountBalances[""] += nGeneratedMature;
1382 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1383 if (pwalletMain->mapAddressBook.count(r.first))
1384 mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1386 mapAccountBalances[""] += r.second;
1390 list<CAccountingEntry> acentries;
1391 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1392 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1393 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1396 BOOST_FOREACH(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) {
1397 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1402 Value listsinceblock(const Array& params, bool fHelp)
1405 throw runtime_error(
1406 "listsinceblock [blockhash] [target-confirmations]\n"
1407 "Get all transactions in blocks since block [blockhash], or all transactions if omitted");
1409 CBlockIndex *pindex = NULL;
1410 int target_confirms = 1;
1412 if (params.size() > 0)
1414 uint256 blockId = 0;
1416 blockId.SetHex(params[0].get_str());
1417 pindex = CBlockLocator(blockId).GetBlockIndex();
1420 if (params.size() > 1)
1422 target_confirms = params[1].get_int();
1424 if (target_confirms < 1)
1425 throw JSONRPCError(-8, "Invalid parameter");
1428 int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1;
1432 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1434 CWalletTx tx = (*it).second;
1436 if (depth == -1 || tx.GetDepthInMainChain() < depth)
1437 ListTransactions(tx, "*", 0, true, transactions);
1442 if (target_confirms == 1)
1445 lastblock = hashBestChain;
1449 int target_height = pindexBest->nHeight + 1 - target_confirms;
1452 for (block = pindexBest;
1453 block && block->nHeight > target_height;
1454 block = block->pprev) { }
1456 lastblock = block ? block->GetBlockHash() : 0;
1460 ret.push_back(Pair("transactions", transactions));
1461 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1466 Value gettransaction(const Array& params, bool fHelp)
1468 if (fHelp || params.size() != 1)
1469 throw runtime_error(
1470 "gettransaction <txid>\n"
1471 "Get detailed information about <txid>");
1474 hash.SetHex(params[0].get_str());
1478 if (!pwalletMain->mapWallet.count(hash))
1479 throw JSONRPCError(-5, "Invalid or non-wallet transaction id");
1480 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1482 int64 nCredit = wtx.GetCredit();
1483 int64 nDebit = wtx.GetDebit();
1484 int64 nNet = nCredit - nDebit;
1485 int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
1487 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1489 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1491 WalletTxToJSON(pwalletMain->mapWallet[hash], entry);
1494 ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
1495 entry.push_back(Pair("details", details));
1501 Value backupwallet(const Array& params, bool fHelp)
1503 if (fHelp || params.size() != 1)
1504 throw runtime_error(
1505 "backupwallet <destination>\n"
1506 "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1508 string strDest = params[0].get_str();
1509 BackupWallet(*pwalletMain, strDest);
1515 Value keypoolrefill(const Array& params, bool fHelp)
1517 if (pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1518 throw runtime_error(
1520 "Fills the keypool, requires wallet passphrase to be set.");
1521 if (!pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1522 throw runtime_error(
1524 "Fills the keypool.");
1526 if (pwalletMain->IsLocked())
1527 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
1529 pwalletMain->TopUpKeyPool();
1531 if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100))
1532 throw JSONRPCError(-4, "Error refreshing keypool.");
1538 void ThreadTopUpKeyPool(void* parg)
1540 pwalletMain->TopUpKeyPool();
1543 void ThreadCleanWalletPassphrase(void* parg)
1545 int64 nMyWakeTime = GetTimeMillis() + *((int64*)parg) * 1000;
1547 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1549 if (nWalletUnlockTime == 0)
1551 nWalletUnlockTime = nMyWakeTime;
1555 if (nWalletUnlockTime==0)
1557 int64 nToSleep = nWalletUnlockTime - GetTimeMillis();
1561 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1563 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1567 if (nWalletUnlockTime)
1569 nWalletUnlockTime = 0;
1570 pwalletMain->Lock();
1575 if (nWalletUnlockTime < nMyWakeTime)
1576 nWalletUnlockTime = nMyWakeTime;
1579 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1581 delete (int64*)parg;
1584 Value walletpassphrase(const Array& params, bool fHelp)
1586 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1587 throw runtime_error(
1588 "walletpassphrase <passphrase> <timeout>\n"
1589 "Stores the wallet decryption key in memory for <timeout> seconds.");
1592 if (!pwalletMain->IsCrypted())
1593 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1595 if (!pwalletMain->IsLocked())
1596 throw JSONRPCError(-17, "Error: Wallet is already unlocked.");
1598 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1599 SecureString strWalletPass;
1600 strWalletPass.reserve(100);
1601 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1602 // Alternately, find a way to make params[0] mlock()'d to begin with.
1603 strWalletPass = params[0].get_str().c_str();
1605 if (strWalletPass.length() > 0)
1607 if (!pwalletMain->Unlock(strWalletPass))
1608 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1611 throw runtime_error(
1612 "walletpassphrase <passphrase> <timeout>\n"
1613 "Stores the wallet decryption key in memory for <timeout> seconds.");
1615 CreateThread(ThreadTopUpKeyPool, NULL);
1616 int64* pnSleepTime = new int64(params[1].get_int64());
1617 CreateThread(ThreadCleanWalletPassphrase, pnSleepTime);
1623 Value walletpassphrasechange(const Array& params, bool fHelp)
1625 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1626 throw runtime_error(
1627 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1628 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1631 if (!pwalletMain->IsCrypted())
1632 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1634 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1635 // Alternately, find a way to make params[0] mlock()'d to begin with.
1636 SecureString strOldWalletPass;
1637 strOldWalletPass.reserve(100);
1638 strOldWalletPass = params[0].get_str().c_str();
1640 SecureString strNewWalletPass;
1641 strNewWalletPass.reserve(100);
1642 strNewWalletPass = params[1].get_str().c_str();
1644 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1645 throw runtime_error(
1646 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1647 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1649 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1650 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1656 Value walletlock(const Array& params, bool fHelp)
1658 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1659 throw runtime_error(
1661 "Removes the wallet encryption key from memory, locking the wallet.\n"
1662 "After calling this method, you will need to call walletpassphrase again\n"
1663 "before being able to call any methods which require the wallet to be unlocked.");
1666 if (!pwalletMain->IsCrypted())
1667 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called.");
1670 LOCK(cs_nWalletUnlockTime);
1671 pwalletMain->Lock();
1672 nWalletUnlockTime = 0;
1679 Value encryptwallet(const Array& params, bool fHelp)
1681 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1682 throw runtime_error(
1683 "encryptwallet <passphrase>\n"
1684 "Encrypts the wallet with <passphrase>.");
1687 if (pwalletMain->IsCrypted())
1688 throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
1690 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1691 // Alternately, find a way to make params[0] mlock()'d to begin with.
1692 SecureString strWalletPass;
1693 strWalletPass.reserve(100);
1694 strWalletPass = params[0].get_str().c_str();
1696 if (strWalletPass.length() < 1)
1697 throw runtime_error(
1698 "encryptwallet <passphrase>\n"
1699 "Encrypts the wallet with <passphrase>.");
1701 if (!pwalletMain->EncryptWallet(strWalletPass))
1702 throw JSONRPCError(-16, "Error: Failed to encrypt the wallet.");
1704 // BDB seems to have a bad habit of writing old data into
1705 // slack space in .dat files; that is bad if the old data is
1706 // unencrypted private keys. So:
1708 return "wallet encrypted; bitcoin server stopping, restart to run with encrypted wallet";
1712 Value validateaddress(const Array& params, bool fHelp)
1714 if (fHelp || params.size() != 1)
1715 throw runtime_error(
1716 "validateaddress <bitcoinaddress>\n"
1717 "Return information about <bitcoinaddress>.");
1719 CBitcoinAddress address(params[0].get_str());
1720 bool isValid = address.IsValid();
1723 ret.push_back(Pair("isvalid", isValid));
1726 // Call Hash160ToAddress() so we always return current ADDRESSVERSION
1727 // version of the address:
1728 string currentAddress = address.ToString();
1729 ret.push_back(Pair("address", currentAddress));
1730 if (pwalletMain->HaveKey(address))
1732 ret.push_back(Pair("ismine", true));
1733 std::vector<unsigned char> vchPubKey;
1734 pwalletMain->GetPubKey(address, vchPubKey);
1735 ret.push_back(Pair("pubkey", HexStr(vchPubKey)));
1737 key.SetPubKey(vchPubKey);
1738 ret.push_back(Pair("iscompressed", key.IsCompressed()));
1740 else if (pwalletMain->HaveCScript(address.GetHash160()))
1742 ret.push_back(Pair("isscript", true));
1744 pwalletMain->GetCScript(address.GetHash160(), subscript);
1745 ret.push_back(Pair("ismine", ::IsMine(*pwalletMain, subscript)));
1746 std::vector<CBitcoinAddress> addresses;
1747 txnouttype whichType;
1749 ExtractAddresses(subscript, whichType, addresses, nRequired);
1750 ret.push_back(Pair("script", GetTxnOutputType(whichType)));
1752 BOOST_FOREACH(const CBitcoinAddress& addr, addresses)
1753 a.push_back(addr.ToString());
1754 ret.push_back(Pair("addresses", a));
1755 if (whichType == TX_MULTISIG)
1756 ret.push_back(Pair("sigsrequired", nRequired));
1759 ret.push_back(Pair("ismine", false));
1760 if (pwalletMain->mapAddressBook.count(address))
1761 ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
1766 Value getwork(const Array& params, bool fHelp)
1768 if (fHelp || params.size() > 1)
1769 throw runtime_error(
1771 "If [data] is not specified, returns formatted hash data to work on:\n"
1772 " \"midstate\" : precomputed hash state after hashing the first half of the data (DEPRECATED)\n" // deprecated
1773 " \"data\" : block data\n"
1774 " \"hash1\" : formatted hash buffer for second hash (DEPRECATED)\n" // deprecated
1775 " \"target\" : little endian hash target\n"
1776 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1779 throw JSONRPCError(-9, "Bitcoin is not connected!");
1781 if (IsInitialBlockDownload())
1782 throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
1784 typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
1785 static mapNewBlock_t mapNewBlock;
1786 static vector<CBlock*> vNewBlock;
1787 static CReserveKey reservekey(pwalletMain);
1789 if (params.size() == 0)
1792 static unsigned int nTransactionsUpdatedLast;
1793 static CBlockIndex* pindexPrev;
1794 static int64 nStart;
1795 static CBlock* pblock;
1796 if (pindexPrev != pindexBest ||
1797 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
1799 if (pindexPrev != pindexBest)
1801 // Deallocate old blocks since they're obsolete now
1802 mapNewBlock.clear();
1803 BOOST_FOREACH(CBlock* pblock, vNewBlock)
1807 nTransactionsUpdatedLast = nTransactionsUpdated;
1808 pindexPrev = pindexBest;
1812 pblock = CreateNewBlock(reservekey);
1814 throw JSONRPCError(-7, "Out of memory");
1815 vNewBlock.push_back(pblock);
1819 pblock->UpdateTime(pindexPrev);
1822 // Update nExtraNonce
1823 static unsigned int nExtraNonce = 0;
1824 IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
1827 mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
1829 // Prebuild hash buffers
1833 FormatHashBuffers(pblock, pmidstate, pdata, phash1);
1835 uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
1838 result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate)))); // deprecated
1839 result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata))));
1840 result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1)))); // deprecated
1841 result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
1847 vector<unsigned char> vchData = ParseHex(params[0].get_str());
1848 if (vchData.size() != 128)
1849 throw JSONRPCError(-8, "Invalid parameter");
1850 CBlock* pdata = (CBlock*)&vchData[0];
1853 for (int i = 0; i < 128/4; i++)
1854 ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]);
1857 if (!mapNewBlock.count(pdata->hashMerkleRoot))
1859 CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
1861 pblock->nTime = pdata->nTime;
1862 pblock->nNonce = pdata->nNonce;
1863 pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
1864 pblock->hashMerkleRoot = pblock->BuildMerkleTree();
1866 return CheckWork(pblock, *pwalletMain, reservekey);
1871 Value getmemorypool(const Array& params, bool fHelp)
1873 if (fHelp || params.size() > 1)
1874 throw runtime_error(
1875 "getmemorypool [data]\n"
1876 "If [data] is not specified, returns data needed to construct a block to work on:\n"
1877 " \"version\" : block version\n"
1878 " \"previousblockhash\" : hash of current highest block\n"
1879 " \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
1880 " \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
1881 " \"coinbaseflags\" : data that should be included in coinbase so support for new features can be judged\n"
1882 " \"time\" : timestamp appropriate for next block\n"
1883 " \"mintime\" : minimum timestamp appropriate for next block\n"
1884 " \"curtime\" : current timestamp\n"
1885 " \"bits\" : compressed target of next block\n"
1886 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1888 if (params.size() == 0)
1891 throw JSONRPCError(-9, "Bitcoin is not connected!");
1893 if (IsInitialBlockDownload())
1894 throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
1896 static CReserveKey reservekey(pwalletMain);
1899 static unsigned int nTransactionsUpdatedLast;
1900 static CBlockIndex* pindexPrev;
1901 static int64 nStart;
1902 static CBlock* pblock;
1903 if (pindexPrev != pindexBest ||
1904 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5))
1906 nTransactionsUpdatedLast = nTransactionsUpdated;
1907 pindexPrev = pindexBest;
1913 pblock = CreateNewBlock(reservekey);
1915 throw JSONRPCError(-7, "Out of memory");
1919 pblock->UpdateTime(pindexPrev);
1923 BOOST_FOREACH(CTransaction tx, pblock->vtx) {
1927 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
1930 transactions.push_back(HexStr(ssTx.begin(), ssTx.end()));
1934 result.push_back(Pair("version", pblock->nVersion));
1935 result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
1936 result.push_back(Pair("transactions", transactions));
1937 result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
1938 result.push_back(Pair("coinbaseflags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end())));
1939 result.push_back(Pair("time", (int64_t)pblock->nTime));
1940 result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1));
1941 result.push_back(Pair("curtime", (int64_t)GetAdjustedTime()));
1942 result.push_back(Pair("bits", HexBits(pblock->nBits)));
1949 CDataStream ssBlock(ParseHex(params[0].get_str()), SER_NETWORK, PROTOCOL_VERSION);
1953 return ProcessBlock(NULL, &pblock);
1957 Value getblockhash(const Array& params, bool fHelp)
1959 if (fHelp || params.size() != 1)
1960 throw runtime_error(
1961 "getblockhash <index>\n"
1962 "Returns hash of block in best-block-chain at <index>.");
1964 int nHeight = params[0].get_int();
1965 if (nHeight < 0 || nHeight > nBestHeight)
1966 throw runtime_error("Block number out of range.");
1969 CBlockIndex* pblockindex = mapBlockIndex[hashBestChain];
1970 while (pblockindex->nHeight > nHeight)
1971 pblockindex = pblockindex->pprev;
1972 return pblockindex->phashBlock->GetHex();
1975 Value getblock(const Array& params, bool fHelp)
1977 if (fHelp || params.size() != 1)
1978 throw runtime_error(
1980 "Returns details of a block with given block-hash.");
1982 std::string strHash = params[0].get_str();
1983 uint256 hash(strHash);
1985 if (mapBlockIndex.count(hash) == 0)
1986 throw JSONRPCError(-5, "Block not found");
1989 CBlockIndex* pblockindex = mapBlockIndex[hash];
1990 block.ReadFromDisk(pblockindex, true);
1992 return blockToJSON(block, pblockindex);
2010 static const CRPCCommand vRPCCommands[] =
2011 { // name function safe mode?
2012 // ------------------------ ----------------------- ----------
2013 { "help", &help, true },
2014 { "stop", &stop, true },
2015 { "getblockcount", &getblockcount, true },
2016 { "getblocknumber", &getblocknumber, true },
2017 { "getconnectioncount", &getconnectioncount, true },
2018 { "getdifficulty", &getdifficulty, true },
2019 { "getgenerate", &getgenerate, true },
2020 { "setgenerate", &setgenerate, true },
2021 { "gethashespersec", &gethashespersec, true },
2022 { "getinfo", &getinfo, true },
2023 { "getmininginfo", &getmininginfo, true },
2024 { "getnewaddress", &getnewaddress, true },
2025 { "getaccountaddress", &getaccountaddress, true },
2026 { "setaccount", &setaccount, true },
2027 { "getaccount", &getaccount, false },
2028 { "getaddressesbyaccount", &getaddressesbyaccount, true },
2029 { "sendtoaddress", &sendtoaddress, false },
2030 { "getreceivedbyaddress", &getreceivedbyaddress, false },
2031 { "getreceivedbyaccount", &getreceivedbyaccount, false },
2032 { "listreceivedbyaddress", &listreceivedbyaddress, false },
2033 { "listreceivedbyaccount", &listreceivedbyaccount, false },
2034 { "backupwallet", &backupwallet, true },
2035 { "keypoolrefill", &keypoolrefill, true },
2036 { "walletpassphrase", &walletpassphrase, true },
2037 { "walletpassphrasechange", &walletpassphrasechange, false },
2038 { "walletlock", &walletlock, true },
2039 { "encryptwallet", &encryptwallet, false },
2040 { "validateaddress", &validateaddress, true },
2041 { "getbalance", &getbalance, false },
2042 { "move", &movecmd, false },
2043 { "sendfrom", &sendfrom, false },
2044 { "sendmany", &sendmany, false },
2045 { "addmultisigaddress", &addmultisigaddress, false },
2046 { "getblock", &getblock, false },
2047 { "getblockhash", &getblockhash, false },
2048 { "gettransaction", &gettransaction, false },
2049 { "listtransactions", &listtransactions, false },
2050 { "signmessage", &signmessage, false },
2051 { "verifymessage", &verifymessage, false },
2052 { "getwork", &getwork, true },
2053 { "listaccounts", &listaccounts, false },
2054 { "settxfee", &settxfee, false },
2055 { "getmemorypool", &getmemorypool, true },
2056 { "listsinceblock", &listsinceblock, false },
2057 { "dumpprivkey", &dumpprivkey, false },
2058 { "importprivkey", &importprivkey, false },
2061 CRPCTable::CRPCTable()
2064 for (vcidx = 0; vcidx < (sizeof(vRPCCommands) / sizeof(vRPCCommands[0])); vcidx++)
2066 const CRPCCommand *pcmd;
2068 pcmd = &vRPCCommands[vcidx];
2069 mapCommands[pcmd->name] = pcmd;
2073 const CRPCCommand *CRPCTable::operator[](string name) const
2075 map<string, const CRPCCommand*>::const_iterator it = mapCommands.find(name);
2076 if (it == mapCommands.end())
2078 return (*it).second;
2084 // This ain't Apache. We're just using HTTP header for the length field
2085 // and to be compatible with other JSON-RPC implementations.
2088 string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
2091 s << "POST / HTTP/1.1\r\n"
2092 << "User-Agent: bitcoin-json-rpc/" << FormatFullVersion() << "\r\n"
2093 << "Host: 127.0.0.1\r\n"
2094 << "Content-Type: application/json\r\n"
2095 << "Content-Length: " << strMsg.size() << "\r\n"
2096 << "Connection: close\r\n"
2097 << "Accept: application/json\r\n";
2098 BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
2099 s << item.first << ": " << item.second << "\r\n";
2100 s << "\r\n" << strMsg;
2105 string rfc1123Time()
2110 struct tm* now_gmt = gmtime(&now);
2111 string locale(setlocale(LC_TIME, NULL));
2112 setlocale(LC_TIME, "C"); // we want posix (aka "C") weekday/month strings
2113 strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt);
2114 setlocale(LC_TIME, locale.c_str());
2115 return string(buffer);
2118 static string HTTPReply(int nStatus, const string& strMsg)
2121 return strprintf("HTTP/1.0 401 Authorization Required\r\n"
2123 "Server: bitcoin-json-rpc/%s\r\n"
2124 "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
2125 "Content-Type: text/html\r\n"
2126 "Content-Length: 296\r\n"
2128 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
2129 "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
2132 "<TITLE>Error</TITLE>\r\n"
2133 "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
2135 "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
2136 "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
2137 const char *cStatus;
2138 if (nStatus == 200) cStatus = "OK";
2139 else if (nStatus == 400) cStatus = "Bad Request";
2140 else if (nStatus == 403) cStatus = "Forbidden";
2141 else if (nStatus == 404) cStatus = "Not Found";
2142 else if (nStatus == 500) cStatus = "Internal Server Error";
2145 "HTTP/1.1 %d %s\r\n"
2147 "Connection: close\r\n"
2148 "Content-Length: %d\r\n"
2149 "Content-Type: application/json\r\n"
2150 "Server: bitcoin-json-rpc/%s\r\n"
2155 rfc1123Time().c_str(),
2157 FormatFullVersion().c_str(),
2161 int ReadHTTPStatus(std::basic_istream<char>& stream)
2164 getline(stream, str);
2165 vector<string> vWords;
2166 boost::split(vWords, str, boost::is_any_of(" "));
2167 if (vWords.size() < 2)
2169 return atoi(vWords[1].c_str());
2172 int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
2178 std::getline(stream, str);
2179 if (str.empty() || str == "\r")
2181 string::size_type nColon = str.find(":");
2182 if (nColon != string::npos)
2184 string strHeader = str.substr(0, nColon);
2185 boost::trim(strHeader);
2186 boost::to_lower(strHeader);
2187 string strValue = str.substr(nColon+1);
2188 boost::trim(strValue);
2189 mapHeadersRet[strHeader] = strValue;
2190 if (strHeader == "content-length")
2191 nLen = atoi(strValue.c_str());
2197 int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
2199 mapHeadersRet.clear();
2203 int nStatus = ReadHTTPStatus(stream);
2206 int nLen = ReadHTTPHeader(stream, mapHeadersRet);
2207 if (nLen < 0 || nLen > (int)MAX_SIZE)
2213 vector<char> vch(nLen);
2214 stream.read(&vch[0], nLen);
2215 strMessageRet = string(vch.begin(), vch.end());
2221 bool HTTPAuthorized(map<string, string>& mapHeaders)
2223 string strAuth = mapHeaders["authorization"];
2224 if (strAuth.substr(0,6) != "Basic ")
2226 string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
2227 string strUserPass = DecodeBase64(strUserPass64);
2228 return strUserPass == strRPCUserColonPass;
2232 // JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
2233 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
2234 // unspecified (HTTP errors and contents of 'error').
2236 // 1.0 spec: http://json-rpc.org/wiki/specification
2237 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
2238 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
2241 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
2244 request.push_back(Pair("method", strMethod));
2245 request.push_back(Pair("params", params));
2246 request.push_back(Pair("id", id));
2247 return write_string(Value(request), false) + "\n";
2250 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
2253 if (error.type() != null_type)
2254 reply.push_back(Pair("result", Value::null));
2256 reply.push_back(Pair("result", result));
2257 reply.push_back(Pair("error", error));
2258 reply.push_back(Pair("id", id));
2259 return write_string(Value(reply), false) + "\n";
2262 void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
2264 // Send error reply from json-rpc error object
2266 int code = find_value(objError, "code").get_int();
2267 if (code == -32600) nStatus = 400;
2268 else if (code == -32601) nStatus = 404;
2269 string strReply = JSONRPCReply(Value::null, objError, id);
2270 stream << HTTPReply(nStatus, strReply) << std::flush;
2273 bool ClientAllowed(const string& strAddress)
2275 if (strAddress == asio::ip::address_v4::loopback().to_string())
2277 const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
2278 BOOST_FOREACH(string strAllow, vAllow)
2279 if (WildcardMatch(strAddress, strAllow))
2285 // IOStream device that speaks SSL but can also speak non-SSL
2287 class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
2289 SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
2291 fUseSSL = fUseSSLIn;
2292 fNeedHandshake = fUseSSLIn;
2295 void handshake(ssl::stream_base::handshake_type role)
2297 if (!fNeedHandshake) return;
2298 fNeedHandshake = false;
2299 stream.handshake(role);
2301 std::streamsize read(char* s, std::streamsize n)
2303 handshake(ssl::stream_base::server); // HTTPS servers read first
2304 if (fUseSSL) return stream.read_some(asio::buffer(s, n));
2305 return stream.next_layer().read_some(asio::buffer(s, n));
2307 std::streamsize write(const char* s, std::streamsize n)
2309 handshake(ssl::stream_base::client); // HTTPS clients write first
2310 if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
2311 return asio::write(stream.next_layer(), asio::buffer(s, n));
2313 bool connect(const std::string& server, const std::string& port)
2315 ip::tcp::resolver resolver(stream.get_io_service());
2316 ip::tcp::resolver::query query(server.c_str(), port.c_str());
2317 ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
2318 ip::tcp::resolver::iterator end;
2319 boost::system::error_code error = asio::error::host_not_found;
2320 while (error && endpoint_iterator != end)
2322 stream.lowest_layer().close();
2323 stream.lowest_layer().connect(*endpoint_iterator++, error);
2331 bool fNeedHandshake;
2336 void ThreadRPCServer(void* parg)
2338 IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
2341 vnThreadsRunning[THREAD_RPCSERVER]++;
2342 ThreadRPCServer2(parg);
2343 vnThreadsRunning[THREAD_RPCSERVER]--;
2345 catch (std::exception& e) {
2346 vnThreadsRunning[THREAD_RPCSERVER]--;
2347 PrintException(&e, "ThreadRPCServer()");
2349 vnThreadsRunning[THREAD_RPCSERVER]--;
2350 PrintException(NULL, "ThreadRPCServer()");
2352 printf("ThreadRPCServer exiting\n");
2355 void ThreadRPCServer2(void* parg)
2357 printf("ThreadRPCServer started\n");
2359 strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
2360 if (mapArgs["-rpcpassword"] == "")
2362 unsigned char rand_pwd[32];
2363 RAND_bytes(rand_pwd, 32);
2364 string strWhatAmI = "To use bitcoind";
2365 if (mapArgs.count("-server"))
2366 strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
2367 else if (mapArgs.count("-daemon"))
2368 strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
2369 ThreadSafeMessageBox(strprintf(
2370 _("%s, you must set a rpcpassword in the configuration file:\n %s\n"
2371 "It is recommended you use the following random password:\n"
2372 "rpcuser=bitcoinrpc\n"
2374 "(you do not need to remember this password)\n"
2375 "If the file does not exist, create it with owner-readable-only file permissions.\n"),
2377 GetConfigFile().string().c_str(),
2378 EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str()),
2379 _("Error"), wxOK | wxMODAL);
2384 bool fUseSSL = GetBoolArg("-rpcssl");
2385 asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
2387 asio::io_service io_service;
2388 ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", 8332));
2389 ip::tcp::acceptor acceptor(io_service);
2392 acceptor.open(endpoint.protocol());
2393 acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
2394 acceptor.bind(endpoint);
2395 acceptor.listen(socket_base::max_connections);
2397 catch(boost::system::system_error &e)
2399 ThreadSafeMessageBox(strprintf(_("An error occured while setting up the RPC port %i for listening: %s"), endpoint.port(), e.what()),
2400 _("Error"), wxOK | wxMODAL);
2405 ssl::context context(io_service, ssl::context::sslv23);
2408 context.set_options(ssl::context::no_sslv2);
2410 filesystem::path pathCertFile(GetArg("-rpcsslcertificatechainfile", "server.cert"));
2411 if (!pathCertFile.is_complete()) pathCertFile = filesystem::path(GetDataDir()) / pathCertFile;
2412 if (filesystem::exists(pathCertFile)) context.use_certificate_chain_file(pathCertFile.string());
2413 else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", pathCertFile.string().c_str());
2415 filesystem::path pathPKFile(GetArg("-rpcsslprivatekeyfile", "server.pem"));
2416 if (!pathPKFile.is_complete()) pathPKFile = filesystem::path(GetDataDir()) / pathPKFile;
2417 if (filesystem::exists(pathPKFile)) context.use_private_key_file(pathPKFile.string(), ssl::context::pem);
2418 else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pathPKFile.string().c_str());
2420 string strCiphers = GetArg("-rpcsslciphers", "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
2421 SSL_CTX_set_cipher_list(context.impl(), strCiphers.c_str());
2426 // Accept connection
2427 SSLStream sslStream(io_service, context);
2428 SSLIOStreamDevice d(sslStream, fUseSSL);
2429 iostreams::stream<SSLIOStreamDevice> stream(d);
2431 ip::tcp::endpoint peer;
2432 vnThreadsRunning[THREAD_RPCSERVER]--;
2433 acceptor.accept(sslStream.lowest_layer(), peer);
2434 vnThreadsRunning[4]++;
2438 // Restrict callers by IP
2439 if (!ClientAllowed(peer.address().to_string()))
2441 // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
2443 stream << HTTPReply(403, "") << std::flush;
2447 map<string, string> mapHeaders;
2450 boost::thread api_caller(ReadHTTP, boost::ref(stream), boost::ref(mapHeaders), boost::ref(strRequest));
2451 if (!api_caller.timed_join(boost::posix_time::seconds(GetArg("-rpctimeout", 30))))
2454 printf("ThreadRPCServer ReadHTTP timeout\n");
2458 // Check authorization
2459 if (mapHeaders.count("authorization") == 0)
2461 stream << HTTPReply(401, "") << std::flush;
2464 if (!HTTPAuthorized(mapHeaders))
2466 printf("ThreadRPCServer incorrect password attempt from %s\n",peer.address().to_string().c_str());
2467 /* Deter brute-forcing short passwords.
2468 If this results in a DOS the user really
2469 shouldn't have their RPC port exposed.*/
2470 if (mapArgs["-rpcpassword"].size() < 20)
2473 stream << HTTPReply(401, "") << std::flush;
2477 Value id = Value::null;
2482 if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
2483 throw JSONRPCError(-32700, "Parse error");
2484 const Object& request = valRequest.get_obj();
2486 // Parse id now so errors from here on will have the id
2487 id = find_value(request, "id");
2490 Value valMethod = find_value(request, "method");
2491 if (valMethod.type() == null_type)
2492 throw JSONRPCError(-32600, "Missing method");
2493 if (valMethod.type() != str_type)
2494 throw JSONRPCError(-32600, "Method must be a string");
2495 string strMethod = valMethod.get_str();
2496 if (strMethod != "getwork" && strMethod != "getmemorypool")
2497 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
2500 Value valParams = find_value(request, "params");
2502 if (valParams.type() == array_type)
2503 params = valParams.get_array();
2504 else if (valParams.type() == null_type)
2507 throw JSONRPCError(-32600, "Params must be an array");
2510 const CRPCCommand *pcmd = tableRPC[strMethod];
2512 throw JSONRPCError(-32601, "Method not found");
2514 // Observe safe mode
2515 string strWarning = GetWarnings("rpc");
2516 if (strWarning != "" && !GetBoolArg("-disablesafemode") &&
2518 throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
2525 LOCK2(cs_main, pwalletMain->cs_wallet);
2526 result = pcmd->actor(params, false);
2530 string strReply = JSONRPCReply(result, Value::null, id);
2531 stream << HTTPReply(200, strReply) << std::flush;
2533 catch (std::exception& e)
2535 ErrorReply(stream, JSONRPCError(-1, e.what()), id);
2538 catch (Object& objError)
2540 ErrorReply(stream, objError, id);
2542 catch (std::exception& e)
2544 ErrorReply(stream, JSONRPCError(-32700, e.what()), id);
2552 Object CallRPC(const string& strMethod, const Array& params)
2554 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2555 throw runtime_error(strprintf(
2556 _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
2557 "If the file does not exist, create it with owner-readable-only file permissions."),
2558 GetConfigFile().string().c_str()));
2560 // Connect to localhost
2561 bool fUseSSL = GetBoolArg("-rpcssl");
2562 asio::io_service io_service;
2563 ssl::context context(io_service, ssl::context::sslv23);
2564 context.set_options(ssl::context::no_sslv2);
2565 SSLStream sslStream(io_service, context);
2566 SSLIOStreamDevice d(sslStream, fUseSSL);
2567 iostreams::stream<SSLIOStreamDevice> stream(d);
2568 if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332")))
2569 throw runtime_error("couldn't connect to server");
2571 // HTTP basic authentication
2572 string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
2573 map<string, string> mapRequestHeaders;
2574 mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
2577 string strRequest = JSONRPCRequest(strMethod, params, 1);
2578 string strPost = HTTPPost(strRequest, mapRequestHeaders);
2579 stream << strPost << std::flush;
2582 map<string, string> mapHeaders;
2584 int nStatus = ReadHTTP(stream, mapHeaders, strReply);
2586 throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
2587 else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
2588 throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
2589 else if (strReply.empty())
2590 throw runtime_error("no response from server");
2594 if (!read_string(strReply, valReply))
2595 throw runtime_error("couldn't parse reply from server");
2596 const Object& reply = valReply.get_obj();
2598 throw runtime_error("expected reply to have result, error and id properties");
2606 template<typename T>
2607 void ConvertTo(Value& value)
2609 if (value.type() == str_type)
2611 // reinterpret string as unquoted json value
2613 if (!read_string(value.get_str(), value2))
2614 throw runtime_error("type mismatch");
2615 value = value2.get_value<T>();
2619 value = value.get_value<T>();
2623 int CommandLineRPC(int argc, char *argv[])
2630 while (argc > 1 && IsSwitchChar(argv[1][0]))
2638 throw runtime_error("too few parameters");
2639 string strMethod = argv[1];
2641 // Parameters default to strings
2643 for (int i = 2; i < argc; i++)
2644 params.push_back(argv[i]);
2645 int n = params.size();
2648 // Special case non-string parameter types
2650 if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
2651 if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2652 if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
2653 if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]);
2654 if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2655 if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2656 if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2657 if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
2658 if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2659 if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
2660 if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2661 if (strMethod == "getblockhash" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2662 if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]);
2663 if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2664 if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]);
2665 if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2666 if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2667 if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2668 if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2669 if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2670 if (strMethod == "listsinceblock" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2671 if (strMethod == "sendmany" && n > 1)
2673 string s = params[1].get_str();
2675 if (!read_string(s, v) || v.type() != obj_type)
2676 throw runtime_error("type mismatch");
2677 params[1] = v.get_obj();
2679 if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2680 if (strMethod == "addmultisigaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2681 if (strMethod == "addmultisigaddress" && n > 1)
2683 string s = params[1].get_str();
2685 if (!read_string(s, v) || v.type() != array_type)
2686 throw runtime_error("type mismatch "+s);
2687 params[1] = v.get_array();
2691 Object reply = CallRPC(strMethod, params);
2694 const Value& result = find_value(reply, "result");
2695 const Value& error = find_value(reply, "error");
2697 if (error.type() != null_type)
2700 strPrint = "error: " + write_string(error, false);
2701 int code = find_value(error.get_obj(), "code").get_int();
2707 if (result.type() == null_type)
2709 else if (result.type() == str_type)
2710 strPrint = result.get_str();
2712 strPrint = write_string(result, true);
2715 catch (std::exception& e)
2717 strPrint = string("error: ") + e.what();
2722 PrintException(NULL, "CommandLineRPC()");
2727 fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
2736 int main(int argc, char *argv[])
2739 // Turn off microsoft heap dump noise
2740 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
2741 _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
2743 setbuf(stdin, NULL);
2744 setbuf(stdout, NULL);
2745 setbuf(stderr, NULL);
2749 if (argc >= 2 && string(argv[1]) == "-server")
2751 printf("server ready\n");
2752 ThreadRPCServer(NULL);
2756 return CommandLineRPC(argc, argv);
2759 catch (std::exception& e) {
2760 PrintException(&e, "main()");
2762 PrintException(NULL, "main()");
2768 const CRPCTable tableRPC;