1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2012 The Bitcoin developers
3 // Distributed under the MIT/X11 software license, see the accompanying
4 // file license.txt or http://www.opensource.org/licenses/mit-license.php.
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 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1410 if (nWalletUnlockTime == 0)
1412 nWalletUnlockTime = nMyWakeTime;
1414 while (GetTime() < nWalletUnlockTime)
1416 int64 nToSleep = GetTime() - nWalletUnlockTime;
1418 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1420 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1423 nWalletUnlockTime = 0;
1424 pwalletMain->Lock();
1428 if (nWalletUnlockTime < nMyWakeTime)
1429 nWalletUnlockTime = nMyWakeTime;
1432 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1437 Value walletpassphrase(const Array& params, bool fHelp)
1439 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1440 throw runtime_error(
1441 "walletpassphrase <passphrase> <timeout>\n"
1442 "Stores the wallet decryption key in memory for <timeout> seconds.");
1445 if (!pwalletMain->IsCrypted())
1446 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1448 if (!pwalletMain->IsLocked())
1449 throw JSONRPCError(-17, "Error: Wallet is already unlocked.");
1451 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1452 SecureString strWalletPass;
1453 strWalletPass.reserve(100);
1454 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1455 // Alternately, find a way to make params[0] mlock()'d to begin with.
1456 strWalletPass = params[0].get_str().c_str();
1458 if (strWalletPass.length() > 0)
1460 if (!pwalletMain->Unlock(strWalletPass))
1461 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1464 throw runtime_error(
1465 "walletpassphrase <passphrase> <timeout>\n"
1466 "Stores the wallet decryption key in memory for <timeout> seconds.");
1468 CreateThread(ThreadTopUpKeyPool, NULL);
1469 int* pnSleepTime = new int(params[1].get_int());
1470 CreateThread(ThreadCleanWalletPassphrase, pnSleepTime);
1476 Value walletpassphrasechange(const Array& params, bool fHelp)
1478 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1479 throw runtime_error(
1480 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1481 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1484 if (!pwalletMain->IsCrypted())
1485 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1487 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1488 // Alternately, find a way to make params[0] mlock()'d to begin with.
1489 SecureString strOldWalletPass;
1490 strOldWalletPass.reserve(100);
1491 strOldWalletPass = params[0].get_str().c_str();
1493 SecureString strNewWalletPass;
1494 strNewWalletPass.reserve(100);
1495 strNewWalletPass = params[1].get_str().c_str();
1497 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1498 throw runtime_error(
1499 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1500 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1502 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1503 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1509 Value walletlock(const Array& params, bool fHelp)
1511 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1512 throw runtime_error(
1514 "Removes the wallet encryption key from memory, locking the wallet.\n"
1515 "After calling this method, you will need to call walletpassphrase again\n"
1516 "before being able to call any methods which require the wallet to be unlocked.");
1519 if (!pwalletMain->IsCrypted())
1520 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called.");
1522 pwalletMain->Lock();
1523 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1525 nWalletUnlockTime = 0;
1532 Value encryptwallet(const Array& params, bool fHelp)
1534 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1535 throw runtime_error(
1536 "encryptwallet <passphrase>\n"
1537 "Encrypts the wallet with <passphrase>.");
1540 if (pwalletMain->IsCrypted())
1541 throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
1544 // shutting down via RPC while the GUI is running does not work (yet):
1545 throw runtime_error("Not Yet Implemented: use GUI to encrypt wallet, not RPC command");
1548 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1549 // Alternately, find a way to make params[0] mlock()'d to begin with.
1550 SecureString strWalletPass;
1551 strWalletPass.reserve(100);
1552 strWalletPass = params[0].get_str().c_str();
1554 if (strWalletPass.length() < 1)
1555 throw runtime_error(
1556 "encryptwallet <passphrase>\n"
1557 "Encrypts the wallet with <passphrase>.");
1559 if (!pwalletMain->EncryptWallet(strWalletPass))
1560 throw JSONRPCError(-16, "Error: Failed to encrypt the wallet.");
1562 // BDB seems to have a bad habit of writing old data into
1563 // slack space in .dat files; that is bad if the old data is
1564 // unencrypted private keys. So:
1565 CreateThread(Shutdown, NULL);
1566 return "wallet encrypted; bitcoin server stopping, restart to run with encrypted wallet";
1570 Value validateaddress(const Array& params, bool fHelp)
1572 if (fHelp || params.size() != 1)
1573 throw runtime_error(
1574 "validateaddress <bitcoinaddress>\n"
1575 "Return information about <bitcoinaddress>.");
1577 CBitcoinAddress address(params[0].get_str());
1578 bool isValid = address.IsValid();
1581 ret.push_back(Pair("isvalid", isValid));
1584 // Call Hash160ToAddress() so we always return current ADDRESSVERSION
1585 // version of the address:
1586 string currentAddress = address.ToString();
1587 ret.push_back(Pair("address", currentAddress));
1588 ret.push_back(Pair("ismine", (pwalletMain->HaveKey(address) > 0)));
1589 if (pwalletMain->mapAddressBook.count(address))
1590 ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
1596 Value getwork(const Array& params, bool fHelp)
1598 if (fHelp || params.size() > 1)
1599 throw runtime_error(
1601 "If [data] is not specified, returns formatted hash data to work on:\n"
1602 " \"midstate\" : precomputed hash state after hashing the first half of the data (DEPRECATED)\n" // deprecated
1603 " \"data\" : block data\n"
1604 " \"hash1\" : formatted hash buffer for second hash (DEPRECATED)\n" // deprecated
1605 " \"target\" : little endian hash target\n"
1606 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1609 throw JSONRPCError(-9, "Bitcoin is not connected!");
1611 if (IsInitialBlockDownload())
1612 throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
1614 typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
1615 static mapNewBlock_t mapNewBlock;
1616 static vector<CBlock*> vNewBlock;
1617 static CReserveKey reservekey(pwalletMain);
1619 if (params.size() == 0)
1622 static unsigned int nTransactionsUpdatedLast;
1623 static CBlockIndex* pindexPrev;
1624 static int64 nStart;
1625 static CBlock* pblock;
1626 if (pindexPrev != pindexBest ||
1627 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
1629 if (pindexPrev != pindexBest)
1631 // Deallocate old blocks since they're obsolete now
1632 mapNewBlock.clear();
1633 BOOST_FOREACH(CBlock* pblock, vNewBlock)
1637 nTransactionsUpdatedLast = nTransactionsUpdated;
1638 pindexPrev = pindexBest;
1642 pblock = CreateNewBlock(reservekey);
1644 throw JSONRPCError(-7, "Out of memory");
1645 vNewBlock.push_back(pblock);
1649 pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
1652 // Update nExtraNonce
1653 static unsigned int nExtraNonce = 0;
1654 IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
1657 mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
1659 // Prebuild hash buffers
1663 FormatHashBuffers(pblock, pmidstate, pdata, phash1);
1665 uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
1668 result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate)))); // deprecated
1669 result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata))));
1670 result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1)))); // deprecated
1671 result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
1677 vector<unsigned char> vchData = ParseHex(params[0].get_str());
1678 if (vchData.size() != 128)
1679 throw JSONRPCError(-8, "Invalid parameter");
1680 CBlock* pdata = (CBlock*)&vchData[0];
1683 for (int i = 0; i < 128/4; i++)
1684 ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]);
1687 if (!mapNewBlock.count(pdata->hashMerkleRoot))
1689 CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
1691 pblock->nTime = pdata->nTime;
1692 pblock->nNonce = pdata->nNonce;
1693 pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
1694 pblock->hashMerkleRoot = pblock->BuildMerkleTree();
1696 return CheckWork(pblock, *pwalletMain, reservekey);
1701 Value getmemorypool(const Array& params, bool fHelp)
1703 if (fHelp || params.size() > 1)
1704 throw runtime_error(
1705 "getmemorypool [data]\n"
1706 "If [data] is not specified, returns data needed to construct a block to work on:\n"
1707 " \"version\" : block version\n"
1708 " \"previousblockhash\" : hash of current highest block\n"
1709 " \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
1710 " \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
1711 " \"time\" : timestamp appropriate for next block\n"
1712 " \"bits\" : compressed target of next block\n"
1713 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1715 if (params.size() == 0)
1718 throw JSONRPCError(-9, "Bitcoin is not connected!");
1720 if (IsInitialBlockDownload())
1721 throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
1723 static CReserveKey reservekey(pwalletMain);
1726 static unsigned int nTransactionsUpdatedLast;
1727 static CBlockIndex* pindexPrev;
1728 static int64 nStart;
1729 static CBlock* pblock;
1730 if (pindexPrev != pindexBest ||
1731 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5))
1733 nTransactionsUpdatedLast = nTransactionsUpdated;
1734 pindexPrev = pindexBest;
1740 pblock = CreateNewBlock(reservekey);
1742 throw JSONRPCError(-7, "Out of memory");
1746 pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
1750 BOOST_FOREACH(CTransaction tx, pblock->vtx) {
1757 transactions.push_back(HexStr(ssTx.begin(), ssTx.end()));
1761 result.push_back(Pair("version", pblock->nVersion));
1762 result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
1763 result.push_back(Pair("transactions", transactions));
1764 result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
1765 result.push_back(Pair("time", (int64_t)pblock->nTime));
1771 uBits.nBits = htonl((int32_t)pblock->nBits);
1772 result.push_back(Pair("bits", HexStr(BEGIN(uBits.cBits), END(uBits.cBits))));
1779 CDataStream ssBlock(ParseHex(params[0].get_str()));
1783 return ProcessBlock(NULL, &pblock);
1801 pair<string, rpcfn_type> pCallTable[] =
1803 make_pair("help", &help),
1804 make_pair("stop", &stop),
1805 make_pair("getblockcount", &getblockcount),
1806 make_pair("getblocknumber", &getblocknumber),
1807 make_pair("getconnectioncount", &getconnectioncount),
1808 make_pair("getdifficulty", &getdifficulty),
1809 make_pair("getgenerate", &getgenerate),
1810 make_pair("setgenerate", &setgenerate),
1811 make_pair("gethashespersec", &gethashespersec),
1812 make_pair("getinfo", &getinfo),
1813 make_pair("getnewaddress", &getnewaddress),
1814 make_pair("getaccountaddress", &getaccountaddress),
1815 make_pair("setaccount", &setaccount),
1816 make_pair("getaccount", &getaccount),
1817 make_pair("getaddressesbyaccount", &getaddressesbyaccount),
1818 make_pair("sendtoaddress", &sendtoaddress),
1819 make_pair("getreceivedbyaddress", &getreceivedbyaddress),
1820 make_pair("getreceivedbyaccount", &getreceivedbyaccount),
1821 make_pair("listreceivedbyaddress", &listreceivedbyaddress),
1822 make_pair("listreceivedbyaccount", &listreceivedbyaccount),
1823 make_pair("backupwallet", &backupwallet),
1824 make_pair("keypoolrefill", &keypoolrefill),
1825 make_pair("walletpassphrase", &walletpassphrase),
1826 make_pair("walletpassphrasechange", &walletpassphrasechange),
1827 make_pair("walletlock", &walletlock),
1828 make_pair("encryptwallet", &encryptwallet),
1829 make_pair("validateaddress", &validateaddress),
1830 make_pair("getbalance", &getbalance),
1831 make_pair("move", &movecmd),
1832 make_pair("sendfrom", &sendfrom),
1833 make_pair("sendmany", &sendmany),
1834 make_pair("gettransaction", &gettransaction),
1835 make_pair("listtransactions", &listtransactions),
1836 make_pair("signmessage", &signmessage),
1837 make_pair("verifymessage", &verifymessage),
1838 make_pair("getwork", &getwork),
1839 make_pair("listaccounts", &listaccounts),
1840 make_pair("settxfee", &settxfee),
1841 make_pair("getmemorypool", &getmemorypool),
1842 make_pair("listsinceblock", &listsinceblock),
1844 map<string, rpcfn_type> mapCallTable(pCallTable, pCallTable + sizeof(pCallTable)/sizeof(pCallTable[0]));
1846 string pAllowInSafeMode[] =
1852 "getconnectioncount",
1859 "getaccountaddress",
1861 "getaddressesbyaccount",
1870 set<string> setAllowInSafeMode(pAllowInSafeMode, pAllowInSafeMode + sizeof(pAllowInSafeMode)/sizeof(pAllowInSafeMode[0]));
1878 // This ain't Apache. We're just using HTTP header for the length field
1879 // and to be compatible with other JSON-RPC implementations.
1882 string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
1885 s << "POST / HTTP/1.1\r\n"
1886 << "User-Agent: bitcoin-json-rpc/" << FormatFullVersion() << "\r\n"
1887 << "Host: 127.0.0.1\r\n"
1888 << "Content-Type: application/json\r\n"
1889 << "Content-Length: " << strMsg.size() << "\r\n"
1890 << "Connection: close\r\n"
1891 << "Accept: application/json\r\n";
1892 BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
1893 s << item.first << ": " << item.second << "\r\n";
1894 s << "\r\n" << strMsg;
1899 string rfc1123Time()
1904 struct tm* now_gmt = gmtime(&now);
1905 string locale(setlocale(LC_TIME, NULL));
1906 setlocale(LC_TIME, "C"); // we want posix (aka "C") weekday/month strings
1907 strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt);
1908 setlocale(LC_TIME, locale.c_str());
1909 return string(buffer);
1912 static string HTTPReply(int nStatus, const string& strMsg)
1915 return strprintf("HTTP/1.0 401 Authorization Required\r\n"
1917 "Server: bitcoin-json-rpc/%s\r\n"
1918 "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
1919 "Content-Type: text/html\r\n"
1920 "Content-Length: 296\r\n"
1922 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
1923 "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
1926 "<TITLE>Error</TITLE>\r\n"
1927 "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
1929 "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
1930 "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
1931 const char *cStatus;
1932 if (nStatus == 200) cStatus = "OK";
1933 else if (nStatus == 400) cStatus = "Bad Request";
1934 else if (nStatus == 403) cStatus = "Forbidden";
1935 else if (nStatus == 404) cStatus = "Not Found";
1936 else if (nStatus == 500) cStatus = "Internal Server Error";
1939 "HTTP/1.1 %d %s\r\n"
1941 "Connection: close\r\n"
1942 "Content-Length: %d\r\n"
1943 "Content-Type: application/json\r\n"
1944 "Server: bitcoin-json-rpc/%s\r\n"
1949 rfc1123Time().c_str(),
1951 FormatFullVersion().c_str(),
1955 int ReadHTTPStatus(std::basic_istream<char>& stream)
1958 getline(stream, str);
1959 vector<string> vWords;
1960 boost::split(vWords, str, boost::is_any_of(" "));
1961 if (vWords.size() < 2)
1963 return atoi(vWords[1].c_str());
1966 int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
1972 std::getline(stream, str);
1973 if (str.empty() || str == "\r")
1975 string::size_type nColon = str.find(":");
1976 if (nColon != string::npos)
1978 string strHeader = str.substr(0, nColon);
1979 boost::trim(strHeader);
1980 boost::to_lower(strHeader);
1981 string strValue = str.substr(nColon+1);
1982 boost::trim(strValue);
1983 mapHeadersRet[strHeader] = strValue;
1984 if (strHeader == "content-length")
1985 nLen = atoi(strValue.c_str());
1991 int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
1993 mapHeadersRet.clear();
1997 int nStatus = ReadHTTPStatus(stream);
2000 int nLen = ReadHTTPHeader(stream, mapHeadersRet);
2001 if (nLen < 0 || nLen > MAX_SIZE)
2007 vector<char> vch(nLen);
2008 stream.read(&vch[0], nLen);
2009 strMessageRet = string(vch.begin(), vch.end());
2015 bool HTTPAuthorized(map<string, string>& mapHeaders)
2017 string strAuth = mapHeaders["authorization"];
2018 if (strAuth.substr(0,6) != "Basic ")
2020 string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
2021 string strUserPass = DecodeBase64(strUserPass64);
2022 string::size_type nColon = strUserPass.find(":");
2023 if (nColon == string::npos)
2025 string strUser = strUserPass.substr(0, nColon);
2026 string strPassword = strUserPass.substr(nColon+1);
2027 return (strUser == mapArgs["-rpcuser"] && strPassword == mapArgs["-rpcpassword"]);
2031 // JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
2032 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
2033 // unspecified (HTTP errors and contents of 'error').
2035 // 1.0 spec: http://json-rpc.org/wiki/specification
2036 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
2037 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
2040 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
2043 request.push_back(Pair("method", strMethod));
2044 request.push_back(Pair("params", params));
2045 request.push_back(Pair("id", id));
2046 return write_string(Value(request), false) + "\n";
2049 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
2052 if (error.type() != null_type)
2053 reply.push_back(Pair("result", Value::null));
2055 reply.push_back(Pair("result", result));
2056 reply.push_back(Pair("error", error));
2057 reply.push_back(Pair("id", id));
2058 return write_string(Value(reply), false) + "\n";
2061 void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
2063 // Send error reply from json-rpc error object
2065 int code = find_value(objError, "code").get_int();
2066 if (code == -32600) nStatus = 400;
2067 else if (code == -32601) nStatus = 404;
2068 string strReply = JSONRPCReply(Value::null, objError, id);
2069 stream << HTTPReply(nStatus, strReply) << std::flush;
2072 bool ClientAllowed(const string& strAddress)
2074 if (strAddress == asio::ip::address_v4::loopback().to_string())
2076 const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
2077 BOOST_FOREACH(string strAllow, vAllow)
2078 if (WildcardMatch(strAddress, strAllow))
2085 // IOStream device that speaks SSL but can also speak non-SSL
2087 class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
2089 SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
2091 fUseSSL = fUseSSLIn;
2092 fNeedHandshake = fUseSSLIn;
2095 void handshake(ssl::stream_base::handshake_type role)
2097 if (!fNeedHandshake) return;
2098 fNeedHandshake = false;
2099 stream.handshake(role);
2101 std::streamsize read(char* s, std::streamsize n)
2103 handshake(ssl::stream_base::server); // HTTPS servers read first
2104 if (fUseSSL) return stream.read_some(asio::buffer(s, n));
2105 return stream.next_layer().read_some(asio::buffer(s, n));
2107 std::streamsize write(const char* s, std::streamsize n)
2109 handshake(ssl::stream_base::client); // HTTPS clients write first
2110 if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
2111 return asio::write(stream.next_layer(), asio::buffer(s, n));
2113 bool connect(const std::string& server, const std::string& port)
2115 ip::tcp::resolver resolver(stream.get_io_service());
2116 ip::tcp::resolver::query query(server.c_str(), port.c_str());
2117 ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
2118 ip::tcp::resolver::iterator end;
2119 boost::system::error_code error = asio::error::host_not_found;
2120 while (error && endpoint_iterator != end)
2122 stream.lowest_layer().close();
2123 stream.lowest_layer().connect(*endpoint_iterator++, error);
2131 bool fNeedHandshake;
2137 void ThreadRPCServer(void* parg)
2139 IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
2142 vnThreadsRunning[4]++;
2143 ThreadRPCServer2(parg);
2144 vnThreadsRunning[4]--;
2146 catch (std::exception& e) {
2147 vnThreadsRunning[4]--;
2148 PrintException(&e, "ThreadRPCServer()");
2150 vnThreadsRunning[4]--;
2151 PrintException(NULL, "ThreadRPCServer()");
2153 printf("ThreadRPCServer exiting\n");
2156 void ThreadRPCServer2(void* parg)
2158 printf("ThreadRPCServer started\n");
2160 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2162 unsigned char rand_pwd[32];
2163 RAND_bytes(rand_pwd, 32);
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 a rpcpassword in the configuration file:\n %s\n"
2171 "It is recommended you use the following random password:\n"
2172 "rpcuser=bitcoinrpc\n"
2174 "(you do not need to remember this password)\n"
2175 "If the file does not exist, create it with owner-readable-only file permissions.\n"),
2177 GetConfigFile().c_str(),
2178 EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str());
2180 CreateThread(Shutdown, NULL);
2185 bool fUseSSL = GetBoolArg("-rpcssl");
2186 asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
2188 asio::io_service io_service;
2189 ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", 8332));
2190 ip::tcp::acceptor acceptor(io_service, endpoint);
2192 acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
2195 ssl::context context(io_service, ssl::context::sslv23);
2198 context.set_options(ssl::context::no_sslv2);
2199 filesystem::path certfile = GetArg("-rpcsslcertificatechainfile", "server.cert");
2200 if (!certfile.is_complete()) certfile = filesystem::path(GetDataDir()) / certfile;
2201 if (filesystem::exists(certfile)) context.use_certificate_chain_file(certfile.string().c_str());
2202 else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", certfile.string().c_str());
2203 filesystem::path pkfile = GetArg("-rpcsslprivatekeyfile", "server.pem");
2204 if (!pkfile.is_complete()) pkfile = filesystem::path(GetDataDir()) / pkfile;
2205 if (filesystem::exists(pkfile)) context.use_private_key_file(pkfile.string().c_str(), ssl::context::pem);
2206 else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pkfile.string().c_str());
2208 string ciphers = GetArg("-rpcsslciphers",
2209 "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
2210 SSL_CTX_set_cipher_list(context.impl(), ciphers.c_str());
2214 throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
2219 // Accept connection
2221 SSLStream sslStream(io_service, context);
2222 SSLIOStreamDevice d(sslStream, fUseSSL);
2223 iostreams::stream<SSLIOStreamDevice> stream(d);
2225 ip::tcp::iostream stream;
2228 ip::tcp::endpoint peer;
2229 vnThreadsRunning[4]--;
2231 acceptor.accept(sslStream.lowest_layer(), peer);
2233 acceptor.accept(*stream.rdbuf(), peer);
2235 vnThreadsRunning[4]++;
2239 // Restrict callers by IP
2240 if (!ClientAllowed(peer.address().to_string()))
2242 // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
2244 stream << HTTPReply(403, "") << std::flush;
2248 map<string, string> mapHeaders;
2251 boost::thread api_caller(ReadHTTP, boost::ref(stream), boost::ref(mapHeaders), boost::ref(strRequest));
2252 if (!api_caller.timed_join(boost::posix_time::seconds(GetArg("-rpctimeout", 30))))
2255 printf("ThreadRPCServer ReadHTTP timeout\n");
2259 // Check authorization
2260 if (mapHeaders.count("authorization") == 0)
2262 stream << HTTPReply(401, "") << std::flush;
2265 if (!HTTPAuthorized(mapHeaders))
2267 printf("ThreadRPCServer incorrect password attempt from %s\n",peer.address().to_string().c_str());
2268 /* Deter brute-forcing short passwords.
2269 If this results in a DOS the user really
2270 shouldn't have their RPC port exposed.*/
2271 if (mapArgs["-rpcpassword"].size() < 20)
2274 stream << HTTPReply(401, "") << std::flush;
2278 Value id = Value::null;
2283 if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
2284 throw JSONRPCError(-32700, "Parse error");
2285 const Object& request = valRequest.get_obj();
2287 // Parse id now so errors from here on will have the id
2288 id = find_value(request, "id");
2291 Value valMethod = find_value(request, "method");
2292 if (valMethod.type() == null_type)
2293 throw JSONRPCError(-32600, "Missing method");
2294 if (valMethod.type() != str_type)
2295 throw JSONRPCError(-32600, "Method must be a string");
2296 string strMethod = valMethod.get_str();
2297 if (strMethod != "getwork" && strMethod != "getmemorypool")
2298 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
2301 Value valParams = find_value(request, "params");
2303 if (valParams.type() == array_type)
2304 params = valParams.get_array();
2305 else if (valParams.type() == null_type)
2308 throw JSONRPCError(-32600, "Params must be an array");
2311 map<string, rpcfn_type>::iterator mi = mapCallTable.find(strMethod);
2312 if (mi == mapCallTable.end())
2313 throw JSONRPCError(-32601, "Method not found");
2315 // Observe safe mode
2316 string strWarning = GetWarnings("rpc");
2317 if (strWarning != "" && !GetBoolArg("-disablesafemode") && !setAllowInSafeMode.count(strMethod))
2318 throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
2324 CRITICAL_BLOCK(cs_main)
2325 CRITICAL_BLOCK(pwalletMain->cs_wallet)
2326 result = (*(*mi).second)(params, false);
2329 string strReply = JSONRPCReply(result, Value::null, id);
2330 stream << HTTPReply(200, strReply) << std::flush;
2332 catch (std::exception& e)
2334 ErrorReply(stream, JSONRPCError(-1, e.what()), id);
2337 catch (Object& objError)
2339 ErrorReply(stream, objError, id);
2341 catch (std::exception& e)
2343 ErrorReply(stream, JSONRPCError(-32700, e.what()), id);
2351 Object CallRPC(const string& strMethod, const Array& params)
2353 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2354 throw runtime_error(strprintf(
2355 _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
2356 "If the file does not exist, create it with owner-readable-only file permissions."),
2357 GetConfigFile().c_str()));
2359 // Connect to localhost
2360 bool fUseSSL = GetBoolArg("-rpcssl");
2362 asio::io_service io_service;
2363 ssl::context context(io_service, ssl::context::sslv23);
2364 context.set_options(ssl::context::no_sslv2);
2365 SSLStream sslStream(io_service, context);
2366 SSLIOStreamDevice d(sslStream, fUseSSL);
2367 iostreams::stream<SSLIOStreamDevice> stream(d);
2368 if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332")))
2369 throw runtime_error("couldn't connect to server");
2372 throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
2374 ip::tcp::iostream stream(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332"));
2376 throw runtime_error("couldn't connect to server");
2380 // HTTP basic authentication
2381 string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
2382 map<string, string> mapRequestHeaders;
2383 mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
2386 string strRequest = JSONRPCRequest(strMethod, params, 1);
2387 string strPost = HTTPPost(strRequest, mapRequestHeaders);
2388 stream << strPost << std::flush;
2391 map<string, string> mapHeaders;
2393 int nStatus = ReadHTTP(stream, mapHeaders, strReply);
2395 throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
2396 else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
2397 throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
2398 else if (strReply.empty())
2399 throw runtime_error("no response from server");
2403 if (!read_string(strReply, valReply))
2404 throw runtime_error("couldn't parse reply from server");
2405 const Object& reply = valReply.get_obj();
2407 throw runtime_error("expected reply to have result, error and id properties");
2415 template<typename T>
2416 void ConvertTo(Value& value)
2418 if (value.type() == str_type)
2420 // reinterpret string as unquoted json value
2422 if (!read_string(value.get_str(), value2))
2423 throw runtime_error("type mismatch");
2424 value = value2.get_value<T>();
2428 value = value.get_value<T>();
2432 int CommandLineRPC(int argc, char *argv[])
2439 while (argc > 1 && IsSwitchChar(argv[1][0]))
2447 throw runtime_error("too few parameters");
2448 string strMethod = argv[1];
2450 // Parameters default to strings
2452 for (int i = 2; i < argc; i++)
2453 params.push_back(argv[i]);
2454 int n = params.size();
2457 // Special case non-string parameter types
2459 if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
2460 if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2461 if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
2462 if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]);
2463 if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2464 if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2465 if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2466 if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
2467 if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2468 if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
2469 if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2470 if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]);
2471 if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2472 if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]);
2473 if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2474 if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2475 if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2476 if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2477 if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2478 if (strMethod == "listsinceblock" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2479 if (strMethod == "sendmany" && n > 1)
2481 string s = params[1].get_str();
2483 if (!read_string(s, v) || v.type() != obj_type)
2484 throw runtime_error("type mismatch");
2485 params[1] = v.get_obj();
2487 if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2490 Object reply = CallRPC(strMethod, params);
2493 const Value& result = find_value(reply, "result");
2494 const Value& error = find_value(reply, "error");
2496 if (error.type() != null_type)
2499 strPrint = "error: " + write_string(error, false);
2500 int code = find_value(error.get_obj(), "code").get_int();
2506 if (result.type() == null_type)
2508 else if (result.type() == str_type)
2509 strPrint = result.get_str();
2511 strPrint = write_string(result, true);
2514 catch (std::exception& e)
2516 strPrint = string("error: ") + e.what();
2521 PrintException(NULL, "CommandLineRPC()");
2526 fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
2535 int main(int argc, char *argv[])
2538 // Turn off microsoft heap dump noise
2539 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
2540 _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
2542 setbuf(stdin, NULL);
2543 setbuf(stdout, NULL);
2544 setbuf(stderr, NULL);
2548 if (argc >= 2 && string(argv[1]) == "-server")
2550 printf("server ready\n");
2551 ThreadRPCServer(NULL);
2555 return CommandLineRPC(argc, argv);
2558 catch (std::exception& e) {
2559 PrintException(&e, "main()");
2561 PrintException(NULL, "main()");