1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Copyright (c) 2011 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.
7 #include "cryptopp/sha.h"
12 #include <boost/asio.hpp>
13 #include <boost/iostreams/concepts.hpp>
14 #include <boost/iostreams/stream.hpp>
15 #include <boost/algorithm/string.hpp>
17 #include <boost/asio/ssl.hpp>
18 #include <boost/filesystem.hpp>
19 #include <boost/filesystem/fstream.hpp>
20 typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> SSLStream;
22 #include "json/json_spirit_reader_template.h"
23 #include "json/json_spirit_writer_template.h"
24 #include "json/json_spirit_utils.h"
25 #define printf OutputDebugStringF
26 // MinGW 3.4.5 gets "fatal error: had to relocate PCH" if the json headers are
27 // precompiled in headers.h. The problem might be when the pch file goes over
28 // a certain size around 145MB. If we need access to json_spirit outside this
29 // file, we could use the compiled json_spirit option.
32 using namespace boost;
33 using namespace boost::asio;
34 using namespace json_spirit;
36 void ThreadRPCServer2(void* parg);
37 typedef Value(*rpcfn_type)(const Array& params, bool fHelp);
38 extern map<string, rpcfn_type> mapCallTable;
40 static int64 nWalletUnlockTime;
41 static CCriticalSection cs_nWalletUnlockTime;
44 Object JSONRPCError(int code, const string& message)
47 error.push_back(Pair("code", code));
48 error.push_back(Pair("message", message));
53 void PrintConsole(const std::string &format, ...)
56 int limit = sizeof(buffer);
58 va_start(arg_ptr, format);
59 int ret = _vsnprintf(buffer, limit, format.c_str(), arg_ptr);
61 if (ret < 0 || ret >= limit)
67 fprintf(stdout, "%s", buffer);
71 int64 AmountFromValue(const Value& value)
73 double dAmount = value.get_real();
74 if (dAmount <= 0.0 || dAmount > 21000000.0)
75 throw JSONRPCError(-3, "Invalid amount");
76 int64 nAmount = roundint64(dAmount * COIN);
77 if (!MoneyRange(nAmount))
78 throw JSONRPCError(-3, "Invalid amount");
82 Value ValueFromAmount(int64 amount)
84 return (double)amount / (double)COIN;
87 void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
89 entry.push_back(Pair("confirmations", wtx.GetDepthInMainChain()));
90 entry.push_back(Pair("txid", wtx.GetHash().GetHex()));
91 entry.push_back(Pair("time", (boost::int64_t)wtx.GetTxTime()));
92 BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
93 entry.push_back(Pair(item.first, item.second));
96 string AccountFromValue(const Value& value)
98 string strAccount = value.get_str();
99 if (strAccount == "*")
100 throw JSONRPCError(-11, "Invalid account name");
107 /// Note: This interface may still be subject to change.
111 Value help(const Array& params, bool fHelp)
113 if (fHelp || params.size() > 1)
116 "List commands, or get help for a command.");
119 if (params.size() > 0)
120 strCommand = params[0].get_str();
123 set<rpcfn_type> setDone;
124 for (map<string, rpcfn_type>::iterator mi = mapCallTable.begin(); mi != mapCallTable.end(); ++mi)
126 string strMethod = (*mi).first;
127 // We already filter duplicates, but these deprecated screw up the sort order
128 if (strMethod == "getamountreceived" ||
129 strMethod == "getallreceived" ||
130 (strMethod.find("label") != string::npos))
132 if (strCommand != "" && strMethod != strCommand)
137 rpcfn_type pfn = (*mi).second;
138 if (setDone.insert(pfn).second)
139 (*pfn)(params, true);
141 catch (std::exception& e)
143 // Help text is returned in an exception
144 string strHelp = string(e.what());
145 if (strCommand == "")
146 if (strHelp.find('\n') != -1)
147 strHelp = strHelp.substr(0, strHelp.find('\n'));
148 strRet += strHelp + "\n";
152 strRet = strprintf("help: unknown command: %s\n", strCommand.c_str());
153 strRet = strRet.substr(0,strRet.size()-1);
158 Value stop(const Array& params, bool fHelp)
160 if (fHelp || params.size() != 0)
163 "Stop bitcoin server.");
165 // Shutdown will take long enough that the response should get back
166 CreateThread(Shutdown, NULL);
167 return "bitcoin server stopping";
171 Value getblockcount(const Array& params, bool fHelp)
173 if (fHelp || params.size() != 0)
176 "Returns the number of blocks in the longest block chain.");
182 Value getblocknumber(const Array& params, bool fHelp)
184 if (fHelp || params.size() != 0)
187 "Returns the block number of the latest block in the longest block chain.");
193 Value getconnectioncount(const Array& params, bool fHelp)
195 if (fHelp || params.size() != 0)
197 "getconnectioncount\n"
198 "Returns the number of connections to other nodes.");
200 return (int)vNodes.size();
204 double GetDifficulty()
206 // Floating point number that is a multiple of the minimum difficulty,
207 // minimum difficulty = 1.0.
209 if (pindexBest == NULL)
211 int nShift = (pindexBest->nBits >> 24) & 0xff;
214 (double)0x0000ffff / (double)(pindexBest->nBits & 0x00ffffff);
230 Value getdifficulty(const Array& params, bool fHelp)
232 if (fHelp || params.size() != 0)
235 "Returns the proof-of-work difficulty as a multiple of the minimum difficulty.");
237 return GetDifficulty();
241 Value getgenerate(const Array& params, bool fHelp)
243 if (fHelp || params.size() != 0)
246 "Returns true or false.");
248 return (bool)fGenerateBitcoins;
252 Value setgenerate(const Array& params, bool fHelp)
254 if (fHelp || params.size() < 1 || params.size() > 2)
256 "setgenerate <generate> [genproclimit]\n"
257 "<generate> is true or false to turn generation on or off.\n"
258 "Generation is limited to [genproclimit] processors, -1 is unlimited.");
260 bool fGenerate = true;
261 if (params.size() > 0)
262 fGenerate = params[0].get_bool();
264 if (params.size() > 1)
266 int nGenProcLimit = params[1].get_int();
267 fLimitProcessors = (nGenProcLimit != -1);
268 WriteSetting("fLimitProcessors", fLimitProcessors);
269 if (nGenProcLimit != -1)
270 WriteSetting("nLimitProcessors", nLimitProcessors = nGenProcLimit);
271 if (nGenProcLimit == 0)
275 GenerateBitcoins(fGenerate, pwalletMain);
280 Value gethashespersec(const Array& params, bool fHelp)
282 if (fHelp || params.size() != 0)
285 "Returns a recent hashes per second performance measurement while generating.");
287 if (GetTimeMillis() - nHPSTimerStart > 8000)
288 return (boost::int64_t)0;
289 return (boost::int64_t)dHashesPerSec;
293 Value getinfo(const Array& params, bool fHelp)
295 if (fHelp || params.size() != 0)
298 "Returns an object containing various state info.");
301 obj.push_back(Pair("version", (int)VERSION));
302 obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
303 obj.push_back(Pair("blocks", (int)nBestHeight));
304 obj.push_back(Pair("connections", (int)vNodes.size()));
305 obj.push_back(Pair("proxy", (fUseProxy ? addrProxy.ToStringIPPort() : string())));
306 obj.push_back(Pair("generate", (bool)fGenerateBitcoins));
307 obj.push_back(Pair("genproclimit", (int)(fLimitProcessors ? nLimitProcessors : -1)));
308 obj.push_back(Pair("difficulty", (double)GetDifficulty()));
309 obj.push_back(Pair("hashespersec", gethashespersec(params, false)));
310 obj.push_back(Pair("testnet", fTestNet));
311 obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));
312 obj.push_back(Pair("keypoolsize", pwalletMain->GetKeyPoolSize()));
313 obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee)));
314 if (pwalletMain->IsCrypted())
315 obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime));
316 obj.push_back(Pair("errors", GetWarnings("statusbar")));
321 Value getnewaddress(const Array& params, bool fHelp)
323 if (fHelp || params.size() > 1)
325 "getnewaddress [account]\n"
326 "Returns a new bitcoin address for receiving payments. "
327 "If [account] is specified (recommended), it is added to the address book "
328 "so payments received with the address will be credited to [account].");
330 // Parse the account first so we don't generate a key if there's an error
332 if (params.size() > 0)
333 strAccount = AccountFromValue(params[0]);
335 if (!pwalletMain->IsLocked())
336 pwalletMain->TopUpKeyPool();
338 // Generate a new key that is added to wallet
339 std::vector<unsigned char> newKey;
340 if (!pwalletMain->GetKeyFromPool(newKey, false))
341 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
342 CBitcoinAddress address(newKey);
344 pwalletMain->SetAddressBookName(address, strAccount);
346 return address.ToString();
350 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
352 CWalletDB walletdb(pwalletMain->strWalletFile);
355 walletdb.ReadAccount(strAccount, account);
357 bool bKeyUsed = false;
359 // Check if the current key has been used
360 if (!account.vchPubKey.empty())
362 CScript scriptPubKey;
363 scriptPubKey.SetBitcoinAddress(account.vchPubKey);
364 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
365 it != pwalletMain->mapWallet.end() && !account.vchPubKey.empty();
368 const CWalletTx& wtx = (*it).second;
369 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
370 if (txout.scriptPubKey == scriptPubKey)
375 // Generate a new key
376 if (account.vchPubKey.empty() || bForceNew || bKeyUsed)
378 if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false))
379 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
381 pwalletMain->SetAddressBookName(CBitcoinAddress(account.vchPubKey), strAccount);
382 walletdb.WriteAccount(strAccount, account);
385 return CBitcoinAddress(account.vchPubKey);
388 Value getaccountaddress(const Array& params, bool fHelp)
390 if (fHelp || params.size() != 1)
392 "getaccountaddress <account>\n"
393 "Returns the current bitcoin address for receiving payments to this account.");
395 // Parse the account first so we don't generate a key if there's an error
396 string strAccount = AccountFromValue(params[0]);
400 ret = GetAccountAddress(strAccount).ToString();
407 Value setaccount(const Array& params, bool fHelp)
409 if (fHelp || params.size() < 1 || params.size() > 2)
411 "setaccount <bitcoinaddress> <account>\n"
412 "Sets the account associated with the given address.");
414 CBitcoinAddress address(params[0].get_str());
415 if (!address.IsValid())
416 throw JSONRPCError(-5, "Invalid bitcoin address");
420 if (params.size() > 1)
421 strAccount = AccountFromValue(params[1]);
423 // Detect when changing the account of an address that is the 'unused current key' of another account:
424 if (pwalletMain->mapAddressBook.count(address))
426 string strOldAccount = pwalletMain->mapAddressBook[address];
427 if (address == GetAccountAddress(strOldAccount))
428 GetAccountAddress(strOldAccount, true);
431 pwalletMain->SetAddressBookName(address, strAccount);
437 Value getaccount(const Array& params, bool fHelp)
439 if (fHelp || params.size() != 1)
441 "getaccount <bitcoinaddress>\n"
442 "Returns the account associated with the given address.");
444 CBitcoinAddress address(params[0].get_str());
445 if (!address.IsValid())
446 throw JSONRPCError(-5, "Invalid bitcoin address");
449 map<CBitcoinAddress, string>::iterator mi = pwalletMain->mapAddressBook.find(address);
450 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
451 strAccount = (*mi).second;
456 Value getaddressesbyaccount(const Array& params, bool fHelp)
458 if (fHelp || params.size() != 1)
460 "getaddressesbyaccount <account>\n"
461 "Returns the list of addresses for the given account.");
463 string strAccount = AccountFromValue(params[0]);
465 // Find all addresses that have the given account
467 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
469 const CBitcoinAddress& address = item.first;
470 const string& strName = item.second;
471 if (strName == strAccount)
472 ret.push_back(address.ToString());
477 Value settxfee(const Array& params, bool fHelp)
479 if (fHelp || params.size() < 1 || params.size() > 1)
481 "settxfee <amount>\n"
482 "<amount> is a real and is rounded to the nearest 0.00000001");
486 if (params[0].get_real() != 0.0)
487 nAmount = AmountFromValue(params[0]); // rejects 0.0 amounts
489 nTransactionFee = nAmount;
493 Value sendtoaddress(const Array& params, bool fHelp)
495 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
497 "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
498 "<amount> is a real and is rounded to the nearest 0.00000001\n"
499 "requires wallet passphrase to be set with walletpassphrase first");
500 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
502 "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
503 "<amount> is a real and is rounded to the nearest 0.00000001");
505 CBitcoinAddress address(params[0].get_str());
506 if (!address.IsValid())
507 throw JSONRPCError(-5, "Invalid bitcoin address");
510 int64 nAmount = AmountFromValue(params[1]);
514 if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
515 wtx.mapValue["comment"] = params[2].get_str();
516 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
517 wtx.mapValue["to"] = params[3].get_str();
519 if (pwalletMain->IsLocked())
520 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
522 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
524 throw JSONRPCError(-4, strError);
526 return wtx.GetHash().GetHex();
529 Value signmessage(const Array& params, bool fHelp)
531 if (fHelp || params.size() != 2)
533 "signmessage <bitcoinaddress> <message>\n"
534 "Sign a message with the private key of an address");
536 string strAddress = params[0].get_str();
537 string strMessage = params[1].get_str();
538 strMessage.insert(0, "Padding text - ");
541 if(!AddressToHash160(strAddress, hash160))
542 throw JSONRPCError(-3, "Invalid address");
544 vector<unsigned char>& vchPubKey = mapPubKeys[hash160];
546 if(!key.SetPubKey(vchPubKey))
547 throw JSONRPCError(-3, "Public key not found");
548 strMessage.insert(0, HexStr(vchPubKey.begin(), vchPubKey.end()).c_str());
550 vector<unsigned char> vchMsg(strMessage.begin(), strMessage.end());
551 vector<unsigned char> vchSig;
552 if (!CKey::Sign(mapKeys[vchPubKey], Hash(vchMsg.begin(), vchMsg.end()), vchSig))
553 throw JSONRPCError(-3, "Sign failed");
556 obj.push_back(Pair("address", strAddress));
557 obj.push_back(Pair("pubkey", HexStr(vchPubKey.begin(), vchPubKey.end()).c_str()));
558 obj.push_back(Pair("sign", HexStr(vchSig.begin(), vchSig.end()).c_str()));
563 Value verifymessage(const Array& params, bool fHelp)
565 if (fHelp || params.size() != 3)
567 "verifymessage <pubkey> <sign> <message>\n"
568 "Verify a signed message with the public key");
570 string strPubKey = params[0].get_str();
571 string strSign = params[1].get_str();
572 string strMessage = params[2].get_str();
573 strMessage.insert(0, "Padding text - ");
574 strMessage.insert(0, strPubKey.c_str());
576 vector<unsigned char> vchPubKey = ParseHex(strPubKey);
577 vector<unsigned char> vchSig = ParseHex(strSign);
578 vector<unsigned char> vchMsg(strMessage.begin(), strMessage.end());
581 if(!key.SetPubKey(vchPubKey))
582 throw JSONRPCError(-3, "Invalid pubkey");
584 if (!key.Verify(Hash(vchMsg.begin(), vchMsg.end()), vchSig))
585 throw JSONRPCError(-3, "Verify failed");
588 obj.push_back(Pair("address", PubKeyToAddress(vchPubKey)));
589 obj.push_back(Pair("pubkey", strPubKey.c_str()));
594 Value getreceivedbyaddress(const Array& params, bool fHelp)
596 if (fHelp || params.size() < 1 || params.size() > 2)
598 "getreceivedbyaddress <bitcoinaddress> [minconf=1]\n"
599 "Returns the total amount received by <bitcoinaddress> in transactions with at least [minconf] confirmations.");
602 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
603 CScript scriptPubKey;
604 if (!address.IsValid())
605 throw JSONRPCError(-5, "Invalid bitcoin address");
606 scriptPubKey.SetBitcoinAddress(address);
607 if (!IsMine(*pwalletMain,scriptPubKey))
610 // Minimum confirmations
612 if (params.size() > 1)
613 nMinDepth = params[1].get_int();
617 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
619 const CWalletTx& wtx = (*it).second;
620 if (wtx.IsCoinBase() || !wtx.IsFinal())
623 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
624 if (txout.scriptPubKey == scriptPubKey)
625 if (wtx.GetDepthInMainChain() >= nMinDepth)
626 nAmount += txout.nValue;
629 return ValueFromAmount(nAmount);
633 void GetAccountAddresses(string strAccount, set<CBitcoinAddress>& setAddress)
635 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
637 const CBitcoinAddress& address = item.first;
638 const string& strName = item.second;
639 if (strName == strAccount)
640 setAddress.insert(address);
645 Value getreceivedbyaccount(const Array& params, bool fHelp)
647 if (fHelp || params.size() < 1 || params.size() > 2)
649 "getreceivedbyaccount <account> [minconf=1]\n"
650 "Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.");
652 // Minimum confirmations
654 if (params.size() > 1)
655 nMinDepth = params[1].get_int();
657 // Get the set of pub keys that have the label
658 string strAccount = AccountFromValue(params[0]);
659 set<CBitcoinAddress> setAddress;
660 GetAccountAddresses(strAccount, setAddress);
664 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
666 const CWalletTx& wtx = (*it).second;
667 if (wtx.IsCoinBase() || !wtx.IsFinal())
670 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
672 CBitcoinAddress address;
673 if (ExtractAddress(txout.scriptPubKey, pwalletMain, address) && setAddress.count(address))
674 if (wtx.GetDepthInMainChain() >= nMinDepth)
675 nAmount += txout.nValue;
679 return (double)nAmount / (double)COIN;
683 int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth)
687 // Tally wallet transactions
688 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
690 const CWalletTx& wtx = (*it).second;
694 int64 nGenerated, nReceived, nSent, nFee;
695 wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee);
697 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
698 nBalance += nReceived;
699 nBalance += nGenerated - nSent - nFee;
702 // Tally internal accounting entries
703 nBalance += walletdb.GetAccountCreditDebit(strAccount);
708 int64 GetAccountBalance(const string& strAccount, int nMinDepth)
710 CWalletDB walletdb(pwalletMain->strWalletFile);
711 return GetAccountBalance(walletdb, strAccount, nMinDepth);
715 Value getbalance(const Array& params, bool fHelp)
717 if (fHelp || params.size() > 2)
719 "getbalance [account] [minconf=1]\n"
720 "If [account] is not specified, returns the server's total available balance.\n"
721 "If [account] is specified, returns the balance in the account.");
723 if (params.size() == 0)
724 return ValueFromAmount(pwalletMain->GetBalance());
727 if (params.size() > 1)
728 nMinDepth = params[1].get_int();
730 if (params[0].get_str() == "*") {
731 // Calculate total balance a different way from GetBalance()
732 // (GetBalance() sums up all unspent TxOuts)
733 // getbalance and getbalance '*' should always return the same number.
735 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
737 const CWalletTx& wtx = (*it).second;
741 int64 allGeneratedImmature, allGeneratedMature, allFee;
742 allGeneratedImmature = allGeneratedMature = allFee = 0;
743 string strSentAccount;
744 list<pair<CBitcoinAddress, int64> > listReceived;
745 list<pair<CBitcoinAddress, int64> > listSent;
746 wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
747 if (wtx.GetDepthInMainChain() >= nMinDepth)
748 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listReceived)
749 nBalance += r.second;
750 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listSent)
751 nBalance -= r.second;
753 nBalance += allGeneratedMature;
755 return ValueFromAmount(nBalance);
758 string strAccount = AccountFromValue(params[0]);
760 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
762 return ValueFromAmount(nBalance);
766 Value movecmd(const Array& params, bool fHelp)
768 if (fHelp || params.size() < 3 || params.size() > 5)
770 "move <fromaccount> <toaccount> <amount> [minconf=1] [comment]\n"
771 "Move from one account in your wallet to another.");
773 string strFrom = AccountFromValue(params[0]);
774 string strTo = AccountFromValue(params[1]);
775 int64 nAmount = AmountFromValue(params[2]);
776 if (params.size() > 3)
777 // unused parameter, used to be nMinDepth, keep type-checking it though
778 (void)params[3].get_int();
780 if (params.size() > 4)
781 strComment = params[4].get_str();
783 CWalletDB walletdb(pwalletMain->strWalletFile);
786 int64 nNow = GetAdjustedTime();
789 CAccountingEntry debit;
790 debit.strAccount = strFrom;
791 debit.nCreditDebit = -nAmount;
793 debit.strOtherAccount = strTo;
794 debit.strComment = strComment;
795 walletdb.WriteAccountingEntry(debit);
798 CAccountingEntry credit;
799 credit.strAccount = strTo;
800 credit.nCreditDebit = nAmount;
802 credit.strOtherAccount = strFrom;
803 credit.strComment = strComment;
804 walletdb.WriteAccountingEntry(credit);
806 walletdb.TxnCommit();
812 Value sendfrom(const Array& params, bool fHelp)
814 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
816 "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
817 "<amount> is a real and is rounded to the nearest 0.00000001\n"
818 "requires wallet passphrase to be set with walletpassphrase first");
819 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
821 "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
822 "<amount> is a real and is rounded to the nearest 0.00000001");
824 string strAccount = AccountFromValue(params[0]);
825 CBitcoinAddress address(params[1].get_str());
826 if (!address.IsValid())
827 throw JSONRPCError(-5, "Invalid bitcoin address");
828 int64 nAmount = AmountFromValue(params[2]);
830 if (params.size() > 3)
831 nMinDepth = params[3].get_int();
834 wtx.strFromAccount = strAccount;
835 if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
836 wtx.mapValue["comment"] = params[4].get_str();
837 if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
838 wtx.mapValue["to"] = params[5].get_str();
840 if (pwalletMain->IsLocked())
841 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
844 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
845 if (nAmount > nBalance)
846 throw JSONRPCError(-6, "Account has insufficient funds");
849 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
851 throw JSONRPCError(-4, strError);
853 return wtx.GetHash().GetHex();
857 Value sendmany(const Array& params, bool fHelp)
859 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
861 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
862 "amounts are double-precision floating point numbers\n"
863 "requires wallet passphrase to be set with walletpassphrase first");
864 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
866 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
867 "amounts are double-precision floating point numbers");
869 string strAccount = AccountFromValue(params[0]);
870 Object sendTo = params[1].get_obj();
872 if (params.size() > 2)
873 nMinDepth = params[2].get_int();
876 wtx.strFromAccount = strAccount;
877 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
878 wtx.mapValue["comment"] = params[3].get_str();
880 set<CBitcoinAddress> setAddress;
881 vector<pair<CScript, int64> > vecSend;
883 int64 totalAmount = 0;
884 BOOST_FOREACH(const Pair& s, sendTo)
886 CBitcoinAddress address(s.name_);
887 if (!address.IsValid())
888 throw JSONRPCError(-5, string("Invalid bitcoin address:")+s.name_);
890 if (setAddress.count(address))
891 throw JSONRPCError(-8, string("Invalid parameter, duplicated address: ")+s.name_);
892 setAddress.insert(address);
894 CScript scriptPubKey;
895 scriptPubKey.SetBitcoinAddress(address);
896 int64 nAmount = AmountFromValue(s.value_);
897 totalAmount += nAmount;
899 vecSend.push_back(make_pair(scriptPubKey, nAmount));
902 if (pwalletMain->IsLocked())
903 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
906 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
907 if (totalAmount > nBalance)
908 throw JSONRPCError(-6, "Account has insufficient funds");
911 CReserveKey keyChange(pwalletMain);
912 int64 nFeeRequired = 0;
913 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
916 if (totalAmount + nFeeRequired > pwalletMain->GetBalance())
917 throw JSONRPCError(-6, "Insufficient funds");
918 throw JSONRPCError(-4, "Transaction creation failed");
920 if (!pwalletMain->CommitTransaction(wtx, keyChange))
921 throw JSONRPCError(-4, "Transaction commit failed");
923 return wtx.GetHash().GetHex();
938 Value ListReceived(const Array& params, bool fByAccounts)
940 // Minimum confirmations
942 if (params.size() > 0)
943 nMinDepth = params[0].get_int();
945 // Whether to include empty accounts
946 bool fIncludeEmpty = false;
947 if (params.size() > 1)
948 fIncludeEmpty = params[1].get_bool();
951 map<CBitcoinAddress, tallyitem> mapTally;
952 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
954 const CWalletTx& wtx = (*it).second;
955 if (wtx.IsCoinBase() || !wtx.IsFinal())
958 int nDepth = wtx.GetDepthInMainChain();
959 if (nDepth < nMinDepth)
962 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
964 CBitcoinAddress address;
965 if (!ExtractAddress(txout.scriptPubKey, pwalletMain, address) || !address.IsValid())
968 tallyitem& item = mapTally[address];
969 item.nAmount += txout.nValue;
970 item.nConf = min(item.nConf, nDepth);
976 map<string, tallyitem> mapAccountTally;
977 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
979 const CBitcoinAddress& address = item.first;
980 const string& strAccount = item.second;
981 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
982 if (it == mapTally.end() && !fIncludeEmpty)
987 if (it != mapTally.end())
989 nAmount = (*it).second.nAmount;
990 nConf = (*it).second.nConf;
995 tallyitem& item = mapAccountTally[strAccount];
996 item.nAmount += nAmount;
997 item.nConf = min(item.nConf, nConf);
1002 obj.push_back(Pair("address", address.ToString()));
1003 obj.push_back(Pair("account", strAccount));
1004 obj.push_back(Pair("label", strAccount)); // deprecated
1005 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1006 obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
1013 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
1015 int64 nAmount = (*it).second.nAmount;
1016 int nConf = (*it).second.nConf;
1018 obj.push_back(Pair("account", (*it).first));
1019 obj.push_back(Pair("label", (*it).first)); // deprecated
1020 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1021 obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
1029 Value listreceivedbyaddress(const Array& params, bool fHelp)
1031 if (fHelp || params.size() > 2)
1032 throw runtime_error(
1033 "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
1034 "[minconf] is the minimum number of confirmations before payments are included.\n"
1035 "[includeempty] whether to include addresses that haven't received any payments.\n"
1036 "Returns an array of objects containing:\n"
1037 " \"address\" : receiving address\n"
1038 " \"account\" : the account of the receiving address\n"
1039 " \"amount\" : total amount received by the address\n"
1040 " \"confirmations\" : number of confirmations of the most recent transaction included");
1042 return ListReceived(params, false);
1045 Value listreceivedbyaccount(const Array& params, bool fHelp)
1047 if (fHelp || params.size() > 2)
1048 throw runtime_error(
1049 "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
1050 "[minconf] is the minimum number of confirmations before payments are included.\n"
1051 "[includeempty] whether to include accounts that haven't received any payments.\n"
1052 "Returns an array of objects containing:\n"
1053 " \"account\" : the account of the receiving addresses\n"
1054 " \"amount\" : total amount received by addresses with this account\n"
1055 " \"confirmations\" : number of confirmations of the most recent transaction included");
1057 return ListReceived(params, true);
1060 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret)
1062 int64 nGeneratedImmature, nGeneratedMature, nFee;
1063 string strSentAccount;
1064 list<pair<CBitcoinAddress, int64> > listReceived;
1065 list<pair<CBitcoinAddress, int64> > listSent;
1066 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1068 bool fAllAccounts = (strAccount == string("*"));
1070 // Generated blocks assigned to account ""
1071 if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == ""))
1074 entry.push_back(Pair("account", string("")));
1075 if (nGeneratedImmature)
1077 entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
1078 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
1082 entry.push_back(Pair("category", "generate"));
1083 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
1086 WalletTxToJSON(wtx, entry);
1087 ret.push_back(entry);
1091 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1093 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1096 entry.push_back(Pair("account", strSentAccount));
1097 entry.push_back(Pair("address", s.first.ToString()));
1098 entry.push_back(Pair("category", "send"));
1099 entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1100 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1102 WalletTxToJSON(wtx, entry);
1103 ret.push_back(entry);
1108 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1109 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1112 if (pwalletMain->mapAddressBook.count(r.first))
1113 account = pwalletMain->mapAddressBook[r.first];
1114 if (fAllAccounts || (account == strAccount))
1117 entry.push_back(Pair("account", account));
1118 entry.push_back(Pair("address", r.first.ToString()));
1119 entry.push_back(Pair("category", "receive"));
1120 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1122 WalletTxToJSON(wtx, entry);
1123 ret.push_back(entry);
1128 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1130 bool fAllAccounts = (strAccount == string("*"));
1132 if (fAllAccounts || acentry.strAccount == strAccount)
1135 entry.push_back(Pair("account", acentry.strAccount));
1136 entry.push_back(Pair("category", "move"));
1137 entry.push_back(Pair("time", (boost::int64_t)acentry.nTime));
1138 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1139 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1140 entry.push_back(Pair("comment", acentry.strComment));
1141 ret.push_back(entry);
1145 Value listtransactions(const Array& params, bool fHelp)
1147 if (fHelp || params.size() > 3)
1148 throw runtime_error(
1149 "listtransactions [account] [count=10] [from=0]\n"
1150 "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1152 string strAccount = "*";
1153 if (params.size() > 0)
1154 strAccount = params[0].get_str();
1156 if (params.size() > 1)
1157 nCount = params[1].get_int();
1159 if (params.size() > 2)
1160 nFrom = params[2].get_int();
1163 CWalletDB walletdb(pwalletMain->strWalletFile);
1165 // Firs: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap:
1166 typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
1167 typedef multimap<int64, TxPair > TxItems;
1170 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1172 CWalletTx* wtx = &((*it).second);
1173 txByTime.insert(make_pair(wtx->GetTxTime(), TxPair(wtx, (CAccountingEntry*)0)));
1175 list<CAccountingEntry> acentries;
1176 walletdb.ListAccountCreditDebit(strAccount, acentries);
1177 BOOST_FOREACH(CAccountingEntry& entry, acentries)
1179 txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
1182 // Now: iterate backwards until we have nCount items to return:
1183 TxItems::reverse_iterator it = txByTime.rbegin();
1184 if (txByTime.size() > nFrom) std::advance(it, nFrom);
1185 for (; it != txByTime.rend(); ++it)
1187 CWalletTx *const pwtx = (*it).second.first;
1189 ListTransactions(*pwtx, strAccount, 0, true, ret);
1190 CAccountingEntry *const pacentry = (*it).second.second;
1192 AcentryToJSON(*pacentry, strAccount, ret);
1194 if (ret.size() >= nCount) break;
1196 // ret is now newest to oldest
1198 // Make sure we return only last nCount items (sends-to-self might give us an extra):
1199 if (ret.size() > nCount)
1201 Array::iterator last = ret.begin();
1202 std::advance(last, nCount);
1203 ret.erase(last, ret.end());
1205 std::reverse(ret.begin(), ret.end()); // oldest to newest
1210 Value listaccounts(const Array& params, bool fHelp)
1212 if (fHelp || params.size() > 1)
1213 throw runtime_error(
1214 "listaccounts [minconf=1]\n"
1215 "Returns Object that has account names as keys, account balances as values.");
1218 if (params.size() > 0)
1219 nMinDepth = params[0].get_int();
1221 map<string, int64> mapAccountBalances;
1222 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& entry, pwalletMain->mapAddressBook) {
1223 if (pwalletMain->HaveKey(entry.first)) // This address belongs to me
1224 mapAccountBalances[entry.second] = 0;
1227 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1229 const CWalletTx& wtx = (*it).second;
1230 int64 nGeneratedImmature, nGeneratedMature, nFee;
1231 string strSentAccount;
1232 list<pair<CBitcoinAddress, int64> > listReceived;
1233 list<pair<CBitcoinAddress, int64> > listSent;
1234 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1235 mapAccountBalances[strSentAccount] -= nFee;
1236 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1237 mapAccountBalances[strSentAccount] -= s.second;
1238 if (wtx.GetDepthInMainChain() >= nMinDepth)
1240 mapAccountBalances[""] += nGeneratedMature;
1241 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1242 if (pwalletMain->mapAddressBook.count(r.first))
1243 mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1245 mapAccountBalances[""] += r.second;
1249 list<CAccountingEntry> acentries;
1250 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1251 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1252 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1255 BOOST_FOREACH(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) {
1256 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1261 Value gettransaction(const Array& params, bool fHelp)
1263 if (fHelp || params.size() != 1)
1264 throw runtime_error(
1265 "gettransaction <txid>\n"
1266 "Get detailed information about <txid>");
1269 hash.SetHex(params[0].get_str());
1273 if (!pwalletMain->mapWallet.count(hash))
1274 throw JSONRPCError(-5, "Invalid or non-wallet transaction id");
1275 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1277 int64 nCredit = wtx.GetCredit();
1278 int64 nDebit = wtx.GetDebit();
1279 int64 nNet = nCredit - nDebit;
1280 int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
1282 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1284 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1286 WalletTxToJSON(pwalletMain->mapWallet[hash], entry);
1289 ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
1290 entry.push_back(Pair("details", details));
1296 Value backupwallet(const Array& params, bool fHelp)
1298 if (fHelp || params.size() != 1)
1299 throw runtime_error(
1300 "backupwallet <destination>\n"
1301 "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1303 string strDest = params[0].get_str();
1304 BackupWallet(*pwalletMain, strDest);
1310 Value keypoolrefill(const Array& params, bool fHelp)
1312 if (pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1313 throw runtime_error(
1315 "Fills the keypool, requires wallet passphrase to be set.");
1316 if (!pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1317 throw runtime_error(
1319 "Fills the keypool.");
1321 if (pwalletMain->IsLocked())
1322 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
1324 pwalletMain->TopUpKeyPool();
1326 if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100))
1327 throw JSONRPCError(-4, "Error refreshing keypool.");
1333 void ThreadTopUpKeyPool(void* parg)
1335 pwalletMain->TopUpKeyPool();
1338 void ThreadCleanWalletPassphrase(void* parg)
1340 int64 nMyWakeTime = GetTime() + *((int*)parg);
1342 if (nWalletUnlockTime == 0)
1344 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1346 nWalletUnlockTime = nMyWakeTime;
1349 while (GetTime() < nWalletUnlockTime)
1350 Sleep(GetTime() - nWalletUnlockTime);
1352 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1354 nWalletUnlockTime = 0;
1359 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1361 if (nWalletUnlockTime < nMyWakeTime)
1362 nWalletUnlockTime = nMyWakeTime;
1368 pwalletMain->Lock();
1373 Value walletpassphrase(const Array& params, bool fHelp)
1375 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1376 throw runtime_error(
1377 "walletpassphrase <passphrase> <timeout>\n"
1378 "Stores the wallet decryption key in memory for <timeout> seconds.");
1381 if (!pwalletMain->IsCrypted())
1382 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1384 if (!pwalletMain->IsLocked())
1385 throw JSONRPCError(-17, "Error: Wallet is already unlocked.");
1387 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1388 string strWalletPass;
1389 strWalletPass.reserve(100);
1390 mlock(&strWalletPass[0], strWalletPass.capacity());
1391 strWalletPass = params[0].get_str();
1393 if (strWalletPass.length() > 0)
1395 if (!pwalletMain->Unlock(strWalletPass))
1397 fill(strWalletPass.begin(), strWalletPass.end(), '\0');
1398 munlock(&strWalletPass[0], strWalletPass.capacity());
1399 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1401 fill(strWalletPass.begin(), strWalletPass.end(), '\0');
1402 munlock(&strWalletPass[0], strWalletPass.capacity());
1405 throw runtime_error(
1406 "walletpassphrase <passphrase> <timeout>\n"
1407 "Stores the wallet decryption key in memory for <timeout> seconds.");
1409 CreateThread(ThreadTopUpKeyPool, NULL);
1410 int* pnSleepTime = new int(params[1].get_int());
1411 CreateThread(ThreadCleanWalletPassphrase, pnSleepTime);
1417 Value walletpassphrasechange(const Array& params, bool fHelp)
1419 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1420 throw runtime_error(
1421 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1422 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1425 if (!pwalletMain->IsCrypted())
1426 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1428 string strOldWalletPass;
1429 strOldWalletPass.reserve(100);
1430 mlock(&strOldWalletPass[0], strOldWalletPass.capacity());
1431 strOldWalletPass = params[0].get_str();
1433 string strNewWalletPass;
1434 strNewWalletPass.reserve(100);
1435 mlock(&strNewWalletPass[0], strNewWalletPass.capacity());
1436 strNewWalletPass = params[1].get_str();
1438 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1439 throw runtime_error(
1440 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1441 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1443 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1445 fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0');
1446 fill(strNewWalletPass.begin(), strNewWalletPass.end(), '\0');
1447 munlock(&strOldWalletPass[0], strOldWalletPass.capacity());
1448 munlock(&strNewWalletPass[0], strNewWalletPass.capacity());
1449 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1451 fill(strNewWalletPass.begin(), strNewWalletPass.end(), '\0');
1452 fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0');
1453 munlock(&strOldWalletPass[0], strOldWalletPass.capacity());
1454 munlock(&strNewWalletPass[0], strNewWalletPass.capacity());
1460 Value walletlock(const Array& params, bool fHelp)
1462 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1463 throw runtime_error(
1465 "Removes the wallet encryption key from memory, locking the wallet.\n"
1466 "After calling this method, you will need to call walletpassphrase again\n"
1467 "before being able to call any methods which require the wallet to be unlocked.");
1470 if (!pwalletMain->IsCrypted())
1471 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called.");
1473 pwalletMain->Lock();
1474 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1476 nWalletUnlockTime = 0;
1483 Value encryptwallet(const Array& params, bool fHelp)
1485 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1486 throw runtime_error(
1487 "encryptwallet <passphrase>\n"
1488 "Encrypts the wallet with <passphrase>.");
1491 if (pwalletMain->IsCrypted())
1492 throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
1494 string strWalletPass;
1495 strWalletPass.reserve(100);
1496 mlock(&strWalletPass[0], strWalletPass.capacity());
1497 strWalletPass = params[0].get_str();
1499 if (strWalletPass.length() < 1)
1500 throw runtime_error(
1501 "encryptwallet <passphrase>\n"
1502 "Encrypts the wallet with <passphrase>.");
1504 if (!pwalletMain->EncryptWallet(strWalletPass))
1506 fill(strWalletPass.begin(), strWalletPass.end(), '\0');
1507 munlock(&strWalletPass[0], strWalletPass.capacity());
1508 throw JSONRPCError(-16, "Error: Failed to encrypt the wallet.");
1510 fill(strWalletPass.begin(), strWalletPass.end(), '\0');
1511 munlock(&strWalletPass[0], strWalletPass.capacity());
1517 Value validateaddress(const Array& params, bool fHelp)
1519 if (fHelp || params.size() != 1)
1520 throw runtime_error(
1521 "validateaddress <bitcoinaddress>\n"
1522 "Return information about <bitcoinaddress>.");
1524 CBitcoinAddress address(params[0].get_str());
1525 bool isValid = address.IsValid();
1528 ret.push_back(Pair("isvalid", isValid));
1531 // Call Hash160ToAddress() so we always return current ADDRESSVERSION
1532 // version of the address:
1533 string currentAddress = address.ToString();
1534 ret.push_back(Pair("address", currentAddress));
1535 ret.push_back(Pair("ismine", (pwalletMain->HaveKey(address) > 0)));
1536 if (pwalletMain->mapAddressBook.count(address))
1537 ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
1543 Value getwork(const Array& params, bool fHelp)
1545 if (fHelp || params.size() > 1)
1546 throw runtime_error(
1548 "If [data] is not specified, returns formatted hash data to work on:\n"
1549 " \"midstate\" : precomputed hash state after hashing the first half of the data\n"
1550 " \"data\" : block data\n"
1551 " \"hash1\" : formatted hash buffer for second hash\n"
1552 " \"target\" : little endian hash target\n"
1553 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1556 throw JSONRPCError(-9, "Bitcoin is not connected!");
1558 if (IsInitialBlockDownload())
1559 throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
1561 typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
1562 static mapNewBlock_t mapNewBlock;
1563 static vector<CBlock*> vNewBlock;
1564 static CReserveKey reservekey(pwalletMain);
1566 if (params.size() == 0)
1569 static unsigned int nTransactionsUpdatedLast;
1570 static CBlockIndex* pindexPrev;
1571 static int64 nStart;
1572 static CBlock* pblock;
1573 if (pindexPrev != pindexBest ||
1574 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
1576 if (pindexPrev != pindexBest)
1578 // Deallocate old blocks since they're obsolete now
1579 mapNewBlock.clear();
1580 BOOST_FOREACH(CBlock* pblock, vNewBlock)
1584 nTransactionsUpdatedLast = nTransactionsUpdated;
1585 pindexPrev = pindexBest;
1589 pblock = CreateNewBlock(reservekey);
1591 throw JSONRPCError(-7, "Out of memory");
1592 vNewBlock.push_back(pblock);
1596 pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
1599 // Update nExtraNonce
1600 static unsigned int nExtraNonce = 0;
1601 IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
1604 mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
1606 // Prebuild hash buffers
1610 FormatHashBuffers(pblock, pmidstate, pdata, phash1);
1612 uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
1615 result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate))));
1616 result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata))));
1617 result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1))));
1618 result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
1624 vector<unsigned char> vchData = ParseHex(params[0].get_str());
1625 if (vchData.size() != 128)
1626 throw JSONRPCError(-8, "Invalid parameter");
1627 CBlock* pdata = (CBlock*)&vchData[0];
1630 for (int i = 0; i < 128/4; i++)
1631 ((unsigned int*)pdata)[i] = CryptoPP::ByteReverse(((unsigned int*)pdata)[i]);
1634 if (!mapNewBlock.count(pdata->hashMerkleRoot))
1636 CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
1638 pblock->nTime = pdata->nTime;
1639 pblock->nNonce = pdata->nNonce;
1640 pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
1641 pblock->hashMerkleRoot = pblock->BuildMerkleTree();
1643 return CheckWork(pblock, *pwalletMain, reservekey);
1661 pair<string, rpcfn_type> pCallTable[] =
1663 make_pair("help", &help),
1664 make_pair("stop", &stop),
1665 make_pair("getblockcount", &getblockcount),
1666 make_pair("getblocknumber", &getblocknumber),
1667 make_pair("getconnectioncount", &getconnectioncount),
1668 make_pair("getdifficulty", &getdifficulty),
1669 make_pair("getgenerate", &getgenerate),
1670 make_pair("setgenerate", &setgenerate),
1671 make_pair("gethashespersec", &gethashespersec),
1672 make_pair("getinfo", &getinfo),
1673 make_pair("getnewaddress", &getnewaddress),
1674 make_pair("getaccountaddress", &getaccountaddress),
1675 make_pair("setaccount", &setaccount),
1676 make_pair("setlabel", &setaccount), // deprecated
1677 make_pair("getaccount", &getaccount),
1678 make_pair("getlabel", &getaccount), // deprecated
1679 make_pair("getaddressesbyaccount", &getaddressesbyaccount),
1680 make_pair("getaddressesbylabel", &getaddressesbyaccount), // deprecated
1681 make_pair("sendtoaddress", &sendtoaddress),
1682 make_pair("getamountreceived", &getreceivedbyaddress), // deprecated, renamed to getreceivedbyaddress
1683 make_pair("getallreceived", &listreceivedbyaddress), // deprecated, renamed to listreceivedbyaddress
1684 make_pair("getreceivedbyaddress", &getreceivedbyaddress),
1685 make_pair("getreceivedbyaccount", &getreceivedbyaccount),
1686 make_pair("getreceivedbylabel", &getreceivedbyaccount), // deprecated
1687 make_pair("listreceivedbyaddress", &listreceivedbyaddress),
1688 make_pair("listreceivedbyaccount", &listreceivedbyaccount),
1689 make_pair("listreceivedbylabel", &listreceivedbyaccount), // deprecated
1690 make_pair("backupwallet", &backupwallet),
1691 make_pair("keypoolrefill", &keypoolrefill),
1692 make_pair("walletpassphrase", &walletpassphrase),
1693 make_pair("walletpassphrasechange", &walletpassphrasechange),
1694 make_pair("walletlock", &walletlock),
1695 make_pair("encryptwallet", &encryptwallet),
1696 make_pair("validateaddress", &validateaddress),
1697 make_pair("getbalance", &getbalance),
1698 make_pair("move", &movecmd),
1699 make_pair("sendfrom", &sendfrom),
1700 make_pair("sendmany", &sendmany),
1701 make_pair("gettransaction", &gettransaction),
1702 make_pair("listtransactions", &listtransactions),
1703 make_pair("signmessage", &signmessage),
1704 make_pair("verifymessage", &verifymessage),
1705 make_pair("getwork", &getwork),
1706 make_pair("listaccounts", &listaccounts),
1707 make_pair("settxfee", &settxfee),
1709 map<string, rpcfn_type> mapCallTable(pCallTable, pCallTable + sizeof(pCallTable)/sizeof(pCallTable[0]));
1711 string pAllowInSafeMode[] =
1717 "getconnectioncount",
1724 "getaccountaddress",
1725 "setlabel", // deprecated
1727 "getlabel", // deprecated
1728 "getaddressesbyaccount",
1729 "getaddressesbylabel", // deprecated
1737 set<string> setAllowInSafeMode(pAllowInSafeMode, pAllowInSafeMode + sizeof(pAllowInSafeMode)/sizeof(pAllowInSafeMode[0]));
1745 // This ain't Apache. We're just using HTTP header for the length field
1746 // and to be compatible with other JSON-RPC implementations.
1749 string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
1752 s << "POST / HTTP/1.1\r\n"
1753 << "User-Agent: bitcoin-json-rpc/" << FormatFullVersion() << "\r\n"
1754 << "Host: 127.0.0.1\r\n"
1755 << "Content-Type: application/json\r\n"
1756 << "Content-Length: " << strMsg.size() << "\r\n"
1757 << "Accept: application/json\r\n";
1758 BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
1759 s << item.first << ": " << item.second << "\r\n";
1760 s << "\r\n" << strMsg;
1765 string rfc1123Time()
1770 struct tm* now_gmt = gmtime(&now);
1771 string locale(setlocale(LC_TIME, NULL));
1772 setlocale(LC_TIME, "C"); // we want posix (aka "C") weekday/month strings
1773 strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt);
1774 setlocale(LC_TIME, locale.c_str());
1775 return string(buffer);
1778 static string HTTPReply(int nStatus, const string& strMsg)
1781 return strprintf("HTTP/1.0 401 Authorization Required\r\n"
1783 "Server: bitcoin-json-rpc/%s\r\n"
1784 "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
1785 "Content-Type: text/html\r\n"
1786 "Content-Length: 296\r\n"
1788 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
1789 "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
1792 "<TITLE>Error</TITLE>\r\n"
1793 "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
1795 "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
1796 "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
1798 if (nStatus == 200) strStatus = "OK";
1799 else if (nStatus == 400) strStatus = "Bad Request";
1800 else if (nStatus == 403) strStatus = "Forbidden";
1801 else if (nStatus == 404) strStatus = "Not Found";
1802 else if (nStatus == 500) strStatus = "Internal Server Error";
1804 "HTTP/1.1 %d %s\r\n"
1806 "Connection: close\r\n"
1807 "Content-Length: %d\r\n"
1808 "Content-Type: application/json\r\n"
1809 "Server: bitcoin-json-rpc/%s\r\n"
1814 rfc1123Time().c_str(),
1816 FormatFullVersion().c_str(),
1820 int ReadHTTPStatus(std::basic_istream<char>& stream)
1823 getline(stream, str);
1824 vector<string> vWords;
1825 boost::split(vWords, str, boost::is_any_of(" "));
1826 if (vWords.size() < 2)
1828 return atoi(vWords[1].c_str());
1831 int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
1837 std::getline(stream, str);
1838 if (str.empty() || str == "\r")
1840 string::size_type nColon = str.find(":");
1841 if (nColon != string::npos)
1843 string strHeader = str.substr(0, nColon);
1844 boost::trim(strHeader);
1845 boost::to_lower(strHeader);
1846 string strValue = str.substr(nColon+1);
1847 boost::trim(strValue);
1848 mapHeadersRet[strHeader] = strValue;
1849 if (strHeader == "content-length")
1850 nLen = atoi(strValue.c_str());
1856 int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
1858 mapHeadersRet.clear();
1862 int nStatus = ReadHTTPStatus(stream);
1865 int nLen = ReadHTTPHeader(stream, mapHeadersRet);
1866 if (nLen < 0 || nLen > MAX_SIZE)
1872 vector<char> vch(nLen);
1873 stream.read(&vch[0], nLen);
1874 strMessageRet = string(vch.begin(), vch.end());
1880 bool HTTPAuthorized(map<string, string>& mapHeaders)
1882 string strAuth = mapHeaders["authorization"];
1883 if (strAuth.substr(0,6) != "Basic ")
1885 string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
1886 string strUserPass = DecodeBase64(strUserPass64);
1887 string::size_type nColon = strUserPass.find(":");
1888 if (nColon == string::npos)
1890 string strUser = strUserPass.substr(0, nColon);
1891 string strPassword = strUserPass.substr(nColon+1);
1892 return (strUser == mapArgs["-rpcuser"] && strPassword == mapArgs["-rpcpassword"]);
1896 // JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
1897 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
1898 // unspecified (HTTP errors and contents of 'error').
1900 // 1.0 spec: http://json-rpc.org/wiki/specification
1901 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
1902 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
1905 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
1908 request.push_back(Pair("method", strMethod));
1909 request.push_back(Pair("params", params));
1910 request.push_back(Pair("id", id));
1911 return write_string(Value(request), false) + "\n";
1914 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
1917 if (error.type() != null_type)
1918 reply.push_back(Pair("result", Value::null));
1920 reply.push_back(Pair("result", result));
1921 reply.push_back(Pair("error", error));
1922 reply.push_back(Pair("id", id));
1923 return write_string(Value(reply), false) + "\n";
1926 void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
1928 // Send error reply from json-rpc error object
1930 int code = find_value(objError, "code").get_int();
1931 if (code == -32600) nStatus = 400;
1932 else if (code == -32601) nStatus = 404;
1933 string strReply = JSONRPCReply(Value::null, objError, id);
1934 stream << HTTPReply(nStatus, strReply) << std::flush;
1937 bool ClientAllowed(const string& strAddress)
1939 if (strAddress == asio::ip::address_v4::loopback().to_string())
1941 const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
1942 BOOST_FOREACH(string strAllow, vAllow)
1943 if (WildcardMatch(strAddress, strAllow))
1950 // IOStream device that speaks SSL but can also speak non-SSL
1952 class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
1954 SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
1956 fUseSSL = fUseSSLIn;
1957 fNeedHandshake = fUseSSLIn;
1960 void handshake(ssl::stream_base::handshake_type role)
1962 if (!fNeedHandshake) return;
1963 fNeedHandshake = false;
1964 stream.handshake(role);
1966 std::streamsize read(char* s, std::streamsize n)
1968 handshake(ssl::stream_base::server); // HTTPS servers read first
1969 if (fUseSSL) return stream.read_some(asio::buffer(s, n));
1970 return stream.next_layer().read_some(asio::buffer(s, n));
1972 std::streamsize write(const char* s, std::streamsize n)
1974 handshake(ssl::stream_base::client); // HTTPS clients write first
1975 if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
1976 return asio::write(stream.next_layer(), asio::buffer(s, n));
1978 bool connect(const std::string& server, const std::string& port)
1980 ip::tcp::resolver resolver(stream.get_io_service());
1981 ip::tcp::resolver::query query(server.c_str(), port.c_str());
1982 ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
1983 ip::tcp::resolver::iterator end;
1984 boost::system::error_code error = asio::error::host_not_found;
1985 while (error && endpoint_iterator != end)
1987 stream.lowest_layer().close();
1988 stream.lowest_layer().connect(*endpoint_iterator++, error);
1996 bool fNeedHandshake;
2002 void ThreadRPCServer(void* parg)
2004 IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
2007 vnThreadsRunning[4]++;
2008 ThreadRPCServer2(parg);
2009 vnThreadsRunning[4]--;
2011 catch (std::exception& e) {
2012 vnThreadsRunning[4]--;
2013 PrintException(&e, "ThreadRPCServer()");
2015 vnThreadsRunning[4]--;
2016 PrintException(NULL, "ThreadRPCServer()");
2018 printf("ThreadRPCServer exiting\n");
2021 void ThreadRPCServer2(void* parg)
2023 printf("ThreadRPCServer started\n");
2025 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2027 string strWhatAmI = "To use bitcoind";
2028 if (mapArgs.count("-server"))
2029 strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
2030 else if (mapArgs.count("-daemon"))
2031 strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
2033 _("Warning: %s, you must set rpcpassword=<password>\nin the configuration file: %s\n"
2034 "If the file does not exist, create it with owner-readable-only file permissions.\n"),
2036 GetConfigFile().c_str());
2037 CreateThread(Shutdown, NULL);
2041 bool fUseSSL = GetBoolArg("-rpcssl");
2042 asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
2044 asio::io_service io_service;
2045 ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", 8332));
2046 ip::tcp::acceptor acceptor(io_service, endpoint);
2048 acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
2051 ssl::context context(io_service, ssl::context::sslv23);
2054 context.set_options(ssl::context::no_sslv2);
2055 filesystem::path certfile = GetArg("-rpcsslcertificatechainfile", "server.cert");
2056 if (!certfile.is_complete()) certfile = filesystem::path(GetDataDir()) / certfile;
2057 if (filesystem::exists(certfile)) context.use_certificate_chain_file(certfile.string().c_str());
2058 else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", certfile.string().c_str());
2059 filesystem::path pkfile = GetArg("-rpcsslprivatekeyfile", "server.pem");
2060 if (!pkfile.is_complete()) pkfile = filesystem::path(GetDataDir()) / pkfile;
2061 if (filesystem::exists(pkfile)) context.use_private_key_file(pkfile.string().c_str(), ssl::context::pem);
2062 else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pkfile.string().c_str());
2064 string ciphers = GetArg("-rpcsslciphers",
2065 "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
2066 SSL_CTX_set_cipher_list(context.impl(), ciphers.c_str());
2070 throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
2075 // Accept connection
2077 SSLStream sslStream(io_service, context);
2078 SSLIOStreamDevice d(sslStream, fUseSSL);
2079 iostreams::stream<SSLIOStreamDevice> stream(d);
2081 ip::tcp::iostream stream;
2084 ip::tcp::endpoint peer;
2085 vnThreadsRunning[4]--;
2087 acceptor.accept(sslStream.lowest_layer(), peer);
2089 acceptor.accept(*stream.rdbuf(), peer);
2091 vnThreadsRunning[4]++;
2095 // Restrict callers by IP
2096 if (!ClientAllowed(peer.address().to_string()))
2098 // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
2100 stream << HTTPReply(403, "") << std::flush;
2104 map<string, string> mapHeaders;
2107 boost::thread api_caller(ReadHTTP, boost::ref(stream), boost::ref(mapHeaders), boost::ref(strRequest));
2108 if (!api_caller.timed_join(boost::posix_time::seconds(GetArg("-rpctimeout", 30))))
2111 printf("ThreadRPCServer ReadHTTP timeout\n");
2115 // Check authorization
2116 if (mapHeaders.count("authorization") == 0)
2118 stream << HTTPReply(401, "") << std::flush;
2121 if (!HTTPAuthorized(mapHeaders))
2123 // Deter brute-forcing short passwords
2124 if (mapArgs["-rpcpassword"].size() < 15)
2127 stream << HTTPReply(401, "") << std::flush;
2128 printf("ThreadRPCServer incorrect password attempt\n");
2132 Value id = Value::null;
2137 if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
2138 throw JSONRPCError(-32700, "Parse error");
2139 const Object& request = valRequest.get_obj();
2141 // Parse id now so errors from here on will have the id
2142 id = find_value(request, "id");
2145 Value valMethod = find_value(request, "method");
2146 if (valMethod.type() == null_type)
2147 throw JSONRPCError(-32600, "Missing method");
2148 if (valMethod.type() != str_type)
2149 throw JSONRPCError(-32600, "Method must be a string");
2150 string strMethod = valMethod.get_str();
2151 if (strMethod != "getwork")
2152 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
2155 Value valParams = find_value(request, "params");
2157 if (valParams.type() == array_type)
2158 params = valParams.get_array();
2159 else if (valParams.type() == null_type)
2162 throw JSONRPCError(-32600, "Params must be an array");
2165 map<string, rpcfn_type>::iterator mi = mapCallTable.find(strMethod);
2166 if (mi == mapCallTable.end())
2167 throw JSONRPCError(-32601, "Method not found");
2169 // Observe safe mode
2170 string strWarning = GetWarnings("rpc");
2171 if (strWarning != "" && !GetBoolArg("-disablesafemode") && !setAllowInSafeMode.count(strMethod))
2172 throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
2178 CRITICAL_BLOCK(cs_main)
2179 CRITICAL_BLOCK(pwalletMain->cs_wallet)
2180 result = (*(*mi).second)(params, false);
2183 string strReply = JSONRPCReply(result, Value::null, id);
2184 stream << HTTPReply(200, strReply) << std::flush;
2186 catch (std::exception& e)
2188 ErrorReply(stream, JSONRPCError(-1, e.what()), id);
2191 catch (Object& objError)
2193 ErrorReply(stream, objError, id);
2195 catch (std::exception& e)
2197 ErrorReply(stream, JSONRPCError(-32700, e.what()), id);
2205 Object CallRPC(const string& strMethod, const Array& params)
2207 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2208 throw runtime_error(strprintf(
2209 _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
2210 "If the file does not exist, create it with owner-readable-only file permissions."),
2211 GetConfigFile().c_str()));
2213 // Connect to localhost
2214 bool fUseSSL = GetBoolArg("-rpcssl");
2216 asio::io_service io_service;
2217 ssl::context context(io_service, ssl::context::sslv23);
2218 context.set_options(ssl::context::no_sslv2);
2219 SSLStream sslStream(io_service, context);
2220 SSLIOStreamDevice d(sslStream, fUseSSL);
2221 iostreams::stream<SSLIOStreamDevice> stream(d);
2222 if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332")))
2223 throw runtime_error("couldn't connect to server");
2226 throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
2228 ip::tcp::iostream stream(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332"));
2230 throw runtime_error("couldn't connect to server");
2234 // HTTP basic authentication
2235 string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
2236 map<string, string> mapRequestHeaders;
2237 mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
2240 string strRequest = JSONRPCRequest(strMethod, params, 1);
2241 string strPost = HTTPPost(strRequest, mapRequestHeaders);
2242 stream << strPost << std::flush;
2245 map<string, string> mapHeaders;
2247 int nStatus = ReadHTTP(stream, mapHeaders, strReply);
2249 throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
2250 else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
2251 throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
2252 else if (strReply.empty())
2253 throw runtime_error("no response from server");
2257 if (!read_string(strReply, valReply))
2258 throw runtime_error("couldn't parse reply from server");
2259 const Object& reply = valReply.get_obj();
2261 throw runtime_error("expected reply to have result, error and id properties");
2269 template<typename T>
2270 void ConvertTo(Value& value)
2272 if (value.type() == str_type)
2274 // reinterpret string as unquoted json value
2276 if (!read_string(value.get_str(), value2))
2277 throw runtime_error("type mismatch");
2278 value = value2.get_value<T>();
2282 value = value.get_value<T>();
2286 int CommandLineRPC(int argc, char *argv[])
2293 while (argc > 1 && IsSwitchChar(argv[1][0]))
2301 throw runtime_error("too few parameters");
2302 string strMethod = argv[1];
2304 // Parameters default to strings
2306 for (int i = 2; i < argc; i++)
2307 params.push_back(argv[i]);
2308 int n = params.size();
2311 // Special case non-string parameter types
2313 if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
2314 if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2315 if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
2316 if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]);
2317 if (strMethod == "getamountreceived" && n > 1) ConvertTo<boost::int64_t>(params[1]); // deprecated
2318 if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2319 if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2320 if (strMethod == "getreceivedbylabel" && n > 1) ConvertTo<boost::int64_t>(params[1]); // deprecated
2321 if (strMethod == "getallreceived" && n > 0) ConvertTo<boost::int64_t>(params[0]); // deprecated
2322 if (strMethod == "getallreceived" && n > 1) ConvertTo<bool>(params[1]); // deprecated
2323 if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2324 if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
2325 if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2326 if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
2327 if (strMethod == "listreceivedbylabel" && n > 0) ConvertTo<boost::int64_t>(params[0]); // deprecated
2328 if (strMethod == "listreceivedbylabel" && n > 1) ConvertTo<bool>(params[1]); // deprecated
2329 if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2330 if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]);
2331 if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2332 if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]);
2333 if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2334 if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2335 if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2336 if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2337 if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2338 if (strMethod == "sendmany" && n > 1)
2340 string s = params[1].get_str();
2342 if (!read_string(s, v) || v.type() != obj_type)
2343 throw runtime_error("type mismatch");
2344 params[1] = v.get_obj();
2346 if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2349 Object reply = CallRPC(strMethod, params);
2352 const Value& result = find_value(reply, "result");
2353 const Value& error = find_value(reply, "error");
2355 if (error.type() != null_type)
2358 strPrint = "error: " + write_string(error, false);
2359 int code = find_value(error.get_obj(), "code").get_int();
2365 if (result.type() == null_type)
2367 else if (result.type() == str_type)
2368 strPrint = result.get_str();
2370 strPrint = write_string(result, true);
2373 catch (std::exception& e)
2375 strPrint = string("error: ") + e.what();
2380 PrintException(NULL, "CommandLineRPC()");
2385 fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
2394 int main(int argc, char *argv[])
2397 // Turn off microsoft heap dump noise
2398 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
2399 _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
2401 setbuf(stdin, NULL);
2402 setbuf(stdout, NULL);
2403 setbuf(stderr, NULL);
2407 if (argc >= 2 && string(argv[1]) == "-server")
2409 printf("server ready\n");
2410 ThreadRPCServer(NULL);
2414 return CommandLineRPC(argc, argv);
2417 catch (std::exception& e) {
2418 PrintException(&e, "main()");
2420 PrintException(NULL, "main()");