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)
1444 lastblock = hashBestChain;
1448 int target_height = pindexBest->nHeight + 1 - target_confirms;
1451 for (block = pindexBest;
1452 block && block->nHeight > target_height;
1453 block = block->pprev) { }
1455 lastblock = block ? block->GetBlockHash() : 0;
1459 ret.push_back(Pair("transactions", transactions));
1460 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1465 Value gettransaction(const Array& params, bool fHelp)
1467 if (fHelp || params.size() != 1)
1468 throw runtime_error(
1469 "gettransaction <txid>\n"
1470 "Get detailed information about <txid>");
1473 hash.SetHex(params[0].get_str());
1477 if (!pwalletMain->mapWallet.count(hash))
1478 throw JSONRPCError(-5, "Invalid or non-wallet transaction id");
1479 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1481 int64 nCredit = wtx.GetCredit();
1482 int64 nDebit = wtx.GetDebit();
1483 int64 nNet = nCredit - nDebit;
1484 int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
1486 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1488 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1490 WalletTxToJSON(pwalletMain->mapWallet[hash], entry);
1493 ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
1494 entry.push_back(Pair("details", details));
1500 Value backupwallet(const Array& params, bool fHelp)
1502 if (fHelp || params.size() != 1)
1503 throw runtime_error(
1504 "backupwallet <destination>\n"
1505 "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1507 string strDest = params[0].get_str();
1508 BackupWallet(*pwalletMain, strDest);
1514 Value keypoolrefill(const Array& params, bool fHelp)
1516 if (pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1517 throw runtime_error(
1519 "Fills the keypool, requires wallet passphrase to be set.");
1520 if (!pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1521 throw runtime_error(
1523 "Fills the keypool.");
1525 if (pwalletMain->IsLocked())
1526 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
1528 pwalletMain->TopUpKeyPool();
1530 if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100))
1531 throw JSONRPCError(-4, "Error refreshing keypool.");
1537 void ThreadTopUpKeyPool(void* parg)
1539 pwalletMain->TopUpKeyPool();
1542 void ThreadCleanWalletPassphrase(void* parg)
1544 int64 nMyWakeTime = GetTimeMillis() + *((int64*)parg) * 1000;
1546 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1548 if (nWalletUnlockTime == 0)
1550 nWalletUnlockTime = nMyWakeTime;
1554 if (nWalletUnlockTime==0)
1556 int64 nToSleep = nWalletUnlockTime - GetTimeMillis();
1560 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1562 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1566 if (nWalletUnlockTime)
1568 nWalletUnlockTime = 0;
1569 pwalletMain->Lock();
1574 if (nWalletUnlockTime < nMyWakeTime)
1575 nWalletUnlockTime = nMyWakeTime;
1578 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1580 delete (int64*)parg;
1583 Value walletpassphrase(const Array& params, bool fHelp)
1585 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1586 throw runtime_error(
1587 "walletpassphrase <passphrase> <timeout>\n"
1588 "Stores the wallet decryption key in memory for <timeout> seconds.");
1591 if (!pwalletMain->IsCrypted())
1592 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1594 if (!pwalletMain->IsLocked())
1595 throw JSONRPCError(-17, "Error: Wallet is already unlocked.");
1597 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1598 SecureString strWalletPass;
1599 strWalletPass.reserve(100);
1600 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1601 // Alternately, find a way to make params[0] mlock()'d to begin with.
1602 strWalletPass = params[0].get_str().c_str();
1604 if (strWalletPass.length() > 0)
1606 if (!pwalletMain->Unlock(strWalletPass))
1607 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1610 throw runtime_error(
1611 "walletpassphrase <passphrase> <timeout>\n"
1612 "Stores the wallet decryption key in memory for <timeout> seconds.");
1614 CreateThread(ThreadTopUpKeyPool, NULL);
1615 int64* pnSleepTime = new int64(params[1].get_int64());
1616 CreateThread(ThreadCleanWalletPassphrase, pnSleepTime);
1622 Value walletpassphrasechange(const Array& params, bool fHelp)
1624 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1625 throw runtime_error(
1626 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1627 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1630 if (!pwalletMain->IsCrypted())
1631 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1633 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1634 // Alternately, find a way to make params[0] mlock()'d to begin with.
1635 SecureString strOldWalletPass;
1636 strOldWalletPass.reserve(100);
1637 strOldWalletPass = params[0].get_str().c_str();
1639 SecureString strNewWalletPass;
1640 strNewWalletPass.reserve(100);
1641 strNewWalletPass = params[1].get_str().c_str();
1643 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1644 throw runtime_error(
1645 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1646 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1648 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1649 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1655 Value walletlock(const Array& params, bool fHelp)
1657 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1658 throw runtime_error(
1660 "Removes the wallet encryption key from memory, locking the wallet.\n"
1661 "After calling this method, you will need to call walletpassphrase again\n"
1662 "before being able to call any methods which require the wallet to be unlocked.");
1665 if (!pwalletMain->IsCrypted())
1666 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called.");
1669 LOCK(cs_nWalletUnlockTime);
1670 pwalletMain->Lock();
1671 nWalletUnlockTime = 0;
1678 Value encryptwallet(const Array& params, bool fHelp)
1680 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1681 throw runtime_error(
1682 "encryptwallet <passphrase>\n"
1683 "Encrypts the wallet with <passphrase>.");
1686 if (pwalletMain->IsCrypted())
1687 throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
1689 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1690 // Alternately, find a way to make params[0] mlock()'d to begin with.
1691 SecureString strWalletPass;
1692 strWalletPass.reserve(100);
1693 strWalletPass = params[0].get_str().c_str();
1695 if (strWalletPass.length() < 1)
1696 throw runtime_error(
1697 "encryptwallet <passphrase>\n"
1698 "Encrypts the wallet with <passphrase>.");
1700 if (!pwalletMain->EncryptWallet(strWalletPass))
1701 throw JSONRPCError(-16, "Error: Failed to encrypt the wallet.");
1703 // BDB seems to have a bad habit of writing old data into
1704 // slack space in .dat files; that is bad if the old data is
1705 // unencrypted private keys. So:
1707 return "wallet encrypted; bitcoin server stopping, restart to run with encrypted wallet";
1711 Value validateaddress(const Array& params, bool fHelp)
1713 if (fHelp || params.size() != 1)
1714 throw runtime_error(
1715 "validateaddress <bitcoinaddress>\n"
1716 "Return information about <bitcoinaddress>.");
1718 CBitcoinAddress address(params[0].get_str());
1719 bool isValid = address.IsValid();
1722 ret.push_back(Pair("isvalid", isValid));
1725 // Call Hash160ToAddress() so we always return current ADDRESSVERSION
1726 // version of the address:
1727 string currentAddress = address.ToString();
1728 ret.push_back(Pair("address", currentAddress));
1729 if (pwalletMain->HaveKey(address))
1731 ret.push_back(Pair("ismine", true));
1732 std::vector<unsigned char> vchPubKey;
1733 pwalletMain->GetPubKey(address, vchPubKey);
1734 ret.push_back(Pair("pubkey", HexStr(vchPubKey)));
1736 key.SetPubKey(vchPubKey);
1737 ret.push_back(Pair("iscompressed", key.IsCompressed()));
1739 else if (pwalletMain->HaveCScript(address.GetHash160()))
1741 ret.push_back(Pair("isscript", true));
1743 pwalletMain->GetCScript(address.GetHash160(), subscript);
1744 ret.push_back(Pair("ismine", ::IsMine(*pwalletMain, subscript)));
1745 std::vector<CBitcoinAddress> addresses;
1746 txnouttype whichType;
1748 ExtractAddresses(subscript, whichType, addresses, nRequired);
1749 ret.push_back(Pair("script", GetTxnOutputType(whichType)));
1751 BOOST_FOREACH(const CBitcoinAddress& addr, addresses)
1752 a.push_back(addr.ToString());
1753 ret.push_back(Pair("addresses", a));
1754 if (whichType == TX_MULTISIG)
1755 ret.push_back(Pair("sigsrequired", nRequired));
1758 ret.push_back(Pair("ismine", false));
1759 if (pwalletMain->mapAddressBook.count(address))
1760 ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
1765 Value getwork(const Array& params, bool fHelp)
1767 if (fHelp || params.size() > 1)
1768 throw runtime_error(
1770 "If [data] is not specified, returns formatted hash data to work on:\n"
1771 " \"midstate\" : precomputed hash state after hashing the first half of the data (DEPRECATED)\n" // deprecated
1772 " \"data\" : block data\n"
1773 " \"hash1\" : formatted hash buffer for second hash (DEPRECATED)\n" // deprecated
1774 " \"target\" : little endian hash target\n"
1775 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1778 throw JSONRPCError(-9, "Bitcoin is not connected!");
1780 if (IsInitialBlockDownload())
1781 throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
1783 typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
1784 static mapNewBlock_t mapNewBlock;
1785 static vector<CBlock*> vNewBlock;
1786 static CReserveKey reservekey(pwalletMain);
1788 if (params.size() == 0)
1791 static unsigned int nTransactionsUpdatedLast;
1792 static CBlockIndex* pindexPrev;
1793 static int64 nStart;
1794 static CBlock* pblock;
1795 if (pindexPrev != pindexBest ||
1796 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
1798 if (pindexPrev != pindexBest)
1800 // Deallocate old blocks since they're obsolete now
1801 mapNewBlock.clear();
1802 BOOST_FOREACH(CBlock* pblock, vNewBlock)
1806 nTransactionsUpdatedLast = nTransactionsUpdated;
1807 pindexPrev = pindexBest;
1811 pblock = CreateNewBlock(reservekey);
1813 throw JSONRPCError(-7, "Out of memory");
1814 vNewBlock.push_back(pblock);
1818 pblock->UpdateTime(pindexPrev);
1821 // Update nExtraNonce
1822 static unsigned int nExtraNonce = 0;
1823 IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
1826 mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
1828 // Prebuild hash buffers
1832 FormatHashBuffers(pblock, pmidstate, pdata, phash1);
1834 uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
1837 result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate)))); // deprecated
1838 result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata))));
1839 result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1)))); // deprecated
1840 result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
1846 vector<unsigned char> vchData = ParseHex(params[0].get_str());
1847 if (vchData.size() != 128)
1848 throw JSONRPCError(-8, "Invalid parameter");
1849 CBlock* pdata = (CBlock*)&vchData[0];
1852 for (int i = 0; i < 128/4; i++)
1853 ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]);
1856 if (!mapNewBlock.count(pdata->hashMerkleRoot))
1858 CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
1860 pblock->nTime = pdata->nTime;
1861 pblock->nNonce = pdata->nNonce;
1862 pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
1863 pblock->hashMerkleRoot = pblock->BuildMerkleTree();
1865 return CheckWork(pblock, *pwalletMain, reservekey);
1870 Value getmemorypool(const Array& params, bool fHelp)
1872 if (fHelp || params.size() > 1)
1873 throw runtime_error(
1874 "getmemorypool [data]\n"
1875 "If [data] is not specified, returns data needed to construct a block to work on:\n"
1876 " \"version\" : block version\n"
1877 " \"previousblockhash\" : hash of current highest block\n"
1878 " \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
1879 " \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
1880 " \"coinbaseflags\" : data that should be included in coinbase so support for new features can be judged\n"
1881 " \"time\" : timestamp appropriate for next block\n"
1882 " \"mintime\" : minimum timestamp appropriate for next block\n"
1883 " \"curtime\" : current timestamp\n"
1884 " \"bits\" : compressed target of next block\n"
1885 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1887 if (params.size() == 0)
1890 throw JSONRPCError(-9, "Bitcoin is not connected!");
1892 if (IsInitialBlockDownload())
1893 throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
1895 static CReserveKey reservekey(pwalletMain);
1898 static unsigned int nTransactionsUpdatedLast;
1899 static CBlockIndex* pindexPrev;
1900 static int64 nStart;
1901 static CBlock* pblock;
1902 if (pindexPrev != pindexBest ||
1903 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5))
1905 nTransactionsUpdatedLast = nTransactionsUpdated;
1906 pindexPrev = pindexBest;
1912 pblock = CreateNewBlock(reservekey);
1914 throw JSONRPCError(-7, "Out of memory");
1918 pblock->UpdateTime(pindexPrev);
1922 BOOST_FOREACH(CTransaction tx, pblock->vtx) {
1926 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
1929 transactions.push_back(HexStr(ssTx.begin(), ssTx.end()));
1933 result.push_back(Pair("version", pblock->nVersion));
1934 result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
1935 result.push_back(Pair("transactions", transactions));
1936 result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
1937 result.push_back(Pair("coinbaseflags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end())));
1938 result.push_back(Pair("time", (int64_t)pblock->nTime));
1939 result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1));
1940 result.push_back(Pair("curtime", (int64_t)GetAdjustedTime()));
1941 result.push_back(Pair("bits", HexBits(pblock->nBits)));
1948 CDataStream ssBlock(ParseHex(params[0].get_str()), SER_NETWORK, PROTOCOL_VERSION);
1952 return ProcessBlock(NULL, &pblock);
1956 Value getblockhash(const Array& params, bool fHelp)
1958 if (fHelp || params.size() != 1)
1959 throw runtime_error(
1960 "getblockhash <index>\n"
1961 "Returns hash of block in best-block-chain at <index>.");
1963 int nHeight = params[0].get_int();
1964 if (nHeight < 0 || nHeight > nBestHeight)
1965 throw runtime_error("Block number out of range.");
1968 CBlockIndex* pblockindex = mapBlockIndex[hashBestChain];
1969 while (pblockindex->nHeight > nHeight)
1970 pblockindex = pblockindex->pprev;
1971 return pblockindex->phashBlock->GetHex();
1974 Value getblock(const Array& params, bool fHelp)
1976 if (fHelp || params.size() != 1)
1977 throw runtime_error(
1979 "Returns details of a block with given block-hash.");
1981 std::string strHash = params[0].get_str();
1982 uint256 hash(strHash);
1984 if (mapBlockIndex.count(hash) == 0)
1985 throw JSONRPCError(-5, "Block not found");
1988 CBlockIndex* pblockindex = mapBlockIndex[hash];
1989 block.ReadFromDisk(pblockindex, true);
1991 return blockToJSON(block, pblockindex);
2009 static const CRPCCommand vRPCCommands[] =
2010 { // name function safe mode?
2011 // ------------------------ ----------------------- ----------
2012 { "help", &help, true },
2013 { "stop", &stop, true },
2014 { "getblockcount", &getblockcount, true },
2015 { "getblocknumber", &getblocknumber, true },
2016 { "getconnectioncount", &getconnectioncount, true },
2017 { "getdifficulty", &getdifficulty, true },
2018 { "getgenerate", &getgenerate, true },
2019 { "setgenerate", &setgenerate, true },
2020 { "gethashespersec", &gethashespersec, true },
2021 { "getinfo", &getinfo, true },
2022 { "getmininginfo", &getmininginfo, true },
2023 { "getnewaddress", &getnewaddress, true },
2024 { "getaccountaddress", &getaccountaddress, true },
2025 { "setaccount", &setaccount, true },
2026 { "getaccount", &getaccount, false },
2027 { "getaddressesbyaccount", &getaddressesbyaccount, true },
2028 { "sendtoaddress", &sendtoaddress, false },
2029 { "getreceivedbyaddress", &getreceivedbyaddress, false },
2030 { "getreceivedbyaccount", &getreceivedbyaccount, false },
2031 { "listreceivedbyaddress", &listreceivedbyaddress, false },
2032 { "listreceivedbyaccount", &listreceivedbyaccount, false },
2033 { "backupwallet", &backupwallet, true },
2034 { "keypoolrefill", &keypoolrefill, true },
2035 { "walletpassphrase", &walletpassphrase, true },
2036 { "walletpassphrasechange", &walletpassphrasechange, false },
2037 { "walletlock", &walletlock, true },
2038 { "encryptwallet", &encryptwallet, false },
2039 { "validateaddress", &validateaddress, true },
2040 { "getbalance", &getbalance, false },
2041 { "move", &movecmd, false },
2042 { "sendfrom", &sendfrom, false },
2043 { "sendmany", &sendmany, false },
2044 { "addmultisigaddress", &addmultisigaddress, false },
2045 { "getblock", &getblock, false },
2046 { "getblockhash", &getblockhash, false },
2047 { "gettransaction", &gettransaction, false },
2048 { "listtransactions", &listtransactions, false },
2049 { "signmessage", &signmessage, false },
2050 { "verifymessage", &verifymessage, false },
2051 { "getwork", &getwork, true },
2052 { "listaccounts", &listaccounts, false },
2053 { "settxfee", &settxfee, false },
2054 { "getmemorypool", &getmemorypool, true },
2055 { "listsinceblock", &listsinceblock, false },
2056 { "dumpprivkey", &dumpprivkey, false },
2057 { "importprivkey", &importprivkey, false },
2060 CRPCTable::CRPCTable()
2063 for (vcidx = 0; vcidx < (sizeof(vRPCCommands) / sizeof(vRPCCommands[0])); vcidx++)
2065 const CRPCCommand *pcmd;
2067 pcmd = &vRPCCommands[vcidx];
2068 mapCommands[pcmd->name] = pcmd;
2072 const CRPCCommand *CRPCTable::operator[](string name) const
2074 map<string, const CRPCCommand*>::const_iterator it = mapCommands.find(name);
2075 if (it == mapCommands.end())
2077 return (*it).second;
2083 // This ain't Apache. We're just using HTTP header for the length field
2084 // and to be compatible with other JSON-RPC implementations.
2087 string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
2090 s << "POST / HTTP/1.1\r\n"
2091 << "User-Agent: bitcoin-json-rpc/" << FormatFullVersion() << "\r\n"
2092 << "Host: 127.0.0.1\r\n"
2093 << "Content-Type: application/json\r\n"
2094 << "Content-Length: " << strMsg.size() << "\r\n"
2095 << "Connection: close\r\n"
2096 << "Accept: application/json\r\n";
2097 BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
2098 s << item.first << ": " << item.second << "\r\n";
2099 s << "\r\n" << strMsg;
2104 string rfc1123Time()
2109 struct tm* now_gmt = gmtime(&now);
2110 string locale(setlocale(LC_TIME, NULL));
2111 setlocale(LC_TIME, "C"); // we want posix (aka "C") weekday/month strings
2112 strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt);
2113 setlocale(LC_TIME, locale.c_str());
2114 return string(buffer);
2117 static string HTTPReply(int nStatus, const string& strMsg)
2120 return strprintf("HTTP/1.0 401 Authorization Required\r\n"
2122 "Server: bitcoin-json-rpc/%s\r\n"
2123 "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
2124 "Content-Type: text/html\r\n"
2125 "Content-Length: 296\r\n"
2127 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
2128 "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
2131 "<TITLE>Error</TITLE>\r\n"
2132 "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
2134 "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
2135 "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
2136 const char *cStatus;
2137 if (nStatus == 200) cStatus = "OK";
2138 else if (nStatus == 400) cStatus = "Bad Request";
2139 else if (nStatus == 403) cStatus = "Forbidden";
2140 else if (nStatus == 404) cStatus = "Not Found";
2141 else if (nStatus == 500) cStatus = "Internal Server Error";
2144 "HTTP/1.1 %d %s\r\n"
2146 "Connection: close\r\n"
2147 "Content-Length: %d\r\n"
2148 "Content-Type: application/json\r\n"
2149 "Server: bitcoin-json-rpc/%s\r\n"
2154 rfc1123Time().c_str(),
2156 FormatFullVersion().c_str(),
2160 int ReadHTTPStatus(std::basic_istream<char>& stream)
2163 getline(stream, str);
2164 vector<string> vWords;
2165 boost::split(vWords, str, boost::is_any_of(" "));
2166 if (vWords.size() < 2)
2168 return atoi(vWords[1].c_str());
2171 int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
2177 std::getline(stream, str);
2178 if (str.empty() || str == "\r")
2180 string::size_type nColon = str.find(":");
2181 if (nColon != string::npos)
2183 string strHeader = str.substr(0, nColon);
2184 boost::trim(strHeader);
2185 boost::to_lower(strHeader);
2186 string strValue = str.substr(nColon+1);
2187 boost::trim(strValue);
2188 mapHeadersRet[strHeader] = strValue;
2189 if (strHeader == "content-length")
2190 nLen = atoi(strValue.c_str());
2196 int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
2198 mapHeadersRet.clear();
2202 int nStatus = ReadHTTPStatus(stream);
2205 int nLen = ReadHTTPHeader(stream, mapHeadersRet);
2206 if (nLen < 0 || nLen > (int)MAX_SIZE)
2212 vector<char> vch(nLen);
2213 stream.read(&vch[0], nLen);
2214 strMessageRet = string(vch.begin(), vch.end());
2220 bool HTTPAuthorized(map<string, string>& mapHeaders)
2222 string strAuth = mapHeaders["authorization"];
2223 if (strAuth.substr(0,6) != "Basic ")
2225 string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
2226 string strUserPass = DecodeBase64(strUserPass64);
2227 return strUserPass == strRPCUserColonPass;
2231 // JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
2232 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
2233 // unspecified (HTTP errors and contents of 'error').
2235 // 1.0 spec: http://json-rpc.org/wiki/specification
2236 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
2237 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
2240 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
2243 request.push_back(Pair("method", strMethod));
2244 request.push_back(Pair("params", params));
2245 request.push_back(Pair("id", id));
2246 return write_string(Value(request), false) + "\n";
2249 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
2252 if (error.type() != null_type)
2253 reply.push_back(Pair("result", Value::null));
2255 reply.push_back(Pair("result", result));
2256 reply.push_back(Pair("error", error));
2257 reply.push_back(Pair("id", id));
2258 return write_string(Value(reply), false) + "\n";
2261 void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
2263 // Send error reply from json-rpc error object
2265 int code = find_value(objError, "code").get_int();
2266 if (code == -32600) nStatus = 400;
2267 else if (code == -32601) nStatus = 404;
2268 string strReply = JSONRPCReply(Value::null, objError, id);
2269 stream << HTTPReply(nStatus, strReply) << std::flush;
2272 bool ClientAllowed(const string& strAddress)
2274 if (strAddress == asio::ip::address_v4::loopback().to_string())
2276 const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
2277 BOOST_FOREACH(string strAllow, vAllow)
2278 if (WildcardMatch(strAddress, strAllow))
2284 // IOStream device that speaks SSL but can also speak non-SSL
2286 class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
2288 SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
2290 fUseSSL = fUseSSLIn;
2291 fNeedHandshake = fUseSSLIn;
2294 void handshake(ssl::stream_base::handshake_type role)
2296 if (!fNeedHandshake) return;
2297 fNeedHandshake = false;
2298 stream.handshake(role);
2300 std::streamsize read(char* s, std::streamsize n)
2302 handshake(ssl::stream_base::server); // HTTPS servers read first
2303 if (fUseSSL) return stream.read_some(asio::buffer(s, n));
2304 return stream.next_layer().read_some(asio::buffer(s, n));
2306 std::streamsize write(const char* s, std::streamsize n)
2308 handshake(ssl::stream_base::client); // HTTPS clients write first
2309 if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
2310 return asio::write(stream.next_layer(), asio::buffer(s, n));
2312 bool connect(const std::string& server, const std::string& port)
2314 ip::tcp::resolver resolver(stream.get_io_service());
2315 ip::tcp::resolver::query query(server.c_str(), port.c_str());
2316 ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
2317 ip::tcp::resolver::iterator end;
2318 boost::system::error_code error = asio::error::host_not_found;
2319 while (error && endpoint_iterator != end)
2321 stream.lowest_layer().close();
2322 stream.lowest_layer().connect(*endpoint_iterator++, error);
2330 bool fNeedHandshake;
2335 void ThreadRPCServer(void* parg)
2337 IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
2340 vnThreadsRunning[THREAD_RPCSERVER]++;
2341 ThreadRPCServer2(parg);
2342 vnThreadsRunning[THREAD_RPCSERVER]--;
2344 catch (std::exception& e) {
2345 vnThreadsRunning[THREAD_RPCSERVER]--;
2346 PrintException(&e, "ThreadRPCServer()");
2348 vnThreadsRunning[THREAD_RPCSERVER]--;
2349 PrintException(NULL, "ThreadRPCServer()");
2351 printf("ThreadRPCServer exiting\n");
2354 void ThreadRPCServer2(void* parg)
2356 printf("ThreadRPCServer started\n");
2358 strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
2359 if (mapArgs["-rpcpassword"] == "")
2361 unsigned char rand_pwd[32];
2362 RAND_bytes(rand_pwd, 32);
2363 string strWhatAmI = "To use bitcoind";
2364 if (mapArgs.count("-server"))
2365 strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
2366 else if (mapArgs.count("-daemon"))
2367 strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
2368 ThreadSafeMessageBox(strprintf(
2369 _("%s, you must set a rpcpassword in the configuration file:\n %s\n"
2370 "It is recommended you use the following random password:\n"
2371 "rpcuser=bitcoinrpc\n"
2373 "(you do not need to remember this password)\n"
2374 "If the file does not exist, create it with owner-readable-only file permissions.\n"),
2376 GetConfigFile().string().c_str(),
2377 EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str()),
2378 _("Error"), wxOK | wxMODAL);
2383 bool fUseSSL = GetBoolArg("-rpcssl");
2384 asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
2386 asio::io_service io_service;
2387 ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", 8332));
2388 ip::tcp::acceptor acceptor(io_service);
2391 acceptor.open(endpoint.protocol());
2392 acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
2393 acceptor.bind(endpoint);
2394 acceptor.listen(socket_base::max_connections);
2396 catch(boost::system::system_error &e)
2398 ThreadSafeMessageBox(strprintf(_("An error occured while setting up the RPC port %i for listening: %s"), endpoint.port(), e.what()),
2399 _("Error"), wxOK | wxMODAL);
2404 ssl::context context(io_service, ssl::context::sslv23);
2407 context.set_options(ssl::context::no_sslv2);
2409 filesystem::path pathCertFile(GetArg("-rpcsslcertificatechainfile", "server.cert"));
2410 if (!pathCertFile.is_complete()) pathCertFile = filesystem::path(GetDataDir()) / pathCertFile;
2411 if (filesystem::exists(pathCertFile)) context.use_certificate_chain_file(pathCertFile.string());
2412 else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", pathCertFile.string().c_str());
2414 filesystem::path pathPKFile(GetArg("-rpcsslprivatekeyfile", "server.pem"));
2415 if (!pathPKFile.is_complete()) pathPKFile = filesystem::path(GetDataDir()) / pathPKFile;
2416 if (filesystem::exists(pathPKFile)) context.use_private_key_file(pathPKFile.string(), ssl::context::pem);
2417 else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pathPKFile.string().c_str());
2419 string strCiphers = GetArg("-rpcsslciphers", "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
2420 SSL_CTX_set_cipher_list(context.impl(), strCiphers.c_str());
2425 // Accept connection
2426 SSLStream sslStream(io_service, context);
2427 SSLIOStreamDevice d(sslStream, fUseSSL);
2428 iostreams::stream<SSLIOStreamDevice> stream(d);
2430 ip::tcp::endpoint peer;
2431 vnThreadsRunning[THREAD_RPCSERVER]--;
2432 acceptor.accept(sslStream.lowest_layer(), peer);
2433 vnThreadsRunning[4]++;
2437 // Restrict callers by IP
2438 if (!ClientAllowed(peer.address().to_string()))
2440 // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
2442 stream << HTTPReply(403, "") << std::flush;
2446 map<string, string> mapHeaders;
2449 boost::thread api_caller(ReadHTTP, boost::ref(stream), boost::ref(mapHeaders), boost::ref(strRequest));
2450 if (!api_caller.timed_join(boost::posix_time::seconds(GetArg("-rpctimeout", 30))))
2453 printf("ThreadRPCServer ReadHTTP timeout\n");
2457 // Check authorization
2458 if (mapHeaders.count("authorization") == 0)
2460 stream << HTTPReply(401, "") << std::flush;
2463 if (!HTTPAuthorized(mapHeaders))
2465 printf("ThreadRPCServer incorrect password attempt from %s\n",peer.address().to_string().c_str());
2466 /* Deter brute-forcing short passwords.
2467 If this results in a DOS the user really
2468 shouldn't have their RPC port exposed.*/
2469 if (mapArgs["-rpcpassword"].size() < 20)
2472 stream << HTTPReply(401, "") << std::flush;
2476 Value id = Value::null;
2481 if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
2482 throw JSONRPCError(-32700, "Parse error");
2483 const Object& request = valRequest.get_obj();
2485 // Parse id now so errors from here on will have the id
2486 id = find_value(request, "id");
2489 Value valMethod = find_value(request, "method");
2490 if (valMethod.type() == null_type)
2491 throw JSONRPCError(-32600, "Missing method");
2492 if (valMethod.type() != str_type)
2493 throw JSONRPCError(-32600, "Method must be a string");
2494 string strMethod = valMethod.get_str();
2495 if (strMethod != "getwork" && strMethod != "getmemorypool")
2496 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
2499 Value valParams = find_value(request, "params");
2501 if (valParams.type() == array_type)
2502 params = valParams.get_array();
2503 else if (valParams.type() == null_type)
2506 throw JSONRPCError(-32600, "Params must be an array");
2509 const CRPCCommand *pcmd = tableRPC[strMethod];
2511 throw JSONRPCError(-32601, "Method not found");
2513 // Observe safe mode
2514 string strWarning = GetWarnings("rpc");
2515 if (strWarning != "" && !GetBoolArg("-disablesafemode") &&
2517 throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
2524 LOCK2(cs_main, pwalletMain->cs_wallet);
2525 result = pcmd->actor(params, false);
2529 string strReply = JSONRPCReply(result, Value::null, id);
2530 stream << HTTPReply(200, strReply) << std::flush;
2532 catch (std::exception& e)
2534 ErrorReply(stream, JSONRPCError(-1, e.what()), id);
2537 catch (Object& objError)
2539 ErrorReply(stream, objError, id);
2541 catch (std::exception& e)
2543 ErrorReply(stream, JSONRPCError(-32700, e.what()), id);
2551 Object CallRPC(const string& strMethod, const Array& params)
2553 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2554 throw runtime_error(strprintf(
2555 _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
2556 "If the file does not exist, create it with owner-readable-only file permissions."),
2557 GetConfigFile().string().c_str()));
2559 // Connect to localhost
2560 bool fUseSSL = GetBoolArg("-rpcssl");
2561 asio::io_service io_service;
2562 ssl::context context(io_service, ssl::context::sslv23);
2563 context.set_options(ssl::context::no_sslv2);
2564 SSLStream sslStream(io_service, context);
2565 SSLIOStreamDevice d(sslStream, fUseSSL);
2566 iostreams::stream<SSLIOStreamDevice> stream(d);
2567 if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332")))
2568 throw runtime_error("couldn't connect to server");
2570 // HTTP basic authentication
2571 string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
2572 map<string, string> mapRequestHeaders;
2573 mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
2576 string strRequest = JSONRPCRequest(strMethod, params, 1);
2577 string strPost = HTTPPost(strRequest, mapRequestHeaders);
2578 stream << strPost << std::flush;
2581 map<string, string> mapHeaders;
2583 int nStatus = ReadHTTP(stream, mapHeaders, strReply);
2585 throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
2586 else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
2587 throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
2588 else if (strReply.empty())
2589 throw runtime_error("no response from server");
2593 if (!read_string(strReply, valReply))
2594 throw runtime_error("couldn't parse reply from server");
2595 const Object& reply = valReply.get_obj();
2597 throw runtime_error("expected reply to have result, error and id properties");
2605 template<typename T>
2606 void ConvertTo(Value& value)
2608 if (value.type() == str_type)
2610 // reinterpret string as unquoted json value
2612 if (!read_string(value.get_str(), value2))
2613 throw runtime_error("type mismatch");
2614 value = value2.get_value<T>();
2618 value = value.get_value<T>();
2622 int CommandLineRPC(int argc, char *argv[])
2629 while (argc > 1 && IsSwitchChar(argv[1][0]))
2637 throw runtime_error("too few parameters");
2638 string strMethod = argv[1];
2640 // Parameters default to strings
2642 for (int i = 2; i < argc; i++)
2643 params.push_back(argv[i]);
2644 int n = params.size();
2647 // Special case non-string parameter types
2649 if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
2650 if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2651 if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
2652 if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]);
2653 if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2654 if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2655 if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2656 if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
2657 if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2658 if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
2659 if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2660 if (strMethod == "getblockhash" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2661 if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]);
2662 if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2663 if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]);
2664 if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2665 if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2666 if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2667 if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2668 if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2669 if (strMethod == "listsinceblock" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2670 if (strMethod == "sendmany" && n > 1)
2672 string s = params[1].get_str();
2674 if (!read_string(s, v) || v.type() != obj_type)
2675 throw runtime_error("type mismatch");
2676 params[1] = v.get_obj();
2678 if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2679 if (strMethod == "addmultisigaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2680 if (strMethod == "addmultisigaddress" && n > 1)
2682 string s = params[1].get_str();
2684 if (!read_string(s, v) || v.type() != array_type)
2685 throw runtime_error("type mismatch "+s);
2686 params[1] = v.get_array();
2690 Object reply = CallRPC(strMethod, params);
2693 const Value& result = find_value(reply, "result");
2694 const Value& error = find_value(reply, "error");
2696 if (error.type() != null_type)
2699 strPrint = "error: " + write_string(error, false);
2700 int code = find_value(error.get_obj(), "code").get_int();
2706 if (result.type() == null_type)
2708 else if (result.type() == str_type)
2709 strPrint = result.get_str();
2711 strPrint = write_string(result, true);
2714 catch (std::exception& e)
2716 strPrint = string("error: ") + e.what();
2721 PrintException(NULL, "CommandLineRPC()");
2726 fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
2735 int main(int argc, char *argv[])
2738 // Turn off microsoft heap dump noise
2739 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
2740 _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
2742 setbuf(stdin, NULL);
2743 setbuf(stdout, NULL);
2744 setbuf(stderr, NULL);
2748 if (argc >= 2 && string(argv[1]) == "-server")
2750 printf("server ready\n");
2751 ThreadRPCServer(NULL);
2755 return CommandLineRPC(argc, argv);
2758 catch (std::exception& e) {
2759 PrintException(&e, "main()");
2761 PrintException(NULL, "main()");
2767 const CRPCTable tableRPC;