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
1003 throw runtime_error("a multisignature address must require at least one key to redeem");
1004 if ((int)keys.size() < nRequired)
1005 throw runtime_error(
1006 strprintf("not enough keys supplied "
1007 "(got %d keys, but need at least %d to redeem)", keys.size(), nRequired));
1008 std::vector<CKey> pubkeys;
1009 pubkeys.resize(keys.size());
1010 for (unsigned int i = 0; i < keys.size(); i++)
1012 const std::string& ks = keys[i].get_str();
1014 // Case 1: bitcoin address and we have full public key:
1015 CBitcoinAddress address(ks);
1016 if (address.IsValid())
1018 if (address.IsScript())
1019 throw runtime_error(
1020 strprintf("%s is a pay-to-script address",ks.c_str()));
1021 std::vector<unsigned char> vchPubKey;
1022 if (!pwalletMain->GetPubKey(address, vchPubKey))
1023 throw runtime_error(
1024 strprintf("no full public key for address %s",ks.c_str()));
1025 if (vchPubKey.empty() || !pubkeys[i].SetPubKey(vchPubKey))
1026 throw runtime_error(" Invalid public key: "+ks);
1029 // Case 2: hex public key
1032 vector<unsigned char> vchPubKey = ParseHex(ks);
1033 if (vchPubKey.empty() || !pubkeys[i].SetPubKey(vchPubKey))
1034 throw runtime_error(" Invalid public key: "+ks);
1038 throw runtime_error(" Invalid public key: "+ks);
1042 // Construct using pay-to-script-hash:
1044 inner.SetMultisig(nRequired, pubkeys);
1046 uint160 scriptHash = Hash160(inner);
1047 CScript scriptPubKey;
1048 scriptPubKey.SetPayToScriptHash(inner);
1049 pwalletMain->AddCScript(inner);
1050 CBitcoinAddress address;
1051 address.SetScriptHash160(scriptHash);
1053 pwalletMain->SetAddressBookName(address, strAccount);
1054 return address.ToString();
1065 nConf = std::numeric_limits<int>::max();
1069 Value ListReceived(const Array& params, bool fByAccounts)
1071 // Minimum confirmations
1073 if (params.size() > 0)
1074 nMinDepth = params[0].get_int();
1076 // Whether to include empty accounts
1077 bool fIncludeEmpty = false;
1078 if (params.size() > 1)
1079 fIncludeEmpty = params[1].get_bool();
1082 map<CBitcoinAddress, tallyitem> mapTally;
1083 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1085 const CWalletTx& wtx = (*it).second;
1087 if (wtx.IsCoinBase() || !wtx.IsFinal())
1090 int nDepth = wtx.GetDepthInMainChain();
1091 if (nDepth < nMinDepth)
1094 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
1096 CBitcoinAddress address;
1097 if (!ExtractAddress(txout.scriptPubKey, address) || !pwalletMain->HaveKey(address) || !address.IsValid())
1100 tallyitem& item = mapTally[address];
1101 item.nAmount += txout.nValue;
1102 item.nConf = min(item.nConf, nDepth);
1108 map<string, tallyitem> mapAccountTally;
1109 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
1111 const CBitcoinAddress& address = item.first;
1112 const string& strAccount = item.second;
1113 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
1114 if (it == mapTally.end() && !fIncludeEmpty)
1118 int nConf = std::numeric_limits<int>::max();
1119 if (it != mapTally.end())
1121 nAmount = (*it).second.nAmount;
1122 nConf = (*it).second.nConf;
1127 tallyitem& item = mapAccountTally[strAccount];
1128 item.nAmount += nAmount;
1129 item.nConf = min(item.nConf, nConf);
1134 obj.push_back(Pair("address", address.ToString()));
1135 obj.push_back(Pair("account", strAccount));
1136 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1137 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1144 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
1146 int64 nAmount = (*it).second.nAmount;
1147 int nConf = (*it).second.nConf;
1149 obj.push_back(Pair("account", (*it).first));
1150 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1151 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1159 Value listreceivedbyaddress(const Array& params, bool fHelp)
1161 if (fHelp || params.size() > 2)
1162 throw runtime_error(
1163 "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
1164 "[minconf] is the minimum number of confirmations before payments are included.\n"
1165 "[includeempty] whether to include addresses that haven't received any payments.\n"
1166 "Returns an array of objects containing:\n"
1167 " \"address\" : receiving address\n"
1168 " \"account\" : the account of the receiving address\n"
1169 " \"amount\" : total amount received by the address\n"
1170 " \"confirmations\" : number of confirmations of the most recent transaction included");
1172 return ListReceived(params, false);
1175 Value listreceivedbyaccount(const Array& params, bool fHelp)
1177 if (fHelp || params.size() > 2)
1178 throw runtime_error(
1179 "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
1180 "[minconf] is the minimum number of confirmations before payments are included.\n"
1181 "[includeempty] whether to include accounts that haven't received any payments.\n"
1182 "Returns an array of objects containing:\n"
1183 " \"account\" : the account of the receiving addresses\n"
1184 " \"amount\" : total amount received by addresses with this account\n"
1185 " \"confirmations\" : number of confirmations of the most recent transaction included");
1187 return ListReceived(params, true);
1190 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret)
1192 int64 nGeneratedImmature, nGeneratedMature, nFee;
1193 string strSentAccount;
1194 list<pair<CBitcoinAddress, int64> > listReceived;
1195 list<pair<CBitcoinAddress, int64> > listSent;
1197 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1199 bool fAllAccounts = (strAccount == string("*"));
1201 // Generated blocks assigned to account ""
1202 if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == ""))
1205 entry.push_back(Pair("account", string("")));
1206 if (nGeneratedImmature)
1208 entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
1209 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
1213 entry.push_back(Pair("category", "generate"));
1214 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
1217 WalletTxToJSON(wtx, entry);
1218 ret.push_back(entry);
1222 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1224 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1227 entry.push_back(Pair("account", strSentAccount));
1228 entry.push_back(Pair("address", s.first.ToString()));
1229 entry.push_back(Pair("category", "send"));
1230 entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1231 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1233 WalletTxToJSON(wtx, entry);
1234 ret.push_back(entry);
1239 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1241 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1244 if (pwalletMain->mapAddressBook.count(r.first))
1245 account = pwalletMain->mapAddressBook[r.first];
1246 if (fAllAccounts || (account == strAccount))
1249 entry.push_back(Pair("account", account));
1250 entry.push_back(Pair("address", r.first.ToString()));
1251 entry.push_back(Pair("category", "receive"));
1252 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1254 WalletTxToJSON(wtx, entry);
1255 ret.push_back(entry);
1261 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1263 bool fAllAccounts = (strAccount == string("*"));
1265 if (fAllAccounts || acentry.strAccount == strAccount)
1268 entry.push_back(Pair("account", acentry.strAccount));
1269 entry.push_back(Pair("category", "move"));
1270 entry.push_back(Pair("time", (boost::int64_t)acentry.nTime));
1271 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1272 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1273 entry.push_back(Pair("comment", acentry.strComment));
1274 ret.push_back(entry);
1278 Value listtransactions(const Array& params, bool fHelp)
1280 if (fHelp || params.size() > 3)
1281 throw runtime_error(
1282 "listtransactions [account] [count=10] [from=0]\n"
1283 "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1285 string strAccount = "*";
1286 if (params.size() > 0)
1287 strAccount = params[0].get_str();
1289 if (params.size() > 1)
1290 nCount = params[1].get_int();
1292 if (params.size() > 2)
1293 nFrom = params[2].get_int();
1296 throw JSONRPCError(-8, "Negative count");
1298 throw JSONRPCError(-8, "Negative from");
1301 CWalletDB walletdb(pwalletMain->strWalletFile);
1303 // First: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap.
1304 typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
1305 typedef multimap<int64, TxPair > TxItems;
1308 // Note: maintaining indices in the database of (account,time) --> txid and (account, time) --> acentry
1309 // would make this much faster for applications that do this a lot.
1310 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1312 CWalletTx* wtx = &((*it).second);
1313 txByTime.insert(make_pair(wtx->GetTxTime(), TxPair(wtx, (CAccountingEntry*)0)));
1315 list<CAccountingEntry> acentries;
1316 walletdb.ListAccountCreditDebit(strAccount, acentries);
1317 BOOST_FOREACH(CAccountingEntry& entry, acentries)
1319 txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
1322 // iterate backwards until we have nCount items to return:
1323 for (TxItems::reverse_iterator it = txByTime.rbegin(); it != txByTime.rend(); ++it)
1325 CWalletTx *const pwtx = (*it).second.first;
1327 ListTransactions(*pwtx, strAccount, 0, true, ret);
1328 CAccountingEntry *const pacentry = (*it).second.second;
1330 AcentryToJSON(*pacentry, strAccount, ret);
1332 if (ret.size() >= (nCount+nFrom)) break;
1334 // ret is newest to oldest
1336 if (nFrom > (int)ret.size())
1338 if ((nFrom + nCount) > (int)ret.size())
1339 nCount = ret.size() - nFrom;
1340 Array::iterator first = ret.begin();
1341 std::advance(first, nFrom);
1342 Array::iterator last = ret.begin();
1343 std::advance(last, nFrom+nCount);
1345 if (last != ret.end()) ret.erase(last, ret.end());
1346 if (first != ret.begin()) ret.erase(ret.begin(), first);
1348 std::reverse(ret.begin(), ret.end()); // Return oldest to newest
1353 Value listaccounts(const Array& params, bool fHelp)
1355 if (fHelp || params.size() > 1)
1356 throw runtime_error(
1357 "listaccounts [minconf=1]\n"
1358 "Returns Object that has account names as keys, account balances as values.");
1361 if (params.size() > 0)
1362 nMinDepth = params[0].get_int();
1364 map<string, int64> mapAccountBalances;
1365 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& entry, pwalletMain->mapAddressBook) {
1366 if (pwalletMain->HaveKey(entry.first)) // This address belongs to me
1367 mapAccountBalances[entry.second] = 0;
1370 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1372 const CWalletTx& wtx = (*it).second;
1373 int64 nGeneratedImmature, nGeneratedMature, nFee;
1374 string strSentAccount;
1375 list<pair<CBitcoinAddress, int64> > listReceived;
1376 list<pair<CBitcoinAddress, int64> > listSent;
1377 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1378 mapAccountBalances[strSentAccount] -= nFee;
1379 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1380 mapAccountBalances[strSentAccount] -= s.second;
1381 if (wtx.GetDepthInMainChain() >= nMinDepth)
1383 mapAccountBalances[""] += nGeneratedMature;
1384 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1385 if (pwalletMain->mapAddressBook.count(r.first))
1386 mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1388 mapAccountBalances[""] += r.second;
1392 list<CAccountingEntry> acentries;
1393 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1394 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1395 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1398 BOOST_FOREACH(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) {
1399 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1404 Value listsinceblock(const Array& params, bool fHelp)
1407 throw runtime_error(
1408 "listsinceblock [blockhash] [target-confirmations]\n"
1409 "Get all transactions in blocks since block [blockhash], or all transactions if omitted");
1411 CBlockIndex *pindex = NULL;
1412 int target_confirms = 1;
1414 if (params.size() > 0)
1416 uint256 blockId = 0;
1418 blockId.SetHex(params[0].get_str());
1419 pindex = CBlockLocator(blockId).GetBlockIndex();
1422 if (params.size() > 1)
1424 target_confirms = params[1].get_int();
1426 if (target_confirms < 1)
1427 throw JSONRPCError(-8, "Invalid parameter");
1430 int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1;
1434 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1436 CWalletTx tx = (*it).second;
1438 if (depth == -1 || tx.GetDepthInMainChain() < depth)
1439 ListTransactions(tx, "*", 0, true, transactions);
1444 if (target_confirms == 1)
1446 lastblock = hashBestChain;
1450 int target_height = pindexBest->nHeight + 1 - target_confirms;
1453 for (block = pindexBest;
1454 block && block->nHeight > target_height;
1455 block = block->pprev) { }
1457 lastblock = block ? block->GetBlockHash() : 0;
1461 ret.push_back(Pair("transactions", transactions));
1462 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1467 Value gettransaction(const Array& params, bool fHelp)
1469 if (fHelp || params.size() != 1)
1470 throw runtime_error(
1471 "gettransaction <txid>\n"
1472 "Get detailed information about <txid>");
1475 hash.SetHex(params[0].get_str());
1479 if (!pwalletMain->mapWallet.count(hash))
1480 throw JSONRPCError(-5, "Invalid or non-wallet transaction id");
1481 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1483 int64 nCredit = wtx.GetCredit();
1484 int64 nDebit = wtx.GetDebit();
1485 int64 nNet = nCredit - nDebit;
1486 int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
1488 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1490 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1492 WalletTxToJSON(pwalletMain->mapWallet[hash], entry);
1495 ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
1496 entry.push_back(Pair("details", details));
1502 Value backupwallet(const Array& params, bool fHelp)
1504 if (fHelp || params.size() != 1)
1505 throw runtime_error(
1506 "backupwallet <destination>\n"
1507 "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1509 string strDest = params[0].get_str();
1510 BackupWallet(*pwalletMain, strDest);
1516 Value keypoolrefill(const Array& params, bool fHelp)
1518 if (pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1519 throw runtime_error(
1521 "Fills the keypool, requires wallet passphrase to be set.");
1522 if (!pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1523 throw runtime_error(
1525 "Fills the keypool.");
1527 if (pwalletMain->IsLocked())
1528 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
1530 pwalletMain->TopUpKeyPool();
1532 if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100))
1533 throw JSONRPCError(-4, "Error refreshing keypool.");
1539 void ThreadTopUpKeyPool(void* parg)
1541 pwalletMain->TopUpKeyPool();
1544 void ThreadCleanWalletPassphrase(void* parg)
1546 int64 nMyWakeTime = GetTimeMillis() + *((int64*)parg) * 1000;
1548 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1550 if (nWalletUnlockTime == 0)
1552 nWalletUnlockTime = nMyWakeTime;
1556 if (nWalletUnlockTime==0)
1558 int64 nToSleep = nWalletUnlockTime - GetTimeMillis();
1562 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1564 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1568 if (nWalletUnlockTime)
1570 nWalletUnlockTime = 0;
1571 pwalletMain->Lock();
1576 if (nWalletUnlockTime < nMyWakeTime)
1577 nWalletUnlockTime = nMyWakeTime;
1580 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1582 delete (int64*)parg;
1585 Value walletpassphrase(const Array& params, bool fHelp)
1587 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1588 throw runtime_error(
1589 "walletpassphrase <passphrase> <timeout>\n"
1590 "Stores the wallet decryption key in memory for <timeout> seconds.");
1593 if (!pwalletMain->IsCrypted())
1594 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1596 if (!pwalletMain->IsLocked())
1597 throw JSONRPCError(-17, "Error: Wallet is already unlocked.");
1599 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1600 SecureString strWalletPass;
1601 strWalletPass.reserve(100);
1602 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1603 // Alternately, find a way to make params[0] mlock()'d to begin with.
1604 strWalletPass = params[0].get_str().c_str();
1606 if (strWalletPass.length() > 0)
1608 if (!pwalletMain->Unlock(strWalletPass))
1609 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1612 throw runtime_error(
1613 "walletpassphrase <passphrase> <timeout>\n"
1614 "Stores the wallet decryption key in memory for <timeout> seconds.");
1616 CreateThread(ThreadTopUpKeyPool, NULL);
1617 int64* pnSleepTime = new int64(params[1].get_int64());
1618 CreateThread(ThreadCleanWalletPassphrase, pnSleepTime);
1624 Value walletpassphrasechange(const Array& params, bool fHelp)
1626 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1627 throw runtime_error(
1628 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1629 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1632 if (!pwalletMain->IsCrypted())
1633 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1635 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1636 // Alternately, find a way to make params[0] mlock()'d to begin with.
1637 SecureString strOldWalletPass;
1638 strOldWalletPass.reserve(100);
1639 strOldWalletPass = params[0].get_str().c_str();
1641 SecureString strNewWalletPass;
1642 strNewWalletPass.reserve(100);
1643 strNewWalletPass = params[1].get_str().c_str();
1645 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1646 throw runtime_error(
1647 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1648 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1650 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1651 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1657 Value walletlock(const Array& params, bool fHelp)
1659 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1660 throw runtime_error(
1662 "Removes the wallet encryption key from memory, locking the wallet.\n"
1663 "After calling this method, you will need to call walletpassphrase again\n"
1664 "before being able to call any methods which require the wallet to be unlocked.");
1667 if (!pwalletMain->IsCrypted())
1668 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called.");
1671 LOCK(cs_nWalletUnlockTime);
1672 pwalletMain->Lock();
1673 nWalletUnlockTime = 0;
1680 Value encryptwallet(const Array& params, bool fHelp)
1682 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1683 throw runtime_error(
1684 "encryptwallet <passphrase>\n"
1685 "Encrypts the wallet with <passphrase>.");
1688 if (pwalletMain->IsCrypted())
1689 throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
1691 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1692 // Alternately, find a way to make params[0] mlock()'d to begin with.
1693 SecureString strWalletPass;
1694 strWalletPass.reserve(100);
1695 strWalletPass = params[0].get_str().c_str();
1697 if (strWalletPass.length() < 1)
1698 throw runtime_error(
1699 "encryptwallet <passphrase>\n"
1700 "Encrypts the wallet with <passphrase>.");
1702 if (!pwalletMain->EncryptWallet(strWalletPass))
1703 throw JSONRPCError(-16, "Error: Failed to encrypt the wallet.");
1705 // BDB seems to have a bad habit of writing old data into
1706 // slack space in .dat files; that is bad if the old data is
1707 // unencrypted private keys. So:
1709 return "wallet encrypted; bitcoin server stopping, restart to run with encrypted wallet";
1713 Value validateaddress(const Array& params, bool fHelp)
1715 if (fHelp || params.size() != 1)
1716 throw runtime_error(
1717 "validateaddress <bitcoinaddress>\n"
1718 "Return information about <bitcoinaddress>.");
1720 CBitcoinAddress address(params[0].get_str());
1721 bool isValid = address.IsValid();
1724 ret.push_back(Pair("isvalid", isValid));
1727 // Call Hash160ToAddress() so we always return current ADDRESSVERSION
1728 // version of the address:
1729 string currentAddress = address.ToString();
1730 ret.push_back(Pair("address", currentAddress));
1731 if (pwalletMain->HaveKey(address))
1733 ret.push_back(Pair("ismine", true));
1734 std::vector<unsigned char> vchPubKey;
1735 pwalletMain->GetPubKey(address, vchPubKey);
1736 ret.push_back(Pair("pubkey", HexStr(vchPubKey)));
1738 key.SetPubKey(vchPubKey);
1739 ret.push_back(Pair("iscompressed", key.IsCompressed()));
1741 else if (pwalletMain->HaveCScript(address.GetHash160()))
1743 ret.push_back(Pair("isscript", true));
1745 pwalletMain->GetCScript(address.GetHash160(), subscript);
1746 ret.push_back(Pair("ismine", ::IsMine(*pwalletMain, subscript)));
1747 std::vector<CBitcoinAddress> addresses;
1748 txnouttype whichType;
1750 ExtractAddresses(subscript, whichType, addresses, nRequired);
1751 ret.push_back(Pair("script", GetTxnOutputType(whichType)));
1753 BOOST_FOREACH(const CBitcoinAddress& addr, addresses)
1754 a.push_back(addr.ToString());
1755 ret.push_back(Pair("addresses", a));
1756 if (whichType == TX_MULTISIG)
1757 ret.push_back(Pair("sigsrequired", nRequired));
1760 ret.push_back(Pair("ismine", false));
1761 if (pwalletMain->mapAddressBook.count(address))
1762 ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
1767 Value getwork(const Array& params, bool fHelp)
1769 if (fHelp || params.size() > 1)
1770 throw runtime_error(
1772 "If [data] is not specified, returns formatted hash data to work on:\n"
1773 " \"midstate\" : precomputed hash state after hashing the first half of the data (DEPRECATED)\n" // deprecated
1774 " \"data\" : block data\n"
1775 " \"hash1\" : formatted hash buffer for second hash (DEPRECATED)\n" // deprecated
1776 " \"target\" : little endian hash target\n"
1777 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1780 throw JSONRPCError(-9, "Bitcoin is not connected!");
1782 if (IsInitialBlockDownload())
1783 throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
1785 typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
1786 static mapNewBlock_t mapNewBlock;
1787 static vector<CBlock*> vNewBlock;
1788 static CReserveKey reservekey(pwalletMain);
1790 if (params.size() == 0)
1793 static unsigned int nTransactionsUpdatedLast;
1794 static CBlockIndex* pindexPrev;
1795 static int64 nStart;
1796 static CBlock* pblock;
1797 if (pindexPrev != pindexBest ||
1798 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
1800 if (pindexPrev != pindexBest)
1802 // Deallocate old blocks since they're obsolete now
1803 mapNewBlock.clear();
1804 BOOST_FOREACH(CBlock* pblock, vNewBlock)
1808 nTransactionsUpdatedLast = nTransactionsUpdated;
1809 pindexPrev = pindexBest;
1813 pblock = CreateNewBlock(reservekey);
1815 throw JSONRPCError(-7, "Out of memory");
1816 vNewBlock.push_back(pblock);
1820 pblock->UpdateTime(pindexPrev);
1823 // Update nExtraNonce
1824 static unsigned int nExtraNonce = 0;
1825 IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
1828 mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
1830 // Prebuild hash buffers
1834 FormatHashBuffers(pblock, pmidstate, pdata, phash1);
1836 uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
1839 result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate)))); // deprecated
1840 result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata))));
1841 result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1)))); // deprecated
1842 result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
1848 vector<unsigned char> vchData = ParseHex(params[0].get_str());
1849 if (vchData.size() != 128)
1850 throw JSONRPCError(-8, "Invalid parameter");
1851 CBlock* pdata = (CBlock*)&vchData[0];
1854 for (int i = 0; i < 128/4; i++)
1855 ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]);
1858 if (!mapNewBlock.count(pdata->hashMerkleRoot))
1860 CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
1862 pblock->nTime = pdata->nTime;
1863 pblock->nNonce = pdata->nNonce;
1864 pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
1865 pblock->hashMerkleRoot = pblock->BuildMerkleTree();
1867 return CheckWork(pblock, *pwalletMain, reservekey);
1872 Value getmemorypool(const Array& params, bool fHelp)
1874 if (fHelp || params.size() > 1)
1875 throw runtime_error(
1876 "getmemorypool [data]\n"
1877 "If [data] is not specified, returns data needed to construct a block to work on:\n"
1878 " \"version\" : block version\n"
1879 " \"previousblockhash\" : hash of current highest block\n"
1880 " \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
1881 " \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
1882 " \"coinbaseflags\" : data that should be included in coinbase so support for new features can be judged\n"
1883 " \"time\" : timestamp appropriate for next block\n"
1884 " \"mintime\" : minimum timestamp appropriate for next block\n"
1885 " \"curtime\" : current timestamp\n"
1886 " \"bits\" : compressed target of next block\n"
1887 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1889 if (params.size() == 0)
1892 throw JSONRPCError(-9, "Bitcoin is not connected!");
1894 if (IsInitialBlockDownload())
1895 throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
1897 static CReserveKey reservekey(pwalletMain);
1900 static unsigned int nTransactionsUpdatedLast;
1901 static CBlockIndex* pindexPrev;
1902 static int64 nStart;
1903 static CBlock* pblock;
1904 if (pindexPrev != pindexBest ||
1905 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5))
1907 nTransactionsUpdatedLast = nTransactionsUpdated;
1908 pindexPrev = pindexBest;
1914 pblock = CreateNewBlock(reservekey);
1916 throw JSONRPCError(-7, "Out of memory");
1920 pblock->UpdateTime(pindexPrev);
1924 BOOST_FOREACH(CTransaction tx, pblock->vtx) {
1928 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
1931 transactions.push_back(HexStr(ssTx.begin(), ssTx.end()));
1935 result.push_back(Pair("version", pblock->nVersion));
1936 result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
1937 result.push_back(Pair("transactions", transactions));
1938 result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
1939 result.push_back(Pair("coinbaseflags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end())));
1940 result.push_back(Pair("time", (int64_t)pblock->nTime));
1941 result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1));
1942 result.push_back(Pair("curtime", (int64_t)GetAdjustedTime()));
1943 result.push_back(Pair("bits", HexBits(pblock->nBits)));
1950 CDataStream ssBlock(ParseHex(params[0].get_str()), SER_NETWORK, PROTOCOL_VERSION);
1954 return ProcessBlock(NULL, &pblock);
1958 Value getblockhash(const Array& params, bool fHelp)
1960 if (fHelp || params.size() != 1)
1961 throw runtime_error(
1962 "getblockhash <index>\n"
1963 "Returns hash of block in best-block-chain at <index>.");
1965 int nHeight = params[0].get_int();
1966 if (nHeight < 0 || nHeight > nBestHeight)
1967 throw runtime_error("Block number out of range.");
1970 CBlockIndex* pblockindex = mapBlockIndex[hashBestChain];
1971 while (pblockindex->nHeight > nHeight)
1972 pblockindex = pblockindex->pprev;
1973 return pblockindex->phashBlock->GetHex();
1976 Value getblock(const Array& params, bool fHelp)
1978 if (fHelp || params.size() != 1)
1979 throw runtime_error(
1981 "Returns details of a block with given block-hash.");
1983 std::string strHash = params[0].get_str();
1984 uint256 hash(strHash);
1986 if (mapBlockIndex.count(hash) == 0)
1987 throw JSONRPCError(-5, "Block not found");
1990 CBlockIndex* pblockindex = mapBlockIndex[hash];
1991 block.ReadFromDisk(pblockindex, true);
1993 return blockToJSON(block, pblockindex);
2011 static const CRPCCommand vRPCCommands[] =
2012 { // name function safe mode?
2013 // ------------------------ ----------------------- ----------
2014 { "help", &help, true },
2015 { "stop", &stop, true },
2016 { "getblockcount", &getblockcount, true },
2017 { "getblocknumber", &getblocknumber, true },
2018 { "getconnectioncount", &getconnectioncount, true },
2019 { "getdifficulty", &getdifficulty, true },
2020 { "getgenerate", &getgenerate, true },
2021 { "setgenerate", &setgenerate, true },
2022 { "gethashespersec", &gethashespersec, true },
2023 { "getinfo", &getinfo, true },
2024 { "getmininginfo", &getmininginfo, true },
2025 { "getnewaddress", &getnewaddress, true },
2026 { "getaccountaddress", &getaccountaddress, true },
2027 { "setaccount", &setaccount, true },
2028 { "getaccount", &getaccount, false },
2029 { "getaddressesbyaccount", &getaddressesbyaccount, true },
2030 { "sendtoaddress", &sendtoaddress, false },
2031 { "getreceivedbyaddress", &getreceivedbyaddress, false },
2032 { "getreceivedbyaccount", &getreceivedbyaccount, false },
2033 { "listreceivedbyaddress", &listreceivedbyaddress, false },
2034 { "listreceivedbyaccount", &listreceivedbyaccount, false },
2035 { "backupwallet", &backupwallet, true },
2036 { "keypoolrefill", &keypoolrefill, true },
2037 { "walletpassphrase", &walletpassphrase, true },
2038 { "walletpassphrasechange", &walletpassphrasechange, false },
2039 { "walletlock", &walletlock, true },
2040 { "encryptwallet", &encryptwallet, false },
2041 { "validateaddress", &validateaddress, true },
2042 { "getbalance", &getbalance, false },
2043 { "move", &movecmd, false },
2044 { "sendfrom", &sendfrom, false },
2045 { "sendmany", &sendmany, false },
2046 { "addmultisigaddress", &addmultisigaddress, false },
2047 { "getblock", &getblock, false },
2048 { "getblockhash", &getblockhash, false },
2049 { "gettransaction", &gettransaction, false },
2050 { "listtransactions", &listtransactions, false },
2051 { "signmessage", &signmessage, false },
2052 { "verifymessage", &verifymessage, false },
2053 { "getwork", &getwork, true },
2054 { "listaccounts", &listaccounts, false },
2055 { "settxfee", &settxfee, false },
2056 { "getmemorypool", &getmemorypool, true },
2057 { "listsinceblock", &listsinceblock, false },
2058 { "dumpprivkey", &dumpprivkey, false },
2059 { "importprivkey", &importprivkey, false },
2062 CRPCTable::CRPCTable()
2065 for (vcidx = 0; vcidx < (sizeof(vRPCCommands) / sizeof(vRPCCommands[0])); vcidx++)
2067 const CRPCCommand *pcmd;
2069 pcmd = &vRPCCommands[vcidx];
2070 mapCommands[pcmd->name] = pcmd;
2074 const CRPCCommand *CRPCTable::operator[](string name) const
2076 map<string, const CRPCCommand*>::const_iterator it = mapCommands.find(name);
2077 if (it == mapCommands.end())
2079 return (*it).second;
2085 // This ain't Apache. We're just using HTTP header for the length field
2086 // and to be compatible with other JSON-RPC implementations.
2089 string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
2092 s << "POST / HTTP/1.1\r\n"
2093 << "User-Agent: bitcoin-json-rpc/" << FormatFullVersion() << "\r\n"
2094 << "Host: 127.0.0.1\r\n"
2095 << "Content-Type: application/json\r\n"
2096 << "Content-Length: " << strMsg.size() << "\r\n"
2097 << "Connection: close\r\n"
2098 << "Accept: application/json\r\n";
2099 BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
2100 s << item.first << ": " << item.second << "\r\n";
2101 s << "\r\n" << strMsg;
2106 string rfc1123Time()
2111 struct tm* now_gmt = gmtime(&now);
2112 string locale(setlocale(LC_TIME, NULL));
2113 setlocale(LC_TIME, "C"); // we want posix (aka "C") weekday/month strings
2114 strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt);
2115 setlocale(LC_TIME, locale.c_str());
2116 return string(buffer);
2119 static string HTTPReply(int nStatus, const string& strMsg)
2122 return strprintf("HTTP/1.0 401 Authorization Required\r\n"
2124 "Server: bitcoin-json-rpc/%s\r\n"
2125 "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
2126 "Content-Type: text/html\r\n"
2127 "Content-Length: 296\r\n"
2129 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
2130 "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
2133 "<TITLE>Error</TITLE>\r\n"
2134 "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
2136 "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
2137 "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
2138 const char *cStatus;
2139 if (nStatus == 200) cStatus = "OK";
2140 else if (nStatus == 400) cStatus = "Bad Request";
2141 else if (nStatus == 403) cStatus = "Forbidden";
2142 else if (nStatus == 404) cStatus = "Not Found";
2143 else if (nStatus == 500) cStatus = "Internal Server Error";
2146 "HTTP/1.1 %d %s\r\n"
2148 "Connection: close\r\n"
2149 "Content-Length: %d\r\n"
2150 "Content-Type: application/json\r\n"
2151 "Server: bitcoin-json-rpc/%s\r\n"
2156 rfc1123Time().c_str(),
2158 FormatFullVersion().c_str(),
2162 int ReadHTTPStatus(std::basic_istream<char>& stream)
2165 getline(stream, str);
2166 vector<string> vWords;
2167 boost::split(vWords, str, boost::is_any_of(" "));
2168 if (vWords.size() < 2)
2170 return atoi(vWords[1].c_str());
2173 int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
2179 std::getline(stream, str);
2180 if (str.empty() || str == "\r")
2182 string::size_type nColon = str.find(":");
2183 if (nColon != string::npos)
2185 string strHeader = str.substr(0, nColon);
2186 boost::trim(strHeader);
2187 boost::to_lower(strHeader);
2188 string strValue = str.substr(nColon+1);
2189 boost::trim(strValue);
2190 mapHeadersRet[strHeader] = strValue;
2191 if (strHeader == "content-length")
2192 nLen = atoi(strValue.c_str());
2198 int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
2200 mapHeadersRet.clear();
2204 int nStatus = ReadHTTPStatus(stream);
2207 int nLen = ReadHTTPHeader(stream, mapHeadersRet);
2208 if (nLen < 0 || nLen > (int)MAX_SIZE)
2214 vector<char> vch(nLen);
2215 stream.read(&vch[0], nLen);
2216 strMessageRet = string(vch.begin(), vch.end());
2222 bool HTTPAuthorized(map<string, string>& mapHeaders)
2224 string strAuth = mapHeaders["authorization"];
2225 if (strAuth.substr(0,6) != "Basic ")
2227 string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
2228 string strUserPass = DecodeBase64(strUserPass64);
2229 return strUserPass == strRPCUserColonPass;
2233 // JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
2234 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
2235 // unspecified (HTTP errors and contents of 'error').
2237 // 1.0 spec: http://json-rpc.org/wiki/specification
2238 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
2239 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
2242 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
2245 request.push_back(Pair("method", strMethod));
2246 request.push_back(Pair("params", params));
2247 request.push_back(Pair("id", id));
2248 return write_string(Value(request), false) + "\n";
2251 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
2254 if (error.type() != null_type)
2255 reply.push_back(Pair("result", Value::null));
2257 reply.push_back(Pair("result", result));
2258 reply.push_back(Pair("error", error));
2259 reply.push_back(Pair("id", id));
2260 return write_string(Value(reply), false) + "\n";
2263 void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
2265 // Send error reply from json-rpc error object
2267 int code = find_value(objError, "code").get_int();
2268 if (code == -32600) nStatus = 400;
2269 else if (code == -32601) nStatus = 404;
2270 string strReply = JSONRPCReply(Value::null, objError, id);
2271 stream << HTTPReply(nStatus, strReply) << std::flush;
2274 bool ClientAllowed(const string& strAddress)
2276 if (strAddress == asio::ip::address_v4::loopback().to_string())
2278 const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
2279 BOOST_FOREACH(string strAllow, vAllow)
2280 if (WildcardMatch(strAddress, strAllow))
2286 // IOStream device that speaks SSL but can also speak non-SSL
2288 class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
2290 SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
2292 fUseSSL = fUseSSLIn;
2293 fNeedHandshake = fUseSSLIn;
2296 void handshake(ssl::stream_base::handshake_type role)
2298 if (!fNeedHandshake) return;
2299 fNeedHandshake = false;
2300 stream.handshake(role);
2302 std::streamsize read(char* s, std::streamsize n)
2304 handshake(ssl::stream_base::server); // HTTPS servers read first
2305 if (fUseSSL) return stream.read_some(asio::buffer(s, n));
2306 return stream.next_layer().read_some(asio::buffer(s, n));
2308 std::streamsize write(const char* s, std::streamsize n)
2310 handshake(ssl::stream_base::client); // HTTPS clients write first
2311 if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
2312 return asio::write(stream.next_layer(), asio::buffer(s, n));
2314 bool connect(const std::string& server, const std::string& port)
2316 ip::tcp::resolver resolver(stream.get_io_service());
2317 ip::tcp::resolver::query query(server.c_str(), port.c_str());
2318 ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
2319 ip::tcp::resolver::iterator end;
2320 boost::system::error_code error = asio::error::host_not_found;
2321 while (error && endpoint_iterator != end)
2323 stream.lowest_layer().close();
2324 stream.lowest_layer().connect(*endpoint_iterator++, error);
2332 bool fNeedHandshake;
2337 void ThreadRPCServer(void* parg)
2339 IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
2342 vnThreadsRunning[THREAD_RPCSERVER]++;
2343 ThreadRPCServer2(parg);
2344 vnThreadsRunning[THREAD_RPCSERVER]--;
2346 catch (std::exception& e) {
2347 vnThreadsRunning[THREAD_RPCSERVER]--;
2348 PrintException(&e, "ThreadRPCServer()");
2350 vnThreadsRunning[THREAD_RPCSERVER]--;
2351 PrintException(NULL, "ThreadRPCServer()");
2353 printf("ThreadRPCServer exiting\n");
2356 void ThreadRPCServer2(void* parg)
2358 printf("ThreadRPCServer started\n");
2360 strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
2361 if (mapArgs["-rpcpassword"] == "")
2363 unsigned char rand_pwd[32];
2364 RAND_bytes(rand_pwd, 32);
2365 string strWhatAmI = "To use bitcoind";
2366 if (mapArgs.count("-server"))
2367 strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
2368 else if (mapArgs.count("-daemon"))
2369 strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
2370 ThreadSafeMessageBox(strprintf(
2371 _("%s, you must set a rpcpassword in the configuration file:\n %s\n"
2372 "It is recommended you use the following random password:\n"
2373 "rpcuser=bitcoinrpc\n"
2375 "(you do not need to remember this password)\n"
2376 "If the file does not exist, create it with owner-readable-only file permissions.\n"),
2378 GetConfigFile().string().c_str(),
2379 EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str()),
2380 _("Error"), wxOK | wxMODAL);
2385 bool fUseSSL = GetBoolArg("-rpcssl");
2386 asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
2388 asio::io_service io_service;
2389 ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", 8332));
2390 ip::tcp::acceptor acceptor(io_service);
2393 acceptor.open(endpoint.protocol());
2394 acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
2395 acceptor.bind(endpoint);
2396 acceptor.listen(socket_base::max_connections);
2398 catch(boost::system::system_error &e)
2400 ThreadSafeMessageBox(strprintf(_("An error occured while setting up the RPC port %i for listening: %s"), endpoint.port(), e.what()),
2401 _("Error"), wxOK | wxMODAL);
2406 ssl::context context(io_service, ssl::context::sslv23);
2409 context.set_options(ssl::context::no_sslv2);
2411 filesystem::path pathCertFile(GetArg("-rpcsslcertificatechainfile", "server.cert"));
2412 if (!pathCertFile.is_complete()) pathCertFile = filesystem::path(GetDataDir()) / pathCertFile;
2413 if (filesystem::exists(pathCertFile)) context.use_certificate_chain_file(pathCertFile.string());
2414 else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", pathCertFile.string().c_str());
2416 filesystem::path pathPKFile(GetArg("-rpcsslprivatekeyfile", "server.pem"));
2417 if (!pathPKFile.is_complete()) pathPKFile = filesystem::path(GetDataDir()) / pathPKFile;
2418 if (filesystem::exists(pathPKFile)) context.use_private_key_file(pathPKFile.string(), ssl::context::pem);
2419 else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pathPKFile.string().c_str());
2421 string strCiphers = GetArg("-rpcsslciphers", "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
2422 SSL_CTX_set_cipher_list(context.impl(), strCiphers.c_str());
2427 // Accept connection
2428 SSLStream sslStream(io_service, context);
2429 SSLIOStreamDevice d(sslStream, fUseSSL);
2430 iostreams::stream<SSLIOStreamDevice> stream(d);
2432 ip::tcp::endpoint peer;
2433 vnThreadsRunning[THREAD_RPCSERVER]--;
2434 acceptor.accept(sslStream.lowest_layer(), peer);
2435 vnThreadsRunning[4]++;
2439 // Restrict callers by IP
2440 if (!ClientAllowed(peer.address().to_string()))
2442 // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
2444 stream << HTTPReply(403, "") << std::flush;
2448 map<string, string> mapHeaders;
2451 boost::thread api_caller(ReadHTTP, boost::ref(stream), boost::ref(mapHeaders), boost::ref(strRequest));
2452 if (!api_caller.timed_join(boost::posix_time::seconds(GetArg("-rpctimeout", 30))))
2455 printf("ThreadRPCServer ReadHTTP timeout\n");
2459 // Check authorization
2460 if (mapHeaders.count("authorization") == 0)
2462 stream << HTTPReply(401, "") << std::flush;
2465 if (!HTTPAuthorized(mapHeaders))
2467 printf("ThreadRPCServer incorrect password attempt from %s\n",peer.address().to_string().c_str());
2468 /* Deter brute-forcing short passwords.
2469 If this results in a DOS the user really
2470 shouldn't have their RPC port exposed.*/
2471 if (mapArgs["-rpcpassword"].size() < 20)
2474 stream << HTTPReply(401, "") << std::flush;
2478 Value id = Value::null;
2483 if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
2484 throw JSONRPCError(-32700, "Parse error");
2485 const Object& request = valRequest.get_obj();
2487 // Parse id now so errors from here on will have the id
2488 id = find_value(request, "id");
2491 Value valMethod = find_value(request, "method");
2492 if (valMethod.type() == null_type)
2493 throw JSONRPCError(-32600, "Missing method");
2494 if (valMethod.type() != str_type)
2495 throw JSONRPCError(-32600, "Method must be a string");
2496 string strMethod = valMethod.get_str();
2497 if (strMethod != "getwork" && strMethod != "getmemorypool")
2498 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
2501 Value valParams = find_value(request, "params");
2503 if (valParams.type() == array_type)
2504 params = valParams.get_array();
2505 else if (valParams.type() == null_type)
2508 throw JSONRPCError(-32600, "Params must be an array");
2511 const CRPCCommand *pcmd = tableRPC[strMethod];
2513 throw JSONRPCError(-32601, "Method not found");
2515 // Observe safe mode
2516 string strWarning = GetWarnings("rpc");
2517 if (strWarning != "" && !GetBoolArg("-disablesafemode") &&
2519 throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
2526 LOCK2(cs_main, pwalletMain->cs_wallet);
2527 result = pcmd->actor(params, false);
2531 string strReply = JSONRPCReply(result, Value::null, id);
2532 stream << HTTPReply(200, strReply) << std::flush;
2534 catch (std::exception& e)
2536 ErrorReply(stream, JSONRPCError(-1, e.what()), id);
2539 catch (Object& objError)
2541 ErrorReply(stream, objError, id);
2543 catch (std::exception& e)
2545 ErrorReply(stream, JSONRPCError(-32700, e.what()), id);
2553 Object CallRPC(const string& strMethod, const Array& params)
2555 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2556 throw runtime_error(strprintf(
2557 _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
2558 "If the file does not exist, create it with owner-readable-only file permissions."),
2559 GetConfigFile().string().c_str()));
2561 // Connect to localhost
2562 bool fUseSSL = GetBoolArg("-rpcssl");
2563 asio::io_service io_service;
2564 ssl::context context(io_service, ssl::context::sslv23);
2565 context.set_options(ssl::context::no_sslv2);
2566 SSLStream sslStream(io_service, context);
2567 SSLIOStreamDevice d(sslStream, fUseSSL);
2568 iostreams::stream<SSLIOStreamDevice> stream(d);
2569 if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332")))
2570 throw runtime_error("couldn't connect to server");
2572 // HTTP basic authentication
2573 string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
2574 map<string, string> mapRequestHeaders;
2575 mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
2578 string strRequest = JSONRPCRequest(strMethod, params, 1);
2579 string strPost = HTTPPost(strRequest, mapRequestHeaders);
2580 stream << strPost << std::flush;
2583 map<string, string> mapHeaders;
2585 int nStatus = ReadHTTP(stream, mapHeaders, strReply);
2587 throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
2588 else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
2589 throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
2590 else if (strReply.empty())
2591 throw runtime_error("no response from server");
2595 if (!read_string(strReply, valReply))
2596 throw runtime_error("couldn't parse reply from server");
2597 const Object& reply = valReply.get_obj();
2599 throw runtime_error("expected reply to have result, error and id properties");
2607 template<typename T>
2608 void ConvertTo(Value& value)
2610 if (value.type() == str_type)
2612 // reinterpret string as unquoted json value
2614 if (!read_string(value.get_str(), value2))
2615 throw runtime_error("type mismatch");
2616 value = value2.get_value<T>();
2620 value = value.get_value<T>();
2624 int CommandLineRPC(int argc, char *argv[])
2631 while (argc > 1 && IsSwitchChar(argv[1][0]))
2639 throw runtime_error("too few parameters");
2640 string strMethod = argv[1];
2642 // Parameters default to strings
2644 for (int i = 2; i < argc; i++)
2645 params.push_back(argv[i]);
2646 int n = params.size();
2649 // Special case non-string parameter types
2651 if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
2652 if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2653 if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
2654 if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]);
2655 if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2656 if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2657 if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2658 if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
2659 if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2660 if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
2661 if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2662 if (strMethod == "getblockhash" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2663 if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]);
2664 if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2665 if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]);
2666 if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2667 if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2668 if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2669 if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2670 if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2671 if (strMethod == "listsinceblock" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2672 if (strMethod == "sendmany" && n > 1)
2674 string s = params[1].get_str();
2676 if (!read_string(s, v) || v.type() != obj_type)
2677 throw runtime_error("type mismatch");
2678 params[1] = v.get_obj();
2680 if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2681 if (strMethod == "addmultisigaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2682 if (strMethod == "addmultisigaddress" && n > 1)
2684 string s = params[1].get_str();
2686 if (!read_string(s, v) || v.type() != array_type)
2687 throw runtime_error("type mismatch "+s);
2688 params[1] = v.get_array();
2692 Object reply = CallRPC(strMethod, params);
2695 const Value& result = find_value(reply, "result");
2696 const Value& error = find_value(reply, "error");
2698 if (error.type() != null_type)
2701 strPrint = "error: " + write_string(error, false);
2702 int code = find_value(error.get_obj(), "code").get_int();
2708 if (result.type() == null_type)
2710 else if (result.type() == str_type)
2711 strPrint = result.get_str();
2713 strPrint = write_string(result, true);
2716 catch (std::exception& e)
2718 strPrint = string("error: ") + e.what();
2723 PrintException(NULL, "CommandLineRPC()");
2728 fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
2737 int main(int argc, char *argv[])
2740 // Turn off microsoft heap dump noise
2741 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
2742 _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
2744 setbuf(stdin, NULL);
2745 setbuf(stdout, NULL);
2746 setbuf(stderr, NULL);
2750 if (argc >= 2 && string(argv[1]) == "-server")
2752 printf("server ready\n");
2753 ThreadRPCServer(NULL);
2757 return CommandLineRPC(argc, argv);
2760 catch (std::exception& e) {
2761 PrintException(&e, "main()");
2763 PrintException(NULL, "main()");
2769 const CRPCTable tableRPC;