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.
11 #include <boost/asio.hpp>
12 #include <boost/iostreams/concepts.hpp>
13 #include <boost/iostreams/stream.hpp>
14 #include <boost/algorithm/string.hpp>
16 #include <boost/asio/ssl.hpp>
17 #include <boost/filesystem.hpp>
18 #include <boost/filesystem/fstream.hpp>
19 typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> SSLStream;
21 #include "json/json_spirit_reader_template.h"
22 #include "json/json_spirit_writer_template.h"
23 #include "json/json_spirit_utils.h"
24 #define printf OutputDebugStringF
25 // MinGW 3.4.5 gets "fatal error: had to relocate PCH" if the json headers are
26 // precompiled in headers.h. The problem might be when the pch file goes over
27 // a certain size around 145MB. If we need access to json_spirit outside this
28 // file, we could use the compiled json_spirit option.
31 using namespace boost;
32 using namespace boost::asio;
33 using namespace json_spirit;
35 void ThreadRPCServer2(void* parg);
36 typedef Value(*rpcfn_type)(const Array& params, bool fHelp);
37 extern map<string, rpcfn_type> mapCallTable;
39 static int64 nWalletUnlockTime;
40 static CCriticalSection cs_nWalletUnlockTime;
43 Object JSONRPCError(int code, const string& message)
46 error.push_back(Pair("code", code));
47 error.push_back(Pair("message", message));
52 void PrintConsole(const std::string &format, ...)
55 int limit = sizeof(buffer);
57 va_start(arg_ptr, format);
58 int ret = _vsnprintf(buffer, limit, format.c_str(), arg_ptr);
60 if (ret < 0 || ret >= limit)
66 fprintf(stdout, "%s", buffer);
70 int64 AmountFromValue(const Value& value)
72 double dAmount = value.get_real();
73 if (dAmount <= 0.0 || dAmount > 21000000.0)
74 throw JSONRPCError(-3, "Invalid amount");
75 int64 nAmount = roundint64(dAmount * COIN);
76 if (!MoneyRange(nAmount))
77 throw JSONRPCError(-3, "Invalid amount");
81 Value ValueFromAmount(int64 amount)
83 return (double)amount / (double)COIN;
86 void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
88 entry.push_back(Pair("confirmations", wtx.GetDepthInMainChain()));
89 entry.push_back(Pair("txid", wtx.GetHash().GetHex()));
90 entry.push_back(Pair("time", (boost::int64_t)wtx.GetTxTime()));
91 BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
92 entry.push_back(Pair(item.first, item.second));
95 string AccountFromValue(const Value& value)
97 string strAccount = value.get_str();
98 if (strAccount == "*")
99 throw JSONRPCError(-11, "Invalid account name");
106 /// Note: This interface may still be subject to change.
110 Value help(const Array& params, bool fHelp)
112 if (fHelp || params.size() > 1)
115 "List commands, or get help for a command.");
118 if (params.size() > 0)
119 strCommand = params[0].get_str();
122 set<rpcfn_type> setDone;
123 for (map<string, rpcfn_type>::iterator mi = mapCallTable.begin(); mi != mapCallTable.end(); ++mi)
125 string strMethod = (*mi).first;
126 // We already filter duplicates, but these deprecated screw up the sort order
127 if (strMethod == "getamountreceived" ||
128 strMethod == "getallreceived" ||
129 (strMethod.find("label") != string::npos))
131 if (strCommand != "" && strMethod != strCommand)
136 rpcfn_type pfn = (*mi).second;
137 if (setDone.insert(pfn).second)
138 (*pfn)(params, true);
140 catch (std::exception& e)
142 // Help text is returned in an exception
143 string strHelp = string(e.what());
144 if (strCommand == "")
145 if (strHelp.find('\n') != -1)
146 strHelp = strHelp.substr(0, strHelp.find('\n'));
147 strRet += strHelp + "\n";
151 strRet = strprintf("help: unknown command: %s\n", strCommand.c_str());
152 strRet = strRet.substr(0,strRet.size()-1);
157 Value stop(const Array& params, bool fHelp)
159 if (fHelp || params.size() != 0)
162 "Stop bitcoin server.");
164 // Shutdown will take long enough that the response should get back
165 CreateThread(Shutdown, NULL);
166 return "bitcoin server stopping";
168 throw runtime_error("NYI: cannot shut down GUI with RPC command");
173 Value getblockcount(const Array& params, bool fHelp)
175 if (fHelp || params.size() != 0)
178 "Returns the number of blocks in the longest block chain.");
184 Value getblocknumber(const Array& params, bool fHelp)
186 if (fHelp || params.size() != 0)
189 "Returns the block number of the latest block in the longest block chain.");
195 Value getconnectioncount(const Array& params, bool fHelp)
197 if (fHelp || params.size() != 0)
199 "getconnectioncount\n"
200 "Returns the number of connections to other nodes.");
202 return (int)vNodes.size();
206 double GetDifficulty()
208 // Floating point number that is a multiple of the minimum difficulty,
209 // minimum difficulty = 1.0.
211 if (pindexBest == NULL)
213 int nShift = (pindexBest->nBits >> 24) & 0xff;
216 (double)0x0000ffff / (double)(pindexBest->nBits & 0x00ffffff);
232 Value getdifficulty(const Array& params, bool fHelp)
234 if (fHelp || params.size() != 0)
237 "Returns the proof-of-work difficulty as a multiple of the minimum difficulty.");
239 return GetDifficulty();
243 Value getgenerate(const Array& params, bool fHelp)
245 if (fHelp || params.size() != 0)
248 "Returns true or false.");
250 return (bool)fGenerateBitcoins;
254 Value setgenerate(const Array& params, bool fHelp)
256 if (fHelp || params.size() < 1 || params.size() > 2)
258 "setgenerate <generate> [genproclimit]\n"
259 "<generate> is true or false to turn generation on or off.\n"
260 "Generation is limited to [genproclimit] processors, -1 is unlimited.");
262 bool fGenerate = true;
263 if (params.size() > 0)
264 fGenerate = params[0].get_bool();
266 if (params.size() > 1)
268 int nGenProcLimit = params[1].get_int();
269 fLimitProcessors = (nGenProcLimit != -1);
270 WriteSetting("fLimitProcessors", fLimitProcessors);
271 if (nGenProcLimit != -1)
272 WriteSetting("nLimitProcessors", nLimitProcessors = nGenProcLimit);
273 if (nGenProcLimit == 0)
277 GenerateBitcoins(fGenerate, pwalletMain);
282 Value gethashespersec(const Array& params, bool fHelp)
284 if (fHelp || params.size() != 0)
287 "Returns a recent hashes per second performance measurement while generating.");
289 if (GetTimeMillis() - nHPSTimerStart > 8000)
290 return (boost::int64_t)0;
291 return (boost::int64_t)dHashesPerSec;
295 Value getinfo(const Array& params, bool fHelp)
297 if (fHelp || params.size() != 0)
300 "Returns an object containing various state info.");
303 obj.push_back(Pair("version", (int)VERSION));
304 obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
305 obj.push_back(Pair("blocks", (int)nBestHeight));
306 obj.push_back(Pair("connections", (int)vNodes.size()));
307 obj.push_back(Pair("proxy", (fUseProxy ? addrProxy.ToStringIPPort() : string())));
308 obj.push_back(Pair("generate", (bool)fGenerateBitcoins));
309 obj.push_back(Pair("genproclimit", (int)(fLimitProcessors ? nLimitProcessors : -1)));
310 obj.push_back(Pair("difficulty", (double)GetDifficulty()));
311 obj.push_back(Pair("hashespersec", gethashespersec(params, false)));
312 obj.push_back(Pair("testnet", fTestNet));
313 obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));
314 obj.push_back(Pair("keypoolsize", pwalletMain->GetKeyPoolSize()));
315 obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee)));
316 if (pwalletMain->IsCrypted())
317 obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime));
318 obj.push_back(Pair("errors", GetWarnings("statusbar")));
323 Value getnewaddress(const Array& params, bool fHelp)
325 if (fHelp || params.size() > 1)
327 "getnewaddress [account]\n"
328 "Returns a new bitcoin address for receiving payments. "
329 "If [account] is specified (recommended), it is added to the address book "
330 "so payments received with the address will be credited to [account].");
332 // Parse the account first so we don't generate a key if there's an error
334 if (params.size() > 0)
335 strAccount = AccountFromValue(params[0]);
337 if (!pwalletMain->IsLocked())
338 pwalletMain->TopUpKeyPool();
340 // Generate a new key that is added to wallet
341 std::vector<unsigned char> newKey;
342 if (!pwalletMain->GetKeyFromPool(newKey, false))
343 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
344 CBitcoinAddress address(newKey);
346 pwalletMain->SetAddressBookName(address, strAccount);
348 return address.ToString();
352 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
354 CWalletDB walletdb(pwalletMain->strWalletFile);
357 walletdb.ReadAccount(strAccount, account);
359 bool bKeyUsed = false;
361 // Check if the current key has been used
362 if (!account.vchPubKey.empty())
364 CScript scriptPubKey;
365 scriptPubKey.SetBitcoinAddress(account.vchPubKey);
366 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
367 it != pwalletMain->mapWallet.end() && !account.vchPubKey.empty();
370 const CWalletTx& wtx = (*it).second;
371 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
372 if (txout.scriptPubKey == scriptPubKey)
377 // Generate a new key
378 if (account.vchPubKey.empty() || bForceNew || bKeyUsed)
380 if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false))
381 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
383 pwalletMain->SetAddressBookName(CBitcoinAddress(account.vchPubKey), strAccount);
384 walletdb.WriteAccount(strAccount, account);
387 return CBitcoinAddress(account.vchPubKey);
390 Value getaccountaddress(const Array& params, bool fHelp)
392 if (fHelp || params.size() != 1)
394 "getaccountaddress <account>\n"
395 "Returns the current bitcoin address for receiving payments to this account.");
397 // Parse the account first so we don't generate a key if there's an error
398 string strAccount = AccountFromValue(params[0]);
402 ret = GetAccountAddress(strAccount).ToString();
409 Value setaccount(const Array& params, bool fHelp)
411 if (fHelp || params.size() < 1 || params.size() > 2)
413 "setaccount <bitcoinaddress> <account>\n"
414 "Sets the account associated with the given address.");
416 CBitcoinAddress address(params[0].get_str());
417 if (!address.IsValid())
418 throw JSONRPCError(-5, "Invalid bitcoin address");
422 if (params.size() > 1)
423 strAccount = AccountFromValue(params[1]);
425 // Detect when changing the account of an address that is the 'unused current key' of another account:
426 if (pwalletMain->mapAddressBook.count(address))
428 string strOldAccount = pwalletMain->mapAddressBook[address];
429 if (address == GetAccountAddress(strOldAccount))
430 GetAccountAddress(strOldAccount, true);
433 pwalletMain->SetAddressBookName(address, strAccount);
439 Value getaccount(const Array& params, bool fHelp)
441 if (fHelp || params.size() != 1)
443 "getaccount <bitcoinaddress>\n"
444 "Returns the account associated with the given address.");
446 CBitcoinAddress address(params[0].get_str());
447 if (!address.IsValid())
448 throw JSONRPCError(-5, "Invalid bitcoin address");
451 map<CBitcoinAddress, string>::iterator mi = pwalletMain->mapAddressBook.find(address);
452 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
453 strAccount = (*mi).second;
458 Value getaddressesbyaccount(const Array& params, bool fHelp)
460 if (fHelp || params.size() != 1)
462 "getaddressesbyaccount <account>\n"
463 "Returns the list of addresses for the given account.");
465 string strAccount = AccountFromValue(params[0]);
467 // Find all addresses that have the given account
469 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
471 const CBitcoinAddress& address = item.first;
472 const string& strName = item.second;
473 if (strName == strAccount)
474 ret.push_back(address.ToString());
479 Value settxfee(const Array& params, bool fHelp)
481 if (fHelp || params.size() < 1 || params.size() > 1)
483 "settxfee <amount>\n"
484 "<amount> is a real and is rounded to the nearest 0.00000001");
488 if (params[0].get_real() != 0.0)
489 nAmount = AmountFromValue(params[0]); // rejects 0.0 amounts
491 nTransactionFee = nAmount;
495 Value sendtoaddress(const Array& params, bool fHelp)
497 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
499 "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
500 "<amount> is a real and is rounded to the nearest 0.00000001\n"
501 "requires wallet passphrase to be set with walletpassphrase first");
502 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
504 "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
505 "<amount> is a real and is rounded to the nearest 0.00000001");
507 CBitcoinAddress address(params[0].get_str());
508 if (!address.IsValid())
509 throw JSONRPCError(-5, "Invalid bitcoin address");
512 int64 nAmount = AmountFromValue(params[1]);
516 if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
517 wtx.mapValue["comment"] = params[2].get_str();
518 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
519 wtx.mapValue["to"] = params[3].get_str();
521 if (pwalletMain->IsLocked())
522 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
524 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
526 throw JSONRPCError(-4, strError);
528 return wtx.GetHash().GetHex();
531 static const string strMessageMagic = "Bitcoin Signed Message:\n";
533 Value signmessage(const Array& params, bool fHelp)
535 if (fHelp || params.size() != 2)
537 "signmessage <bitcoinaddress> <message>\n"
538 "Sign a message with the private key of an address");
540 if (pwalletMain->IsLocked())
541 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
543 string strAddress = params[0].get_str();
544 string strMessage = params[1].get_str();
546 CBitcoinAddress addr(strAddress);
548 throw JSONRPCError(-3, "Invalid address");
551 if (!pwalletMain->GetKey(addr, key))
552 throw JSONRPCError(-4, "Private key not available");
554 CDataStream ss(SER_GETHASH);
555 ss << strMessageMagic;
558 vector<unsigned char> vchSig;
559 if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig))
560 throw JSONRPCError(-5, "Sign failed");
562 return EncodeBase64(&vchSig[0], vchSig.size());
565 Value verifymessage(const Array& params, bool fHelp)
567 if (fHelp || params.size() != 3)
569 "verifymessage <bitcoinaddress> <signature> <message>\n"
570 "Verify a signed message");
572 string strAddress = params[0].get_str();
573 string strSign = params[1].get_str();
574 string strMessage = params[2].get_str();
576 CBitcoinAddress addr(strAddress);
578 throw JSONRPCError(-3, "Invalid address");
580 bool fInvalid = false;
581 vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
584 throw JSONRPCError(-5, "Malformed base64 encoding");
586 CDataStream ss(SER_GETHASH);
587 ss << strMessageMagic;
591 if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
594 return (key.GetAddress() == addr);
598 Value getreceivedbyaddress(const Array& params, bool fHelp)
600 if (fHelp || params.size() < 1 || params.size() > 2)
602 "getreceivedbyaddress <bitcoinaddress> [minconf=1]\n"
603 "Returns the total amount received by <bitcoinaddress> in transactions with at least [minconf] confirmations.");
606 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
607 CScript scriptPubKey;
608 if (!address.IsValid())
609 throw JSONRPCError(-5, "Invalid bitcoin address");
610 scriptPubKey.SetBitcoinAddress(address);
611 if (!IsMine(*pwalletMain,scriptPubKey))
614 // Minimum confirmations
616 if (params.size() > 1)
617 nMinDepth = params[1].get_int();
621 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
623 const CWalletTx& wtx = (*it).second;
624 if (wtx.IsCoinBase() || !wtx.IsFinal())
627 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
628 if (txout.scriptPubKey == scriptPubKey)
629 if (wtx.GetDepthInMainChain() >= nMinDepth)
630 nAmount += txout.nValue;
633 return ValueFromAmount(nAmount);
637 void GetAccountAddresses(string strAccount, set<CBitcoinAddress>& setAddress)
639 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
641 const CBitcoinAddress& address = item.first;
642 const string& strName = item.second;
643 if (strName == strAccount)
644 setAddress.insert(address);
649 Value getreceivedbyaccount(const Array& params, bool fHelp)
651 if (fHelp || params.size() < 1 || params.size() > 2)
653 "getreceivedbyaccount <account> [minconf=1]\n"
654 "Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.");
656 // Minimum confirmations
658 if (params.size() > 1)
659 nMinDepth = params[1].get_int();
661 // Get the set of pub keys that have the label
662 string strAccount = AccountFromValue(params[0]);
663 set<CBitcoinAddress> setAddress;
664 GetAccountAddresses(strAccount, setAddress);
668 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
670 const CWalletTx& wtx = (*it).second;
671 if (wtx.IsCoinBase() || !wtx.IsFinal())
674 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
676 CBitcoinAddress address;
677 if (ExtractAddress(txout.scriptPubKey, pwalletMain, address) && setAddress.count(address))
678 if (wtx.GetDepthInMainChain() >= nMinDepth)
679 nAmount += txout.nValue;
683 return (double)nAmount / (double)COIN;
687 int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth)
691 // Tally wallet transactions
692 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
694 const CWalletTx& wtx = (*it).second;
698 int64 nGenerated, nReceived, nSent, nFee;
699 wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee);
701 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
702 nBalance += nReceived;
703 nBalance += nGenerated - nSent - nFee;
706 // Tally internal accounting entries
707 nBalance += walletdb.GetAccountCreditDebit(strAccount);
712 int64 GetAccountBalance(const string& strAccount, int nMinDepth)
714 CWalletDB walletdb(pwalletMain->strWalletFile);
715 return GetAccountBalance(walletdb, strAccount, nMinDepth);
719 Value getbalance(const Array& params, bool fHelp)
721 if (fHelp || params.size() > 2)
723 "getbalance [account] [minconf=1]\n"
724 "If [account] is not specified, returns the server's total available balance.\n"
725 "If [account] is specified, returns the balance in the account.");
727 if (params.size() == 0)
728 return ValueFromAmount(pwalletMain->GetBalance());
731 if (params.size() > 1)
732 nMinDepth = params[1].get_int();
734 if (params[0].get_str() == "*") {
735 // Calculate total balance a different way from GetBalance()
736 // (GetBalance() sums up all unspent TxOuts)
737 // getbalance and getbalance '*' should always return the same number.
739 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
741 const CWalletTx& wtx = (*it).second;
745 int64 allGeneratedImmature, allGeneratedMature, allFee;
746 allGeneratedImmature = allGeneratedMature = allFee = 0;
747 string strSentAccount;
748 list<pair<CBitcoinAddress, int64> > listReceived;
749 list<pair<CBitcoinAddress, int64> > listSent;
750 wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
751 if (wtx.GetDepthInMainChain() >= nMinDepth)
752 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listReceived)
753 nBalance += r.second;
754 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listSent)
755 nBalance -= r.second;
757 nBalance += allGeneratedMature;
759 return ValueFromAmount(nBalance);
762 string strAccount = AccountFromValue(params[0]);
764 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
766 return ValueFromAmount(nBalance);
770 Value movecmd(const Array& params, bool fHelp)
772 if (fHelp || params.size() < 3 || params.size() > 5)
774 "move <fromaccount> <toaccount> <amount> [minconf=1] [comment]\n"
775 "Move from one account in your wallet to another.");
777 string strFrom = AccountFromValue(params[0]);
778 string strTo = AccountFromValue(params[1]);
779 int64 nAmount = AmountFromValue(params[2]);
780 if (params.size() > 3)
781 // unused parameter, used to be nMinDepth, keep type-checking it though
782 (void)params[3].get_int();
784 if (params.size() > 4)
785 strComment = params[4].get_str();
787 CWalletDB walletdb(pwalletMain->strWalletFile);
790 int64 nNow = GetAdjustedTime();
793 CAccountingEntry debit;
794 debit.strAccount = strFrom;
795 debit.nCreditDebit = -nAmount;
797 debit.strOtherAccount = strTo;
798 debit.strComment = strComment;
799 walletdb.WriteAccountingEntry(debit);
802 CAccountingEntry credit;
803 credit.strAccount = strTo;
804 credit.nCreditDebit = nAmount;
806 credit.strOtherAccount = strFrom;
807 credit.strComment = strComment;
808 walletdb.WriteAccountingEntry(credit);
810 walletdb.TxnCommit();
816 Value sendfrom(const Array& params, bool fHelp)
818 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
820 "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
821 "<amount> is a real and is rounded to the nearest 0.00000001\n"
822 "requires wallet passphrase to be set with walletpassphrase first");
823 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
825 "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
826 "<amount> is a real and is rounded to the nearest 0.00000001");
828 string strAccount = AccountFromValue(params[0]);
829 CBitcoinAddress address(params[1].get_str());
830 if (!address.IsValid())
831 throw JSONRPCError(-5, "Invalid bitcoin address");
832 int64 nAmount = AmountFromValue(params[2]);
834 if (params.size() > 3)
835 nMinDepth = params[3].get_int();
838 wtx.strFromAccount = strAccount;
839 if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
840 wtx.mapValue["comment"] = params[4].get_str();
841 if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
842 wtx.mapValue["to"] = params[5].get_str();
844 if (pwalletMain->IsLocked())
845 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
848 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
849 if (nAmount > nBalance)
850 throw JSONRPCError(-6, "Account has insufficient funds");
853 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
855 throw JSONRPCError(-4, strError);
857 return wtx.GetHash().GetHex();
861 Value sendmany(const Array& params, bool fHelp)
863 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
865 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
866 "amounts are double-precision floating point numbers\n"
867 "requires wallet passphrase to be set with walletpassphrase first");
868 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
870 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
871 "amounts are double-precision floating point numbers");
873 string strAccount = AccountFromValue(params[0]);
874 Object sendTo = params[1].get_obj();
876 if (params.size() > 2)
877 nMinDepth = params[2].get_int();
880 wtx.strFromAccount = strAccount;
881 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
882 wtx.mapValue["comment"] = params[3].get_str();
884 set<CBitcoinAddress> setAddress;
885 vector<pair<CScript, int64> > vecSend;
887 int64 totalAmount = 0;
888 BOOST_FOREACH(const Pair& s, sendTo)
890 CBitcoinAddress address(s.name_);
891 if (!address.IsValid())
892 throw JSONRPCError(-5, string("Invalid bitcoin address:")+s.name_);
894 if (setAddress.count(address))
895 throw JSONRPCError(-8, string("Invalid parameter, duplicated address: ")+s.name_);
896 setAddress.insert(address);
898 CScript scriptPubKey;
899 scriptPubKey.SetBitcoinAddress(address);
900 int64 nAmount = AmountFromValue(s.value_);
901 totalAmount += nAmount;
903 vecSend.push_back(make_pair(scriptPubKey, nAmount));
906 if (pwalletMain->IsLocked())
907 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
910 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
911 if (totalAmount > nBalance)
912 throw JSONRPCError(-6, "Account has insufficient funds");
915 CReserveKey keyChange(pwalletMain);
916 int64 nFeeRequired = 0;
917 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
920 if (totalAmount + nFeeRequired > pwalletMain->GetBalance())
921 throw JSONRPCError(-6, "Insufficient funds");
922 throw JSONRPCError(-4, "Transaction creation failed");
924 if (!pwalletMain->CommitTransaction(wtx, keyChange))
925 throw JSONRPCError(-4, "Transaction commit failed");
927 return wtx.GetHash().GetHex();
942 Value ListReceived(const Array& params, bool fByAccounts)
944 // Minimum confirmations
946 if (params.size() > 0)
947 nMinDepth = params[0].get_int();
949 // Whether to include empty accounts
950 bool fIncludeEmpty = false;
951 if (params.size() > 1)
952 fIncludeEmpty = params[1].get_bool();
955 map<CBitcoinAddress, tallyitem> mapTally;
956 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
958 const CWalletTx& wtx = (*it).second;
959 if (wtx.IsCoinBase() || !wtx.IsFinal())
962 int nDepth = wtx.GetDepthInMainChain();
963 if (nDepth < nMinDepth)
966 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
968 CBitcoinAddress address;
969 if (!ExtractAddress(txout.scriptPubKey, pwalletMain, address) || !address.IsValid())
972 tallyitem& item = mapTally[address];
973 item.nAmount += txout.nValue;
974 item.nConf = min(item.nConf, nDepth);
980 map<string, tallyitem> mapAccountTally;
981 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
983 const CBitcoinAddress& address = item.first;
984 const string& strAccount = item.second;
985 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
986 if (it == mapTally.end() && !fIncludeEmpty)
991 if (it != mapTally.end())
993 nAmount = (*it).second.nAmount;
994 nConf = (*it).second.nConf;
999 tallyitem& item = mapAccountTally[strAccount];
1000 item.nAmount += nAmount;
1001 item.nConf = min(item.nConf, nConf);
1006 obj.push_back(Pair("address", address.ToString()));
1007 obj.push_back(Pair("account", strAccount));
1008 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1009 obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
1016 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
1018 int64 nAmount = (*it).second.nAmount;
1019 int nConf = (*it).second.nConf;
1021 obj.push_back(Pair("account", (*it).first));
1022 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1023 obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
1031 Value listreceivedbyaddress(const Array& params, bool fHelp)
1033 if (fHelp || params.size() > 2)
1034 throw runtime_error(
1035 "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
1036 "[minconf] is the minimum number of confirmations before payments are included.\n"
1037 "[includeempty] whether to include addresses that haven't received any payments.\n"
1038 "Returns an array of objects containing:\n"
1039 " \"address\" : receiving address\n"
1040 " \"account\" : the account of the receiving address\n"
1041 " \"amount\" : total amount received by the address\n"
1042 " \"confirmations\" : number of confirmations of the most recent transaction included");
1044 return ListReceived(params, false);
1047 Value listreceivedbyaccount(const Array& params, bool fHelp)
1049 if (fHelp || params.size() > 2)
1050 throw runtime_error(
1051 "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
1052 "[minconf] is the minimum number of confirmations before payments are included.\n"
1053 "[includeempty] whether to include accounts that haven't received any payments.\n"
1054 "Returns an array of objects containing:\n"
1055 " \"account\" : the account of the receiving addresses\n"
1056 " \"amount\" : total amount received by addresses with this account\n"
1057 " \"confirmations\" : number of confirmations of the most recent transaction included");
1059 return ListReceived(params, true);
1062 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret)
1064 int64 nGeneratedImmature, nGeneratedMature, nFee;
1065 string strSentAccount;
1066 list<pair<CBitcoinAddress, int64> > listReceived;
1067 list<pair<CBitcoinAddress, int64> > listSent;
1068 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1070 bool fAllAccounts = (strAccount == string("*"));
1072 // Generated blocks assigned to account ""
1073 if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == ""))
1076 entry.push_back(Pair("account", string("")));
1077 if (nGeneratedImmature)
1079 entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
1080 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
1084 entry.push_back(Pair("category", "generate"));
1085 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
1088 WalletTxToJSON(wtx, entry);
1089 ret.push_back(entry);
1093 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1095 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1098 entry.push_back(Pair("account", strSentAccount));
1099 entry.push_back(Pair("address", s.first.ToString()));
1100 entry.push_back(Pair("category", "send"));
1101 entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1102 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1104 WalletTxToJSON(wtx, entry);
1105 ret.push_back(entry);
1110 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1111 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1114 if (pwalletMain->mapAddressBook.count(r.first))
1115 account = pwalletMain->mapAddressBook[r.first];
1116 if (fAllAccounts || (account == strAccount))
1119 entry.push_back(Pair("account", account));
1120 entry.push_back(Pair("address", r.first.ToString()));
1121 entry.push_back(Pair("category", "receive"));
1122 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1124 WalletTxToJSON(wtx, entry);
1125 ret.push_back(entry);
1130 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1132 bool fAllAccounts = (strAccount == string("*"));
1134 if (fAllAccounts || acentry.strAccount == strAccount)
1137 entry.push_back(Pair("account", acentry.strAccount));
1138 entry.push_back(Pair("category", "move"));
1139 entry.push_back(Pair("time", (boost::int64_t)acentry.nTime));
1140 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1141 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1142 entry.push_back(Pair("comment", acentry.strComment));
1143 ret.push_back(entry);
1147 Value listtransactions(const Array& params, bool fHelp)
1149 if (fHelp || params.size() > 3)
1150 throw runtime_error(
1151 "listtransactions [account] [count=10] [from=0]\n"
1152 "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1154 string strAccount = "*";
1155 if (params.size() > 0)
1156 strAccount = params[0].get_str();
1158 if (params.size() > 1)
1159 nCount = params[1].get_int();
1161 if (params.size() > 2)
1162 nFrom = params[2].get_int();
1165 CWalletDB walletdb(pwalletMain->strWalletFile);
1167 // Firs: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap:
1168 typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
1169 typedef multimap<int64, TxPair > TxItems;
1172 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1174 CWalletTx* wtx = &((*it).second);
1175 txByTime.insert(make_pair(wtx->GetTxTime(), TxPair(wtx, (CAccountingEntry*)0)));
1177 list<CAccountingEntry> acentries;
1178 walletdb.ListAccountCreditDebit(strAccount, acentries);
1179 BOOST_FOREACH(CAccountingEntry& entry, acentries)
1181 txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
1184 // Now: iterate backwards until we have nCount items to return:
1185 TxItems::reverse_iterator it = txByTime.rbegin();
1186 if (txByTime.size() > nFrom) std::advance(it, nFrom);
1187 for (; it != txByTime.rend(); ++it)
1189 CWalletTx *const pwtx = (*it).second.first;
1191 ListTransactions(*pwtx, strAccount, 0, true, ret);
1192 CAccountingEntry *const pacentry = (*it).second.second;
1194 AcentryToJSON(*pacentry, strAccount, ret);
1196 if (ret.size() >= nCount) break;
1198 // ret is now newest to oldest
1200 // Make sure we return only last nCount items (sends-to-self might give us an extra):
1201 if (ret.size() > nCount)
1203 Array::iterator last = ret.begin();
1204 std::advance(last, nCount);
1205 ret.erase(last, ret.end());
1207 std::reverse(ret.begin(), ret.end()); // oldest to newest
1212 Value listaccounts(const Array& params, bool fHelp)
1214 if (fHelp || params.size() > 1)
1215 throw runtime_error(
1216 "listaccounts [minconf=1]\n"
1217 "Returns Object that has account names as keys, account balances as values.");
1220 if (params.size() > 0)
1221 nMinDepth = params[0].get_int();
1223 map<string, int64> mapAccountBalances;
1224 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& entry, pwalletMain->mapAddressBook) {
1225 if (pwalletMain->HaveKey(entry.first)) // This address belongs to me
1226 mapAccountBalances[entry.second] = 0;
1229 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1231 const CWalletTx& wtx = (*it).second;
1232 int64 nGeneratedImmature, nGeneratedMature, nFee;
1233 string strSentAccount;
1234 list<pair<CBitcoinAddress, int64> > listReceived;
1235 list<pair<CBitcoinAddress, int64> > listSent;
1236 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1237 mapAccountBalances[strSentAccount] -= nFee;
1238 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1239 mapAccountBalances[strSentAccount] -= s.second;
1240 if (wtx.GetDepthInMainChain() >= nMinDepth)
1242 mapAccountBalances[""] += nGeneratedMature;
1243 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1244 if (pwalletMain->mapAddressBook.count(r.first))
1245 mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1247 mapAccountBalances[""] += r.second;
1251 list<CAccountingEntry> acentries;
1252 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1253 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1254 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1257 BOOST_FOREACH(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) {
1258 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1263 Value listsinceblock(const Array& params, bool fHelp)
1266 throw runtime_error(
1267 "listsinceblock [blockid] [target-confirmations]\n"
1268 "Get all transactions in blocks since block [blockid], or all transactions if omitted");
1270 CBlockIndex *pindex = NULL;
1271 int target_confirms = 1;
1273 if (params.size() > 0)
1275 uint256 blockId = 0;
1277 blockId.SetHex(params[0].get_str());
1278 pindex = CBlockLocator(blockId).GetBlockIndex();
1281 if (params.size() > 1)
1283 target_confirms = params[1].get_int();
1285 if (target_confirms < 1)
1286 throw JSONRPCError(-8, "Invalid parameter");
1289 int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1;
1293 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1295 CWalletTx tx = (*it).second;
1297 if (depth == -1 || tx.GetDepthInMainChain() < depth)
1298 ListTransactions(tx, "*", 0, true, transactions);
1303 if (target_confirms == 1)
1306 lastblock = hashBestChain;
1310 int target_height = pindexBest->nHeight + 1 - target_confirms;
1313 for (block = pindexBest;
1314 block && block->nHeight > target_height;
1315 block = block->pprev);
1317 lastblock = block ? block->GetBlockHash() : 0;
1321 ret.push_back(Pair("transactions", transactions));
1322 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1327 Value gettransaction(const Array& params, bool fHelp)
1329 if (fHelp || params.size() != 1)
1330 throw runtime_error(
1331 "gettransaction <txid>\n"
1332 "Get detailed information about <txid>");
1335 hash.SetHex(params[0].get_str());
1339 if (!pwalletMain->mapWallet.count(hash))
1340 throw JSONRPCError(-5, "Invalid or non-wallet transaction id");
1341 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1343 int64 nCredit = wtx.GetCredit();
1344 int64 nDebit = wtx.GetDebit();
1345 int64 nNet = nCredit - nDebit;
1346 int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
1348 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1350 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1352 WalletTxToJSON(pwalletMain->mapWallet[hash], entry);
1355 ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
1356 entry.push_back(Pair("details", details));
1362 Value backupwallet(const Array& params, bool fHelp)
1364 if (fHelp || params.size() != 1)
1365 throw runtime_error(
1366 "backupwallet <destination>\n"
1367 "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1369 string strDest = params[0].get_str();
1370 BackupWallet(*pwalletMain, strDest);
1376 Value keypoolrefill(const Array& params, bool fHelp)
1378 if (pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1379 throw runtime_error(
1381 "Fills the keypool, requires wallet passphrase to be set.");
1382 if (!pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1383 throw runtime_error(
1385 "Fills the keypool.");
1387 if (pwalletMain->IsLocked())
1388 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
1390 pwalletMain->TopUpKeyPool();
1392 if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100))
1393 throw JSONRPCError(-4, "Error refreshing keypool.");
1399 void ThreadTopUpKeyPool(void* parg)
1401 pwalletMain->TopUpKeyPool();
1404 void ThreadCleanWalletPassphrase(void* parg)
1406 int64 nMyWakeTime = GetTime() + *((int*)parg);
1408 if (nWalletUnlockTime == 0)
1410 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1412 nWalletUnlockTime = nMyWakeTime;
1415 while (GetTime() < nWalletUnlockTime)
1416 Sleep(GetTime() - nWalletUnlockTime);
1418 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1420 nWalletUnlockTime = 0;
1425 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1427 if (nWalletUnlockTime < nMyWakeTime)
1428 nWalletUnlockTime = nMyWakeTime;
1434 pwalletMain->Lock();
1439 Value walletpassphrase(const Array& params, bool fHelp)
1441 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1442 throw runtime_error(
1443 "walletpassphrase <passphrase> <timeout>\n"
1444 "Stores the wallet decryption key in memory for <timeout> seconds.");
1447 if (!pwalletMain->IsCrypted())
1448 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1450 if (!pwalletMain->IsLocked())
1451 throw JSONRPCError(-17, "Error: Wallet is already unlocked.");
1453 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1454 SecureString strWalletPass;
1455 strWalletPass.reserve(100);
1456 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1457 // Alternately, find a way to make params[0] mlock()'d to begin with.
1458 strWalletPass = params[0].get_str().c_str();
1460 if (strWalletPass.length() > 0)
1462 if (!pwalletMain->Unlock(strWalletPass))
1463 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1466 throw runtime_error(
1467 "walletpassphrase <passphrase> <timeout>\n"
1468 "Stores the wallet decryption key in memory for <timeout> seconds.");
1470 CreateThread(ThreadTopUpKeyPool, NULL);
1471 int* pnSleepTime = new int(params[1].get_int());
1472 CreateThread(ThreadCleanWalletPassphrase, pnSleepTime);
1478 Value walletpassphrasechange(const Array& params, bool fHelp)
1480 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1481 throw runtime_error(
1482 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1483 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1486 if (!pwalletMain->IsCrypted())
1487 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1489 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1490 // Alternately, find a way to make params[0] mlock()'d to begin with.
1491 SecureString strOldWalletPass;
1492 strOldWalletPass.reserve(100);
1493 strOldWalletPass = params[0].get_str().c_str();
1495 SecureString strNewWalletPass;
1496 strNewWalletPass.reserve(100);
1497 strNewWalletPass = params[1].get_str().c_str();
1499 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1500 throw runtime_error(
1501 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1502 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1504 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1505 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1511 Value walletlock(const Array& params, bool fHelp)
1513 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1514 throw runtime_error(
1516 "Removes the wallet encryption key from memory, locking the wallet.\n"
1517 "After calling this method, you will need to call walletpassphrase again\n"
1518 "before being able to call any methods which require the wallet to be unlocked.");
1521 if (!pwalletMain->IsCrypted())
1522 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called.");
1524 pwalletMain->Lock();
1525 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1527 nWalletUnlockTime = 0;
1534 Value encryptwallet(const Array& params, bool fHelp)
1536 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1537 throw runtime_error(
1538 "encryptwallet <passphrase>\n"
1539 "Encrypts the wallet with <passphrase>.");
1542 if (pwalletMain->IsCrypted())
1543 throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
1546 // shutting down via RPC while the GUI is running does not work (yet):
1547 throw runtime_error("Not Yet Implemented: use GUI to encrypt wallet, not RPC command");
1550 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1551 // Alternately, find a way to make params[0] mlock()'d to begin with.
1552 SecureString strWalletPass;
1553 strWalletPass.reserve(100);
1554 strWalletPass = params[0].get_str().c_str();
1556 if (strWalletPass.length() < 1)
1557 throw runtime_error(
1558 "encryptwallet <passphrase>\n"
1559 "Encrypts the wallet with <passphrase>.");
1561 if (!pwalletMain->EncryptWallet(strWalletPass))
1562 throw JSONRPCError(-16, "Error: Failed to encrypt the wallet.");
1564 // BDB seems to have a bad habit of writing old data into
1565 // slack space in .dat files; that is bad if the old data is
1566 // unencrypted private keys. So:
1567 CreateThread(Shutdown, NULL);
1568 return "wallet encrypted; bitcoin server stopping, restart to run with encrypted wallet";
1572 Value validateaddress(const Array& params, bool fHelp)
1574 if (fHelp || params.size() != 1)
1575 throw runtime_error(
1576 "validateaddress <bitcoinaddress>\n"
1577 "Return information about <bitcoinaddress>.");
1579 CBitcoinAddress address(params[0].get_str());
1580 bool isValid = address.IsValid();
1583 ret.push_back(Pair("isvalid", isValid));
1586 // Call Hash160ToAddress() so we always return current ADDRESSVERSION
1587 // version of the address:
1588 string currentAddress = address.ToString();
1589 ret.push_back(Pair("address", currentAddress));
1590 ret.push_back(Pair("ismine", (pwalletMain->HaveKey(address) > 0)));
1591 if (pwalletMain->mapAddressBook.count(address))
1592 ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
1598 Value getwork(const Array& params, bool fHelp)
1600 if (fHelp || params.size() > 1)
1601 throw runtime_error(
1603 "If [data] is not specified, returns formatted hash data to work on:\n"
1604 " \"midstate\" : precomputed hash state after hashing the first half of the data (DEPRECATED)\n" // deprecated
1605 " \"data\" : block data\n"
1606 " \"hash1\" : formatted hash buffer for second hash (DEPRECATED)\n" // deprecated
1607 " \"target\" : little endian hash target\n"
1608 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1611 throw JSONRPCError(-9, "Bitcoin is not connected!");
1613 if (IsInitialBlockDownload())
1614 throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
1616 typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
1617 static mapNewBlock_t mapNewBlock;
1618 static vector<CBlock*> vNewBlock;
1619 static CReserveKey reservekey(pwalletMain);
1621 if (params.size() == 0)
1624 static unsigned int nTransactionsUpdatedLast;
1625 static CBlockIndex* pindexPrev;
1626 static int64 nStart;
1627 static CBlock* pblock;
1628 if (pindexPrev != pindexBest ||
1629 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
1631 if (pindexPrev != pindexBest)
1633 // Deallocate old blocks since they're obsolete now
1634 mapNewBlock.clear();
1635 BOOST_FOREACH(CBlock* pblock, vNewBlock)
1639 nTransactionsUpdatedLast = nTransactionsUpdated;
1640 pindexPrev = pindexBest;
1644 pblock = CreateNewBlock(reservekey);
1646 throw JSONRPCError(-7, "Out of memory");
1647 vNewBlock.push_back(pblock);
1651 pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
1654 // Update nExtraNonce
1655 static unsigned int nExtraNonce = 0;
1656 IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
1659 mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
1661 // Prebuild hash buffers
1665 FormatHashBuffers(pblock, pmidstate, pdata, phash1);
1667 uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
1670 result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate)))); // deprecated
1671 result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata))));
1672 result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1)))); // deprecated
1673 result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
1679 vector<unsigned char> vchData = ParseHex(params[0].get_str());
1680 if (vchData.size() != 128)
1681 throw JSONRPCError(-8, "Invalid parameter");
1682 CBlock* pdata = (CBlock*)&vchData[0];
1685 for (int i = 0; i < 128/4; i++)
1686 ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]);
1689 if (!mapNewBlock.count(pdata->hashMerkleRoot))
1691 CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
1693 pblock->nTime = pdata->nTime;
1694 pblock->nNonce = pdata->nNonce;
1695 pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
1696 pblock->hashMerkleRoot = pblock->BuildMerkleTree();
1698 return CheckWork(pblock, *pwalletMain, reservekey);
1703 Value getmemorypool(const Array& params, bool fHelp)
1705 if (fHelp || params.size() > 1)
1706 throw runtime_error(
1707 "getmemorypool [data]\n"
1708 "If [data] is not specified, returns data needed to construct a block to work on:\n"
1709 " \"version\" : block version\n"
1710 " \"previousblockhash\" : hash of current highest block\n"
1711 " \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
1712 " \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
1713 " \"time\" : timestamp appropriate for next block\n"
1714 " \"bits\" : compressed target of next block\n"
1715 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1717 if (params.size() == 0)
1720 throw JSONRPCError(-9, "Bitcoin is not connected!");
1722 if (IsInitialBlockDownload())
1723 throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
1725 static CReserveKey reservekey(pwalletMain);
1728 static unsigned int nTransactionsUpdatedLast;
1729 static CBlockIndex* pindexPrev;
1730 static int64 nStart;
1731 static CBlock* pblock;
1732 if (pindexPrev != pindexBest ||
1733 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5))
1735 nTransactionsUpdatedLast = nTransactionsUpdated;
1736 pindexPrev = pindexBest;
1742 pblock = CreateNewBlock(reservekey);
1744 throw JSONRPCError(-7, "Out of memory");
1748 pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
1752 BOOST_FOREACH(CTransaction tx, pblock->vtx) {
1759 transactions.push_back(HexStr(ssTx.begin(), ssTx.end()));
1763 result.push_back(Pair("version", pblock->nVersion));
1764 result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
1765 result.push_back(Pair("transactions", transactions));
1766 result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
1767 result.push_back(Pair("time", (int64_t)pblock->nTime));
1773 uBits.nBits = htonl((int32_t)pblock->nBits);
1774 result.push_back(Pair("bits", HexStr(BEGIN(uBits.cBits), END(uBits.cBits))));
1781 CDataStream ssBlock(ParseHex(params[0].get_str()));
1785 return ProcessBlock(NULL, &pblock);
1803 pair<string, rpcfn_type> pCallTable[] =
1805 make_pair("help", &help),
1806 make_pair("stop", &stop),
1807 make_pair("getblockcount", &getblockcount),
1808 make_pair("getblocknumber", &getblocknumber),
1809 make_pair("getconnectioncount", &getconnectioncount),
1810 make_pair("getdifficulty", &getdifficulty),
1811 make_pair("getgenerate", &getgenerate),
1812 make_pair("setgenerate", &setgenerate),
1813 make_pair("gethashespersec", &gethashespersec),
1814 make_pair("getinfo", &getinfo),
1815 make_pair("getnewaddress", &getnewaddress),
1816 make_pair("getaccountaddress", &getaccountaddress),
1817 make_pair("setaccount", &setaccount),
1818 make_pair("getaccount", &getaccount),
1819 make_pair("getaddressesbyaccount", &getaddressesbyaccount),
1820 make_pair("sendtoaddress", &sendtoaddress),
1821 make_pair("getreceivedbyaddress", &getreceivedbyaddress),
1822 make_pair("getreceivedbyaccount", &getreceivedbyaccount),
1823 make_pair("listreceivedbyaddress", &listreceivedbyaddress),
1824 make_pair("listreceivedbyaccount", &listreceivedbyaccount),
1825 make_pair("backupwallet", &backupwallet),
1826 make_pair("keypoolrefill", &keypoolrefill),
1827 make_pair("walletpassphrase", &walletpassphrase),
1828 make_pair("walletpassphrasechange", &walletpassphrasechange),
1829 make_pair("walletlock", &walletlock),
1830 make_pair("encryptwallet", &encryptwallet),
1831 make_pair("validateaddress", &validateaddress),
1832 make_pair("getbalance", &getbalance),
1833 make_pair("move", &movecmd),
1834 make_pair("sendfrom", &sendfrom),
1835 make_pair("sendmany", &sendmany),
1836 make_pair("gettransaction", &gettransaction),
1837 make_pair("listtransactions", &listtransactions),
1838 make_pair("signmessage", &signmessage),
1839 make_pair("verifymessage", &verifymessage),
1840 make_pair("getwork", &getwork),
1841 make_pair("listaccounts", &listaccounts),
1842 make_pair("settxfee", &settxfee),
1843 make_pair("getmemorypool", &getmemorypool),
1844 make_pair("listsinceblock", &listsinceblock),
1846 map<string, rpcfn_type> mapCallTable(pCallTable, pCallTable + sizeof(pCallTable)/sizeof(pCallTable[0]));
1848 string pAllowInSafeMode[] =
1854 "getconnectioncount",
1861 "getaccountaddress",
1863 "getaddressesbyaccount",
1872 set<string> setAllowInSafeMode(pAllowInSafeMode, pAllowInSafeMode + sizeof(pAllowInSafeMode)/sizeof(pAllowInSafeMode[0]));
1880 // This ain't Apache. We're just using HTTP header for the length field
1881 // and to be compatible with other JSON-RPC implementations.
1884 string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
1887 s << "POST / HTTP/1.1\r\n"
1888 << "User-Agent: bitcoin-json-rpc/" << FormatFullVersion() << "\r\n"
1889 << "Host: 127.0.0.1\r\n"
1890 << "Content-Type: application/json\r\n"
1891 << "Content-Length: " << strMsg.size() << "\r\n"
1892 << "Connection: close\r\n"
1893 << "Accept: application/json\r\n";
1894 BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
1895 s << item.first << ": " << item.second << "\r\n";
1896 s << "\r\n" << strMsg;
1901 string rfc1123Time()
1906 struct tm* now_gmt = gmtime(&now);
1907 string locale(setlocale(LC_TIME, NULL));
1908 setlocale(LC_TIME, "C"); // we want posix (aka "C") weekday/month strings
1909 strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt);
1910 setlocale(LC_TIME, locale.c_str());
1911 return string(buffer);
1914 static string HTTPReply(int nStatus, const string& strMsg)
1917 return strprintf("HTTP/1.0 401 Authorization Required\r\n"
1919 "Server: bitcoin-json-rpc/%s\r\n"
1920 "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
1921 "Content-Type: text/html\r\n"
1922 "Content-Length: 296\r\n"
1924 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
1925 "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
1928 "<TITLE>Error</TITLE>\r\n"
1929 "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
1931 "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
1932 "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
1933 const char *cStatus;
1934 if (nStatus == 200) cStatus = "OK";
1935 else if (nStatus == 400) cStatus = "Bad Request";
1936 else if (nStatus == 403) cStatus = "Forbidden";
1937 else if (nStatus == 404) cStatus = "Not Found";
1938 else if (nStatus == 500) cStatus = "Internal Server Error";
1941 "HTTP/1.1 %d %s\r\n"
1943 "Connection: close\r\n"
1944 "Content-Length: %d\r\n"
1945 "Content-Type: application/json\r\n"
1946 "Server: bitcoin-json-rpc/%s\r\n"
1951 rfc1123Time().c_str(),
1953 FormatFullVersion().c_str(),
1957 int ReadHTTPStatus(std::basic_istream<char>& stream)
1960 getline(stream, str);
1961 vector<string> vWords;
1962 boost::split(vWords, str, boost::is_any_of(" "));
1963 if (vWords.size() < 2)
1965 return atoi(vWords[1].c_str());
1968 int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
1974 std::getline(stream, str);
1975 if (str.empty() || str == "\r")
1977 string::size_type nColon = str.find(":");
1978 if (nColon != string::npos)
1980 string strHeader = str.substr(0, nColon);
1981 boost::trim(strHeader);
1982 boost::to_lower(strHeader);
1983 string strValue = str.substr(nColon+1);
1984 boost::trim(strValue);
1985 mapHeadersRet[strHeader] = strValue;
1986 if (strHeader == "content-length")
1987 nLen = atoi(strValue.c_str());
1993 int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
1995 mapHeadersRet.clear();
1999 int nStatus = ReadHTTPStatus(stream);
2002 int nLen = ReadHTTPHeader(stream, mapHeadersRet);
2003 if (nLen < 0 || nLen > MAX_SIZE)
2009 vector<char> vch(nLen);
2010 stream.read(&vch[0], nLen);
2011 strMessageRet = string(vch.begin(), vch.end());
2017 bool HTTPAuthorized(map<string, string>& mapHeaders)
2019 string strAuth = mapHeaders["authorization"];
2020 if (strAuth.substr(0,6) != "Basic ")
2022 string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
2023 string strUserPass = DecodeBase64(strUserPass64);
2024 string::size_type nColon = strUserPass.find(":");
2025 if (nColon == string::npos)
2027 string strUser = strUserPass.substr(0, nColon);
2028 string strPassword = strUserPass.substr(nColon+1);
2029 return (strUser == mapArgs["-rpcuser"] && strPassword == mapArgs["-rpcpassword"]);
2033 // JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
2034 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
2035 // unspecified (HTTP errors and contents of 'error').
2037 // 1.0 spec: http://json-rpc.org/wiki/specification
2038 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
2039 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
2042 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
2045 request.push_back(Pair("method", strMethod));
2046 request.push_back(Pair("params", params));
2047 request.push_back(Pair("id", id));
2048 return write_string(Value(request), false) + "\n";
2051 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
2054 if (error.type() != null_type)
2055 reply.push_back(Pair("result", Value::null));
2057 reply.push_back(Pair("result", result));
2058 reply.push_back(Pair("error", error));
2059 reply.push_back(Pair("id", id));
2060 return write_string(Value(reply), false) + "\n";
2063 void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
2065 // Send error reply from json-rpc error object
2067 int code = find_value(objError, "code").get_int();
2068 if (code == -32600) nStatus = 400;
2069 else if (code == -32601) nStatus = 404;
2070 string strReply = JSONRPCReply(Value::null, objError, id);
2071 stream << HTTPReply(nStatus, strReply) << std::flush;
2074 bool ClientAllowed(const string& strAddress)
2076 if (strAddress == asio::ip::address_v4::loopback().to_string())
2078 const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
2079 BOOST_FOREACH(string strAllow, vAllow)
2080 if (WildcardMatch(strAddress, strAllow))
2087 // IOStream device that speaks SSL but can also speak non-SSL
2089 class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
2091 SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
2093 fUseSSL = fUseSSLIn;
2094 fNeedHandshake = fUseSSLIn;
2097 void handshake(ssl::stream_base::handshake_type role)
2099 if (!fNeedHandshake) return;
2100 fNeedHandshake = false;
2101 stream.handshake(role);
2103 std::streamsize read(char* s, std::streamsize n)
2105 handshake(ssl::stream_base::server); // HTTPS servers read first
2106 if (fUseSSL) return stream.read_some(asio::buffer(s, n));
2107 return stream.next_layer().read_some(asio::buffer(s, n));
2109 std::streamsize write(const char* s, std::streamsize n)
2111 handshake(ssl::stream_base::client); // HTTPS clients write first
2112 if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
2113 return asio::write(stream.next_layer(), asio::buffer(s, n));
2115 bool connect(const std::string& server, const std::string& port)
2117 ip::tcp::resolver resolver(stream.get_io_service());
2118 ip::tcp::resolver::query query(server.c_str(), port.c_str());
2119 ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
2120 ip::tcp::resolver::iterator end;
2121 boost::system::error_code error = asio::error::host_not_found;
2122 while (error && endpoint_iterator != end)
2124 stream.lowest_layer().close();
2125 stream.lowest_layer().connect(*endpoint_iterator++, error);
2133 bool fNeedHandshake;
2139 void ThreadRPCServer(void* parg)
2141 IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
2144 vnThreadsRunning[4]++;
2145 ThreadRPCServer2(parg);
2146 vnThreadsRunning[4]--;
2148 catch (std::exception& e) {
2149 vnThreadsRunning[4]--;
2150 PrintException(&e, "ThreadRPCServer()");
2152 vnThreadsRunning[4]--;
2153 PrintException(NULL, "ThreadRPCServer()");
2155 printf("ThreadRPCServer exiting\n");
2158 void ThreadRPCServer2(void* parg)
2160 printf("ThreadRPCServer started\n");
2162 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2164 string strWhatAmI = "To use bitcoind";
2165 if (mapArgs.count("-server"))
2166 strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
2167 else if (mapArgs.count("-daemon"))
2168 strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
2170 _("Error: %s, you must set rpcpassword=<password>\nin the configuration file: %s\n"
2171 "If the file does not exist, create it with owner-readable-only file permissions.\n"),
2173 GetConfigFile().c_str());
2175 CreateThread(Shutdown, NULL);
2180 bool fUseSSL = GetBoolArg("-rpcssl");
2181 asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
2183 asio::io_service io_service;
2184 ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", 8332));
2185 ip::tcp::acceptor acceptor(io_service, endpoint);
2187 acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
2190 ssl::context context(io_service, ssl::context::sslv23);
2193 context.set_options(ssl::context::no_sslv2);
2194 filesystem::path certfile = GetArg("-rpcsslcertificatechainfile", "server.cert");
2195 if (!certfile.is_complete()) certfile = filesystem::path(GetDataDir()) / certfile;
2196 if (filesystem::exists(certfile)) context.use_certificate_chain_file(certfile.string().c_str());
2197 else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", certfile.string().c_str());
2198 filesystem::path pkfile = GetArg("-rpcsslprivatekeyfile", "server.pem");
2199 if (!pkfile.is_complete()) pkfile = filesystem::path(GetDataDir()) / pkfile;
2200 if (filesystem::exists(pkfile)) context.use_private_key_file(pkfile.string().c_str(), ssl::context::pem);
2201 else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pkfile.string().c_str());
2203 string ciphers = GetArg("-rpcsslciphers",
2204 "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
2205 SSL_CTX_set_cipher_list(context.impl(), ciphers.c_str());
2209 throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
2214 // Accept connection
2216 SSLStream sslStream(io_service, context);
2217 SSLIOStreamDevice d(sslStream, fUseSSL);
2218 iostreams::stream<SSLIOStreamDevice> stream(d);
2220 ip::tcp::iostream stream;
2223 ip::tcp::endpoint peer;
2224 vnThreadsRunning[4]--;
2226 acceptor.accept(sslStream.lowest_layer(), peer);
2228 acceptor.accept(*stream.rdbuf(), peer);
2230 vnThreadsRunning[4]++;
2234 // Restrict callers by IP
2235 if (!ClientAllowed(peer.address().to_string()))
2237 // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
2239 stream << HTTPReply(403, "") << std::flush;
2243 map<string, string> mapHeaders;
2246 boost::thread api_caller(ReadHTTP, boost::ref(stream), boost::ref(mapHeaders), boost::ref(strRequest));
2247 if (!api_caller.timed_join(boost::posix_time::seconds(GetArg("-rpctimeout", 30))))
2250 printf("ThreadRPCServer ReadHTTP timeout\n");
2254 // Check authorization
2255 if (mapHeaders.count("authorization") == 0)
2257 stream << HTTPReply(401, "") << std::flush;
2260 if (!HTTPAuthorized(mapHeaders))
2262 // Deter brute-forcing short passwords
2263 if (mapArgs["-rpcpassword"].size() < 15)
2266 stream << HTTPReply(401, "") << std::flush;
2267 printf("ThreadRPCServer incorrect password attempt\n");
2271 Value id = Value::null;
2276 if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
2277 throw JSONRPCError(-32700, "Parse error");
2278 const Object& request = valRequest.get_obj();
2280 // Parse id now so errors from here on will have the id
2281 id = find_value(request, "id");
2284 Value valMethod = find_value(request, "method");
2285 if (valMethod.type() == null_type)
2286 throw JSONRPCError(-32600, "Missing method");
2287 if (valMethod.type() != str_type)
2288 throw JSONRPCError(-32600, "Method must be a string");
2289 string strMethod = valMethod.get_str();
2290 if (strMethod != "getwork" && strMethod != "getmemorypool")
2291 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
2294 Value valParams = find_value(request, "params");
2296 if (valParams.type() == array_type)
2297 params = valParams.get_array();
2298 else if (valParams.type() == null_type)
2301 throw JSONRPCError(-32600, "Params must be an array");
2304 map<string, rpcfn_type>::iterator mi = mapCallTable.find(strMethod);
2305 if (mi == mapCallTable.end())
2306 throw JSONRPCError(-32601, "Method not found");
2308 // Observe safe mode
2309 string strWarning = GetWarnings("rpc");
2310 if (strWarning != "" && !GetBoolArg("-disablesafemode") && !setAllowInSafeMode.count(strMethod))
2311 throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
2317 CRITICAL_BLOCK(cs_main)
2318 CRITICAL_BLOCK(pwalletMain->cs_wallet)
2319 result = (*(*mi).second)(params, false);
2322 string strReply = JSONRPCReply(result, Value::null, id);
2323 stream << HTTPReply(200, strReply) << std::flush;
2325 catch (std::exception& e)
2327 ErrorReply(stream, JSONRPCError(-1, e.what()), id);
2330 catch (Object& objError)
2332 ErrorReply(stream, objError, id);
2334 catch (std::exception& e)
2336 ErrorReply(stream, JSONRPCError(-32700, e.what()), id);
2344 Object CallRPC(const string& strMethod, const Array& params)
2346 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2347 throw runtime_error(strprintf(
2348 _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
2349 "If the file does not exist, create it with owner-readable-only file permissions."),
2350 GetConfigFile().c_str()));
2352 // Connect to localhost
2353 bool fUseSSL = GetBoolArg("-rpcssl");
2355 asio::io_service io_service;
2356 ssl::context context(io_service, ssl::context::sslv23);
2357 context.set_options(ssl::context::no_sslv2);
2358 SSLStream sslStream(io_service, context);
2359 SSLIOStreamDevice d(sslStream, fUseSSL);
2360 iostreams::stream<SSLIOStreamDevice> stream(d);
2361 if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332")))
2362 throw runtime_error("couldn't connect to server");
2365 throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
2367 ip::tcp::iostream stream(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332"));
2369 throw runtime_error("couldn't connect to server");
2373 // HTTP basic authentication
2374 string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
2375 map<string, string> mapRequestHeaders;
2376 mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
2379 string strRequest = JSONRPCRequest(strMethod, params, 1);
2380 string strPost = HTTPPost(strRequest, mapRequestHeaders);
2381 stream << strPost << std::flush;
2384 map<string, string> mapHeaders;
2386 int nStatus = ReadHTTP(stream, mapHeaders, strReply);
2388 throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
2389 else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
2390 throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
2391 else if (strReply.empty())
2392 throw runtime_error("no response from server");
2396 if (!read_string(strReply, valReply))
2397 throw runtime_error("couldn't parse reply from server");
2398 const Object& reply = valReply.get_obj();
2400 throw runtime_error("expected reply to have result, error and id properties");
2408 template<typename T>
2409 void ConvertTo(Value& value)
2411 if (value.type() == str_type)
2413 // reinterpret string as unquoted json value
2415 if (!read_string(value.get_str(), value2))
2416 throw runtime_error("type mismatch");
2417 value = value2.get_value<T>();
2421 value = value.get_value<T>();
2425 int CommandLineRPC(int argc, char *argv[])
2432 while (argc > 1 && IsSwitchChar(argv[1][0]))
2440 throw runtime_error("too few parameters");
2441 string strMethod = argv[1];
2443 // Parameters default to strings
2445 for (int i = 2; i < argc; i++)
2446 params.push_back(argv[i]);
2447 int n = params.size();
2450 // Special case non-string parameter types
2452 if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
2453 if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2454 if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
2455 if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]);
2456 if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2457 if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2458 if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2459 if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
2460 if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2461 if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
2462 if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2463 if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]);
2464 if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2465 if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]);
2466 if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2467 if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2468 if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2469 if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2470 if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2471 if (strMethod == "listsinceblock" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2472 if (strMethod == "sendmany" && n > 1)
2474 string s = params[1].get_str();
2476 if (!read_string(s, v) || v.type() != obj_type)
2477 throw runtime_error("type mismatch");
2478 params[1] = v.get_obj();
2480 if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2483 Object reply = CallRPC(strMethod, params);
2486 const Value& result = find_value(reply, "result");
2487 const Value& error = find_value(reply, "error");
2489 if (error.type() != null_type)
2492 strPrint = "error: " + write_string(error, false);
2493 int code = find_value(error.get_obj(), "code").get_int();
2499 if (result.type() == null_type)
2501 else if (result.type() == str_type)
2502 strPrint = result.get_str();
2504 strPrint = write_string(result, true);
2507 catch (std::exception& e)
2509 strPrint = string("error: ") + e.what();
2514 PrintException(NULL, "CommandLineRPC()");
2519 fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
2528 int main(int argc, char *argv[])
2531 // Turn off microsoft heap dump noise
2532 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
2533 _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
2535 setbuf(stdin, NULL);
2536 setbuf(stdout, NULL);
2537 setbuf(stderr, NULL);
2541 if (argc >= 2 && string(argv[1]) == "-server")
2543 printf("server ready\n");
2544 ThreadRPCServer(NULL);
2548 return CommandLineRPC(argc, argv);
2551 catch (std::exception& e) {
2552 PrintException(&e, "main()");
2554 PrintException(NULL, "main()");