1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Copyright (c) 2011 The Bitcoin developers
3 // Copyright (c) 2011 The PPCoin developers
4 // Distributed under the MIT/X11 software license, see the accompanying
5 // file license.txt or http://www.opensource.org/licenses/mit-license.php.
12 #include <boost/asio.hpp>
13 #include <boost/iostreams/concepts.hpp>
14 #include <boost/iostreams/stream.hpp>
15 #include <boost/algorithm/string.hpp>
17 #include <boost/asio/ssl.hpp>
18 #include <boost/filesystem.hpp>
19 #include <boost/filesystem/fstream.hpp>
20 typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> SSLStream;
22 #include "json/json_spirit_reader_template.h"
23 #include "json/json_spirit_writer_template.h"
24 #include "json/json_spirit_utils.h"
25 #define printf OutputDebugStringF
26 // MinGW 3.4.5 gets "fatal error: had to relocate PCH" if the json headers are
27 // precompiled in headers.h. The problem might be when the pch file goes over
28 // a certain size around 145MB. If we need access to json_spirit outside this
29 // file, we could use the compiled json_spirit option.
32 using namespace boost;
33 using namespace boost::asio;
34 using namespace json_spirit;
36 void ThreadRPCServer2(void* parg);
37 typedef Value(*rpcfn_type)(const Array& params, bool fHelp);
38 extern map<string, rpcfn_type> mapCallTable;
40 static std::string strRPCUserColonPass;
42 static int64 nWalletUnlockTime;
43 static CCriticalSection cs_nWalletUnlockTime;
46 Object JSONRPCError(int code, const string& message)
49 error.push_back(Pair("code", code));
50 error.push_back(Pair("message", message));
55 void PrintConsole(const std::string &format, ...)
58 int limit = sizeof(buffer);
60 va_start(arg_ptr, format);
61 int ret = _vsnprintf(buffer, limit, format.c_str(), arg_ptr);
63 if (ret < 0 || ret >= limit)
69 fprintf(stdout, "%s", buffer);
73 int64 AmountFromValue(const Value& value)
75 double dAmount = value.get_real();
76 if (dAmount <= 0.0 || dAmount > MAX_MONEY)
77 throw JSONRPCError(-3, "Invalid amount");
78 int64 nAmount = roundint64(dAmount * COIN);
79 if (!MoneyRange(nAmount))
80 throw JSONRPCError(-3, "Invalid amount");
84 Value ValueFromAmount(int64 amount)
86 return (double)amount / (double)COIN;
89 void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
91 entry.push_back(Pair("confirmations", wtx.GetDepthInMainChain()));
92 entry.push_back(Pair("txid", wtx.GetHash().GetHex()));
93 entry.push_back(Pair("time", (boost::int64_t)wtx.GetTxTime()));
94 BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
95 entry.push_back(Pair(item.first, item.second));
98 string AccountFromValue(const Value& value)
100 string strAccount = value.get_str();
101 if (strAccount == "*")
102 throw JSONRPCError(-11, "Invalid account name");
109 /// Note: This interface may still be subject to change.
113 Value help(const Array& params, bool fHelp)
115 if (fHelp || params.size() > 1)
118 "List commands, or get help for a command.");
121 if (params.size() > 0)
122 strCommand = params[0].get_str();
125 set<rpcfn_type> setDone;
126 for (map<string, rpcfn_type>::iterator mi = mapCallTable.begin(); mi != mapCallTable.end(); ++mi)
128 string strMethod = (*mi).first;
129 // We already filter duplicates, but these deprecated screw up the sort order
130 if (strMethod == "getamountreceived" ||
131 strMethod == "getallreceived" ||
132 strMethod == "getblocknumber" || // deprecated
133 (strMethod.find("label") != string::npos))
135 if (strCommand != "" && strMethod != strCommand)
140 rpcfn_type pfn = (*mi).second;
141 if (setDone.insert(pfn).second)
142 (*pfn)(params, true);
144 catch (std::exception& e)
146 // Help text is returned in an exception
147 string strHelp = string(e.what());
148 if (strCommand == "")
149 if (strHelp.find('\n') != -1)
150 strHelp = strHelp.substr(0, strHelp.find('\n'));
151 strRet += strHelp + "\n";
155 strRet = strprintf("help: unknown command: %s\n", strCommand.c_str());
156 strRet = strRet.substr(0,strRet.size()-1);
161 Value stop(const Array& params, bool fHelp)
163 if (fHelp || params.size() != 0)
166 "Stop bitcoin server.");
168 // Shutdown will take long enough that the response should get back
169 CreateThread(Shutdown, NULL);
170 return "bitcoin server stopping";
172 throw runtime_error("NYI: cannot shut down GUI with RPC command");
177 Value getblockcount(const Array& params, bool fHelp)
179 if (fHelp || params.size() != 0)
182 "Returns the number of blocks in the longest block chain.");
189 Value getblocknumber(const Array& params, bool fHelp)
191 if (fHelp || params.size() != 0)
194 "Deprecated. Use getblockcount.");
200 Value getconnectioncount(const Array& params, bool fHelp)
202 if (fHelp || params.size() != 0)
204 "getconnectioncount\n"
205 "Returns the number of connections to other nodes.");
207 return (int)vNodes.size();
211 double GetDifficulty()
213 // Floating point number that is a multiple of the minimum difficulty,
214 // minimum difficulty = 1.0.
216 if (pindexBest == NULL)
218 int nShift = (pindexBest->nBits >> 24) & 0xff;
221 (double)0x0000ffff / (double)(pindexBest->nBits & 0x00ffffff);
237 Value getdifficulty(const Array& params, bool fHelp)
239 if (fHelp || params.size() != 0)
242 "Returns the proof-of-work difficulty as a multiple of the minimum difficulty.");
244 return GetDifficulty();
248 Value getgenerate(const Array& params, bool fHelp)
250 if (fHelp || params.size() != 0)
253 "Returns true or false.");
255 return (bool)fGenerateBitcoins;
259 Value setgenerate(const Array& params, bool fHelp)
261 if (fHelp || params.size() < 1 || params.size() > 2)
263 "setgenerate <generate> [genproclimit]\n"
264 "<generate> is true or false to turn generation on or off.\n"
265 "Generation is limited to [genproclimit] processors, -1 is unlimited.");
267 bool fGenerate = true;
268 if (params.size() > 0)
269 fGenerate = params[0].get_bool();
271 if (params.size() > 1)
273 int nGenProcLimit = params[1].get_int();
274 fLimitProcessors = (nGenProcLimit != -1);
275 WriteSetting("fLimitProcessors", fLimitProcessors);
276 if (nGenProcLimit != -1)
277 WriteSetting("nLimitProcessors", nLimitProcessors = nGenProcLimit);
278 if (nGenProcLimit == 0)
282 GenerateBitcoins(fGenerate, pwalletMain);
287 Value gethashespersec(const Array& params, bool fHelp)
289 if (fHelp || params.size() != 0)
292 "Returns a recent hashes per second performance measurement while generating.");
294 if (GetTimeMillis() - nHPSTimerStart > 8000)
295 return (boost::int64_t)0;
296 return (boost::int64_t)dHashesPerSec;
300 Value getinfo(const Array& params, bool fHelp)
302 if (fHelp || params.size() != 0)
305 "Returns an object containing various state info.");
308 obj.push_back(Pair("version", (int)VERSION));
309 obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
310 obj.push_back(Pair("blocks", (int)nBestHeight));
311 obj.push_back(Pair("connections", (int)vNodes.size()));
312 obj.push_back(Pair("proxy", (fUseProxy ? addrProxy.ToStringIPPort() : string())));
313 obj.push_back(Pair("generate", (bool)fGenerateBitcoins));
314 obj.push_back(Pair("genproclimit", (int)(fLimitProcessors ? nLimitProcessors : -1)));
315 obj.push_back(Pair("difficulty", (double)GetDifficulty()));
316 obj.push_back(Pair("hashespersec", gethashespersec(params, false)));
317 obj.push_back(Pair("testnet", fTestNet));
318 obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));
319 obj.push_back(Pair("keypoolsize", pwalletMain->GetKeyPoolSize()));
320 obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee)));
321 if (pwalletMain->IsCrypted())
322 obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime));
323 obj.push_back(Pair("errors", GetWarnings("statusbar")));
328 Value getnewaddress(const Array& params, bool fHelp)
330 if (fHelp || params.size() > 1)
332 "getnewaddress [account]\n"
333 "Returns a new bitcoin address for receiving payments. "
334 "If [account] is specified (recommended), it is added to the address book "
335 "so payments received with the address will be credited to [account].");
337 // Parse the account first so we don't generate a key if there's an error
339 if (params.size() > 0)
340 strAccount = AccountFromValue(params[0]);
342 if (!pwalletMain->IsLocked())
343 pwalletMain->TopUpKeyPool();
345 // Generate a new key that is added to wallet
346 std::vector<unsigned char> newKey;
347 if (!pwalletMain->GetKeyFromPool(newKey, false))
348 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
349 CBitcoinAddress address(newKey);
351 pwalletMain->SetAddressBookName(address, strAccount);
353 return address.ToString();
357 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
359 CWalletDB walletdb(pwalletMain->strWalletFile);
362 walletdb.ReadAccount(strAccount, account);
364 bool bKeyUsed = false;
366 // Check if the current key has been used
367 if (!account.vchPubKey.empty())
369 CScript scriptPubKey;
370 scriptPubKey.SetBitcoinAddress(account.vchPubKey);
371 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
372 it != pwalletMain->mapWallet.end() && !account.vchPubKey.empty();
375 const CWalletTx& wtx = (*it).second;
376 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
377 if (txout.scriptPubKey == scriptPubKey)
382 // Generate a new key
383 if (account.vchPubKey.empty() || bForceNew || bKeyUsed)
385 if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false))
386 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
388 pwalletMain->SetAddressBookName(CBitcoinAddress(account.vchPubKey), strAccount);
389 walletdb.WriteAccount(strAccount, account);
392 return CBitcoinAddress(account.vchPubKey);
395 Value getaccountaddress(const Array& params, bool fHelp)
397 if (fHelp || params.size() != 1)
399 "getaccountaddress <account>\n"
400 "Returns the current bitcoin address for receiving payments to this account.");
402 // Parse the account first so we don't generate a key if there's an error
403 string strAccount = AccountFromValue(params[0]);
407 ret = GetAccountAddress(strAccount).ToString();
414 Value setaccount(const Array& params, bool fHelp)
416 if (fHelp || params.size() < 1 || params.size() > 2)
418 "setaccount <bitcoinaddress> <account>\n"
419 "Sets the account associated with the given address.");
421 CBitcoinAddress address(params[0].get_str());
422 if (!address.IsValid())
423 throw JSONRPCError(-5, "Invalid bitcoin address");
427 if (params.size() > 1)
428 strAccount = AccountFromValue(params[1]);
430 // Detect when changing the account of an address that is the 'unused current key' of another account:
431 if (pwalletMain->mapAddressBook.count(address))
433 string strOldAccount = pwalletMain->mapAddressBook[address];
434 if (address == GetAccountAddress(strOldAccount))
435 GetAccountAddress(strOldAccount, true);
438 pwalletMain->SetAddressBookName(address, strAccount);
444 Value getaccount(const Array& params, bool fHelp)
446 if (fHelp || params.size() != 1)
448 "getaccount <bitcoinaddress>\n"
449 "Returns the account associated with the given address.");
451 CBitcoinAddress address(params[0].get_str());
452 if (!address.IsValid())
453 throw JSONRPCError(-5, "Invalid bitcoin address");
456 map<CBitcoinAddress, string>::iterator mi = pwalletMain->mapAddressBook.find(address);
457 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
458 strAccount = (*mi).second;
463 Value getaddressesbyaccount(const Array& params, bool fHelp)
465 if (fHelp || params.size() != 1)
467 "getaddressesbyaccount <account>\n"
468 "Returns the list of addresses for the given account.");
470 string strAccount = AccountFromValue(params[0]);
472 // Find all addresses that have the given account
474 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
476 const CBitcoinAddress& address = item.first;
477 const string& strName = item.second;
478 if (strName == strAccount)
479 ret.push_back(address.ToString());
484 Value settxfee(const Array& params, bool fHelp)
486 if (fHelp || params.size() < 1 || params.size() > 1)
488 "settxfee <amount>\n"
489 "<amount> is a real and is rounded to the nearest 0.0001\n"
490 "Minimum and default transaction fee is 1 coin");
493 int64 nAmount = MIN_TX_FEE;
494 if (params[0].get_real() != 0.0) // rejects 0.0 amounts
495 nAmount = max(nAmount, AmountFromValue(params[0]));
497 nTransactionFee = nAmount;
501 Value sendtoaddress(const Array& params, bool fHelp)
503 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
505 "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
506 "<amount> is a real and is rounded to the nearest 0.00000001\n"
507 "requires wallet passphrase to be set with walletpassphrase first");
508 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
510 "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
511 "<amount> is a real and is rounded to the nearest 0.00000001");
513 CBitcoinAddress address(params[0].get_str());
514 if (!address.IsValid())
515 throw JSONRPCError(-5, "Invalid bitcoin address");
518 int64 nAmount = AmountFromValue(params[1]);
522 if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
523 wtx.mapValue["comment"] = params[2].get_str();
524 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
525 wtx.mapValue["to"] = params[3].get_str();
527 if (pwalletMain->IsLocked())
528 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
530 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
532 throw JSONRPCError(-4, strError);
534 return wtx.GetHash().GetHex();
537 static const string strMessageMagic = "Bitcoin Signed Message:\n";
539 Value signmessage(const Array& params, bool fHelp)
541 if (fHelp || params.size() != 2)
543 "signmessage <bitcoinaddress> <message>\n"
544 "Sign a message with the private key of an address");
546 if (pwalletMain->IsLocked())
547 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
549 string strAddress = params[0].get_str();
550 string strMessage = params[1].get_str();
552 CBitcoinAddress addr(strAddress);
554 throw JSONRPCError(-3, "Invalid address");
557 if (!pwalletMain->GetKey(addr, key))
558 throw JSONRPCError(-4, "Private key not available");
560 CDataStream ss(SER_GETHASH);
561 ss << strMessageMagic;
564 vector<unsigned char> vchSig;
565 if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig))
566 throw JSONRPCError(-5, "Sign failed");
568 return EncodeBase64(&vchSig[0], vchSig.size());
571 Value verifymessage(const Array& params, bool fHelp)
573 if (fHelp || params.size() != 3)
575 "verifymessage <bitcoinaddress> <signature> <message>\n"
576 "Verify a signed message");
578 string strAddress = params[0].get_str();
579 string strSign = params[1].get_str();
580 string strMessage = params[2].get_str();
582 CBitcoinAddress addr(strAddress);
584 throw JSONRPCError(-3, "Invalid address");
586 bool fInvalid = false;
587 vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
590 throw JSONRPCError(-5, "Malformed base64 encoding");
592 CDataStream ss(SER_GETHASH);
593 ss << strMessageMagic;
597 if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
600 return (key.GetAddress() == addr);
604 Value getreceivedbyaddress(const Array& params, bool fHelp)
606 if (fHelp || params.size() < 1 || params.size() > 2)
608 "getreceivedbyaddress <bitcoinaddress> [minconf=1]\n"
609 "Returns the total amount received by <bitcoinaddress> in transactions with at least [minconf] confirmations.");
612 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
613 CScript scriptPubKey;
614 if (!address.IsValid())
615 throw JSONRPCError(-5, "Invalid bitcoin address");
616 scriptPubKey.SetBitcoinAddress(address);
617 if (!IsMine(*pwalletMain,scriptPubKey))
620 // Minimum confirmations
622 if (params.size() > 1)
623 nMinDepth = params[1].get_int();
627 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
629 const CWalletTx& wtx = (*it).second;
630 if (wtx.IsCoinBase() || !wtx.IsFinal())
633 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
634 if (txout.scriptPubKey == scriptPubKey)
635 if (wtx.GetDepthInMainChain() >= nMinDepth)
636 nAmount += txout.nValue;
639 return ValueFromAmount(nAmount);
643 void GetAccountAddresses(string strAccount, set<CBitcoinAddress>& setAddress)
645 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
647 const CBitcoinAddress& address = item.first;
648 const string& strName = item.second;
649 if (strName == strAccount)
650 setAddress.insert(address);
655 Value getreceivedbyaccount(const Array& params, bool fHelp)
657 if (fHelp || params.size() < 1 || params.size() > 2)
659 "getreceivedbyaccount <account> [minconf=1]\n"
660 "Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.");
662 // Minimum confirmations
664 if (params.size() > 1)
665 nMinDepth = params[1].get_int();
667 // Get the set of pub keys that have the label
668 string strAccount = AccountFromValue(params[0]);
669 set<CBitcoinAddress> setAddress;
670 GetAccountAddresses(strAccount, setAddress);
674 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
676 const CWalletTx& wtx = (*it).second;
677 if (wtx.IsCoinBase() || !wtx.IsFinal())
680 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
682 CBitcoinAddress address;
683 if (ExtractAddress(txout.scriptPubKey, pwalletMain, address) && setAddress.count(address))
684 if (wtx.GetDepthInMainChain() >= nMinDepth)
685 nAmount += txout.nValue;
689 return (double)nAmount / (double)COIN;
693 int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth)
697 // Tally wallet transactions
698 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
700 const CWalletTx& wtx = (*it).second;
704 int64 nGenerated, nReceived, nSent, nFee;
705 wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee);
707 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
708 nBalance += nReceived;
709 nBalance += nGenerated - nSent - nFee;
712 // Tally internal accounting entries
713 nBalance += walletdb.GetAccountCreditDebit(strAccount);
718 int64 GetAccountBalance(const string& strAccount, int nMinDepth)
720 CWalletDB walletdb(pwalletMain->strWalletFile);
721 return GetAccountBalance(walletdb, strAccount, nMinDepth);
725 Value getbalance(const Array& params, bool fHelp)
727 if (fHelp || params.size() > 2)
729 "getbalance [account] [minconf=1]\n"
730 "If [account] is not specified, returns the server's total available balance.\n"
731 "If [account] is specified, returns the balance in the account.");
733 if (params.size() == 0)
734 return ValueFromAmount(pwalletMain->GetBalance());
737 if (params.size() > 1)
738 nMinDepth = params[1].get_int();
740 if (params[0].get_str() == "*") {
741 // Calculate total balance a different way from GetBalance()
742 // (GetBalance() sums up all unspent TxOuts)
743 // getbalance and getbalance '*' should always return the same number.
745 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
747 const CWalletTx& wtx = (*it).second;
751 int64 allGeneratedImmature, allGeneratedMature, allFee;
752 allGeneratedImmature = allGeneratedMature = allFee = 0;
753 string strSentAccount;
754 list<pair<CBitcoinAddress, int64> > listReceived;
755 list<pair<CBitcoinAddress, int64> > listSent;
756 wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
757 if (wtx.GetDepthInMainChain() >= nMinDepth)
758 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listReceived)
759 nBalance += r.second;
760 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listSent)
761 nBalance -= r.second;
763 nBalance += allGeneratedMature;
765 return ValueFromAmount(nBalance);
768 string strAccount = AccountFromValue(params[0]);
770 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
772 return ValueFromAmount(nBalance);
776 Value movecmd(const Array& params, bool fHelp)
778 if (fHelp || params.size() < 3 || params.size() > 5)
780 "move <fromaccount> <toaccount> <amount> [minconf=1] [comment]\n"
781 "Move from one account in your wallet to another.");
783 string strFrom = AccountFromValue(params[0]);
784 string strTo = AccountFromValue(params[1]);
785 int64 nAmount = AmountFromValue(params[2]);
786 if (params.size() > 3)
787 // unused parameter, used to be nMinDepth, keep type-checking it though
788 (void)params[3].get_int();
790 if (params.size() > 4)
791 strComment = params[4].get_str();
793 CWalletDB walletdb(pwalletMain->strWalletFile);
796 int64 nNow = GetAdjustedTime();
799 CAccountingEntry debit;
800 debit.strAccount = strFrom;
801 debit.nCreditDebit = -nAmount;
803 debit.strOtherAccount = strTo;
804 debit.strComment = strComment;
805 walletdb.WriteAccountingEntry(debit);
808 CAccountingEntry credit;
809 credit.strAccount = strTo;
810 credit.nCreditDebit = nAmount;
812 credit.strOtherAccount = strFrom;
813 credit.strComment = strComment;
814 walletdb.WriteAccountingEntry(credit);
816 walletdb.TxnCommit();
822 Value sendfrom(const Array& params, bool fHelp)
824 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
826 "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
827 "<amount> is a real and is rounded to the nearest 0.00000001\n"
828 "requires wallet passphrase to be set with walletpassphrase first");
829 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
831 "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
832 "<amount> is a real and is rounded to the nearest 0.00000001");
834 string strAccount = AccountFromValue(params[0]);
835 CBitcoinAddress address(params[1].get_str());
836 if (!address.IsValid())
837 throw JSONRPCError(-5, "Invalid bitcoin address");
838 int64 nAmount = AmountFromValue(params[2]);
840 if (params.size() > 3)
841 nMinDepth = params[3].get_int();
844 wtx.strFromAccount = strAccount;
845 if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
846 wtx.mapValue["comment"] = params[4].get_str();
847 if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
848 wtx.mapValue["to"] = params[5].get_str();
850 if (pwalletMain->IsLocked())
851 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
854 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
855 if (nAmount > nBalance)
856 throw JSONRPCError(-6, "Account has insufficient funds");
859 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
861 throw JSONRPCError(-4, strError);
863 return wtx.GetHash().GetHex();
867 Value sendmany(const Array& params, bool fHelp)
869 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
871 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
872 "amounts are double-precision floating point numbers\n"
873 "requires wallet passphrase to be set with walletpassphrase first");
874 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
876 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
877 "amounts are double-precision floating point numbers");
879 string strAccount = AccountFromValue(params[0]);
880 Object sendTo = params[1].get_obj();
882 if (params.size() > 2)
883 nMinDepth = params[2].get_int();
886 wtx.strFromAccount = strAccount;
887 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
888 wtx.mapValue["comment"] = params[3].get_str();
890 set<CBitcoinAddress> setAddress;
891 vector<pair<CScript, int64> > vecSend;
893 int64 totalAmount = 0;
894 BOOST_FOREACH(const Pair& s, sendTo)
896 CBitcoinAddress address(s.name_);
897 if (!address.IsValid())
898 throw JSONRPCError(-5, string("Invalid bitcoin address:")+s.name_);
900 if (setAddress.count(address))
901 throw JSONRPCError(-8, string("Invalid parameter, duplicated address: ")+s.name_);
902 setAddress.insert(address);
904 CScript scriptPubKey;
905 scriptPubKey.SetBitcoinAddress(address);
906 int64 nAmount = AmountFromValue(s.value_);
907 totalAmount += nAmount;
909 vecSend.push_back(make_pair(scriptPubKey, nAmount));
912 if (pwalletMain->IsLocked())
913 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
916 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
917 if (totalAmount > nBalance)
918 throw JSONRPCError(-6, "Account has insufficient funds");
921 CReserveKey keyChange(pwalletMain);
922 int64 nFeeRequired = 0;
923 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
926 if (totalAmount + nFeeRequired > pwalletMain->GetBalance())
927 throw JSONRPCError(-6, "Insufficient funds");
928 throw JSONRPCError(-4, "Transaction creation failed");
930 if (!pwalletMain->CommitTransaction(wtx, keyChange))
931 throw JSONRPCError(-4, "Transaction commit failed");
933 return wtx.GetHash().GetHex();
948 Value ListReceived(const Array& params, bool fByAccounts)
950 // Minimum confirmations
952 if (params.size() > 0)
953 nMinDepth = params[0].get_int();
955 // Whether to include empty accounts
956 bool fIncludeEmpty = false;
957 if (params.size() > 1)
958 fIncludeEmpty = params[1].get_bool();
961 map<CBitcoinAddress, tallyitem> mapTally;
962 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
964 const CWalletTx& wtx = (*it).second;
965 if (wtx.IsCoinBase() || !wtx.IsFinal())
968 int nDepth = wtx.GetDepthInMainChain();
969 if (nDepth < nMinDepth)
972 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
974 CBitcoinAddress address;
975 if (!ExtractAddress(txout.scriptPubKey, pwalletMain, address) || !address.IsValid())
978 tallyitem& item = mapTally[address];
979 item.nAmount += txout.nValue;
980 item.nConf = min(item.nConf, nDepth);
986 map<string, tallyitem> mapAccountTally;
987 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
989 const CBitcoinAddress& address = item.first;
990 const string& strAccount = item.second;
991 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
992 if (it == mapTally.end() && !fIncludeEmpty)
997 if (it != mapTally.end())
999 nAmount = (*it).second.nAmount;
1000 nConf = (*it).second.nConf;
1005 tallyitem& item = mapAccountTally[strAccount];
1006 item.nAmount += nAmount;
1007 item.nConf = min(item.nConf, nConf);
1012 obj.push_back(Pair("address", address.ToString()));
1013 obj.push_back(Pair("account", strAccount));
1014 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1015 obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
1022 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
1024 int64 nAmount = (*it).second.nAmount;
1025 int nConf = (*it).second.nConf;
1027 obj.push_back(Pair("account", (*it).first));
1028 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1029 obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
1037 Value listreceivedbyaddress(const Array& params, bool fHelp)
1039 if (fHelp || params.size() > 2)
1040 throw runtime_error(
1041 "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
1042 "[minconf] is the minimum number of confirmations before payments are included.\n"
1043 "[includeempty] whether to include addresses that haven't received any payments.\n"
1044 "Returns an array of objects containing:\n"
1045 " \"address\" : receiving address\n"
1046 " \"account\" : the account of the receiving address\n"
1047 " \"amount\" : total amount received by the address\n"
1048 " \"confirmations\" : number of confirmations of the most recent transaction included");
1050 return ListReceived(params, false);
1053 Value listreceivedbyaccount(const Array& params, bool fHelp)
1055 if (fHelp || params.size() > 2)
1056 throw runtime_error(
1057 "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
1058 "[minconf] is the minimum number of confirmations before payments are included.\n"
1059 "[includeempty] whether to include accounts that haven't received any payments.\n"
1060 "Returns an array of objects containing:\n"
1061 " \"account\" : the account of the receiving addresses\n"
1062 " \"amount\" : total amount received by addresses with this account\n"
1063 " \"confirmations\" : number of confirmations of the most recent transaction included");
1065 return ListReceived(params, true);
1068 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret)
1070 int64 nGeneratedImmature, nGeneratedMature, nFee;
1071 string strSentAccount;
1072 list<pair<CBitcoinAddress, int64> > listReceived;
1073 list<pair<CBitcoinAddress, int64> > listSent;
1074 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1076 bool fAllAccounts = (strAccount == string("*"));
1078 // Generated blocks assigned to account ""
1079 if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == ""))
1082 entry.push_back(Pair("account", string("")));
1083 if (nGeneratedImmature)
1085 entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
1086 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
1090 entry.push_back(Pair("category", "generate"));
1091 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
1094 WalletTxToJSON(wtx, entry);
1095 ret.push_back(entry);
1099 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1101 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1104 entry.push_back(Pair("account", strSentAccount));
1105 entry.push_back(Pair("address", s.first.ToString()));
1106 entry.push_back(Pair("category", "send"));
1107 entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1108 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1110 WalletTxToJSON(wtx, entry);
1111 ret.push_back(entry);
1116 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1117 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1120 if (pwalletMain->mapAddressBook.count(r.first))
1121 account = pwalletMain->mapAddressBook[r.first];
1122 if (fAllAccounts || (account == strAccount))
1125 entry.push_back(Pair("account", account));
1126 entry.push_back(Pair("address", r.first.ToString()));
1127 entry.push_back(Pair("category", "receive"));
1128 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1130 WalletTxToJSON(wtx, entry);
1131 ret.push_back(entry);
1136 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1138 bool fAllAccounts = (strAccount == string("*"));
1140 if (fAllAccounts || acentry.strAccount == strAccount)
1143 entry.push_back(Pair("account", acentry.strAccount));
1144 entry.push_back(Pair("category", "move"));
1145 entry.push_back(Pair("time", (boost::int64_t)acentry.nTime));
1146 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1147 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1148 entry.push_back(Pair("comment", acentry.strComment));
1149 ret.push_back(entry);
1153 Value listtransactions(const Array& params, bool fHelp)
1155 if (fHelp || params.size() > 3)
1156 throw runtime_error(
1157 "listtransactions [account] [count=10] [from=0]\n"
1158 "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1160 string strAccount = "*";
1161 if (params.size() > 0)
1162 strAccount = params[0].get_str();
1164 if (params.size() > 1)
1165 nCount = params[1].get_int();
1167 if (params.size() > 2)
1168 nFrom = params[2].get_int();
1171 CWalletDB walletdb(pwalletMain->strWalletFile);
1173 // Firs: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap:
1174 typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
1175 typedef multimap<int64, TxPair > TxItems;
1178 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1180 CWalletTx* wtx = &((*it).second);
1181 txByTime.insert(make_pair(wtx->GetTxTime(), TxPair(wtx, (CAccountingEntry*)0)));
1183 list<CAccountingEntry> acentries;
1184 walletdb.ListAccountCreditDebit(strAccount, acentries);
1185 BOOST_FOREACH(CAccountingEntry& entry, acentries)
1187 txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
1190 // Now: iterate backwards until we have nCount items to return:
1191 TxItems::reverse_iterator it = txByTime.rbegin();
1192 if (txByTime.size() > nFrom) std::advance(it, nFrom);
1193 for (; it != txByTime.rend(); ++it)
1195 CWalletTx *const pwtx = (*it).second.first;
1197 ListTransactions(*pwtx, strAccount, 0, true, ret);
1198 CAccountingEntry *const pacentry = (*it).second.second;
1200 AcentryToJSON(*pacentry, strAccount, ret);
1202 if (ret.size() >= nCount) break;
1204 // ret is now newest to oldest
1206 // Make sure we return only last nCount items (sends-to-self might give us an extra):
1207 if (ret.size() > nCount)
1209 Array::iterator last = ret.begin();
1210 std::advance(last, nCount);
1211 ret.erase(last, ret.end());
1213 std::reverse(ret.begin(), ret.end()); // oldest to newest
1218 Value listaccounts(const Array& params, bool fHelp)
1220 if (fHelp || params.size() > 1)
1221 throw runtime_error(
1222 "listaccounts [minconf=1]\n"
1223 "Returns Object that has account names as keys, account balances as values.");
1226 if (params.size() > 0)
1227 nMinDepth = params[0].get_int();
1229 map<string, int64> mapAccountBalances;
1230 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& entry, pwalletMain->mapAddressBook) {
1231 if (pwalletMain->HaveKey(entry.first)) // This address belongs to me
1232 mapAccountBalances[entry.second] = 0;
1235 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1237 const CWalletTx& wtx = (*it).second;
1238 int64 nGeneratedImmature, nGeneratedMature, nFee;
1239 string strSentAccount;
1240 list<pair<CBitcoinAddress, int64> > listReceived;
1241 list<pair<CBitcoinAddress, int64> > listSent;
1242 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1243 mapAccountBalances[strSentAccount] -= nFee;
1244 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1245 mapAccountBalances[strSentAccount] -= s.second;
1246 if (wtx.GetDepthInMainChain() >= nMinDepth)
1248 mapAccountBalances[""] += nGeneratedMature;
1249 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1250 if (pwalletMain->mapAddressBook.count(r.first))
1251 mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1253 mapAccountBalances[""] += r.second;
1257 list<CAccountingEntry> acentries;
1258 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1259 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1260 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1263 BOOST_FOREACH(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) {
1264 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1269 Value listsinceblock(const Array& params, bool fHelp)
1272 throw runtime_error(
1273 "listsinceblock [blockid] [target-confirmations]\n"
1274 "Get all transactions in blocks since block [blockid], or all transactions if omitted");
1276 CBlockIndex *pindex = NULL;
1277 int target_confirms = 1;
1279 if (params.size() > 0)
1281 uint256 blockId = 0;
1283 blockId.SetHex(params[0].get_str());
1284 pindex = CBlockLocator(blockId).GetBlockIndex();
1287 if (params.size() > 1)
1289 target_confirms = params[1].get_int();
1291 if (target_confirms < 1)
1292 throw JSONRPCError(-8, "Invalid parameter");
1295 int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1;
1299 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1301 CWalletTx tx = (*it).second;
1303 if (depth == -1 || tx.GetDepthInMainChain() < depth)
1304 ListTransactions(tx, "*", 0, true, transactions);
1309 if (target_confirms == 1)
1312 lastblock = hashBestChain;
1316 int target_height = pindexBest->nHeight + 1 - target_confirms;
1319 for (block = pindexBest;
1320 block && block->nHeight > target_height;
1321 block = block->pprev);
1323 lastblock = block ? block->GetBlockHash() : 0;
1327 ret.push_back(Pair("transactions", transactions));
1328 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1333 Value gettransaction(const Array& params, bool fHelp)
1335 if (fHelp || params.size() != 1)
1336 throw runtime_error(
1337 "gettransaction <txid>\n"
1338 "Get detailed information about <txid>");
1341 hash.SetHex(params[0].get_str());
1345 if (!pwalletMain->mapWallet.count(hash))
1346 throw JSONRPCError(-5, "Invalid or non-wallet transaction id");
1347 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1349 int64 nCredit = wtx.GetCredit();
1350 int64 nDebit = wtx.GetDebit();
1351 int64 nNet = nCredit - nDebit;
1352 int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
1354 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1356 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1358 WalletTxToJSON(pwalletMain->mapWallet[hash], entry);
1361 ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
1362 entry.push_back(Pair("details", details));
1368 Value backupwallet(const Array& params, bool fHelp)
1370 if (fHelp || params.size() != 1)
1371 throw runtime_error(
1372 "backupwallet <destination>\n"
1373 "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1375 string strDest = params[0].get_str();
1376 BackupWallet(*pwalletMain, strDest);
1382 Value keypoolrefill(const Array& params, bool fHelp)
1384 if (pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1385 throw runtime_error(
1387 "Fills the keypool, requires wallet passphrase to be set.");
1388 if (!pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1389 throw runtime_error(
1391 "Fills the keypool.");
1393 if (pwalletMain->IsLocked())
1394 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
1396 pwalletMain->TopUpKeyPool();
1398 if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100))
1399 throw JSONRPCError(-4, "Error refreshing keypool.");
1405 void ThreadTopUpKeyPool(void* parg)
1407 pwalletMain->TopUpKeyPool();
1410 void ThreadCleanWalletPassphrase(void* parg)
1412 int64 nMyWakeTime = GetTime() + *((int*)parg);
1414 if (nWalletUnlockTime == 0)
1416 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1418 nWalletUnlockTime = nMyWakeTime;
1421 while (GetTime() < nWalletUnlockTime)
1422 Sleep(GetTime() - nWalletUnlockTime);
1424 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1426 nWalletUnlockTime = 0;
1431 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1433 if (nWalletUnlockTime < nMyWakeTime)
1434 nWalletUnlockTime = nMyWakeTime;
1440 pwalletMain->Lock();
1445 Value walletpassphrase(const Array& params, bool fHelp)
1447 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1448 throw runtime_error(
1449 "walletpassphrase <passphrase> <timeout>\n"
1450 "Stores the wallet decryption key in memory for <timeout> seconds.");
1453 if (!pwalletMain->IsCrypted())
1454 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1456 if (!pwalletMain->IsLocked())
1457 throw JSONRPCError(-17, "Error: Wallet is already unlocked.");
1459 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1460 SecureString strWalletPass;
1461 strWalletPass.reserve(100);
1462 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1463 // Alternately, find a way to make params[0] mlock()'d to begin with.
1464 strWalletPass = params[0].get_str().c_str();
1466 if (strWalletPass.length() > 0)
1468 if (!pwalletMain->Unlock(strWalletPass))
1469 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1472 throw runtime_error(
1473 "walletpassphrase <passphrase> <timeout>\n"
1474 "Stores the wallet decryption key in memory for <timeout> seconds.");
1476 CreateThread(ThreadTopUpKeyPool, NULL);
1477 int* pnSleepTime = new int(params[1].get_int());
1478 CreateThread(ThreadCleanWalletPassphrase, pnSleepTime);
1484 Value walletpassphrasechange(const Array& params, bool fHelp)
1486 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1487 throw runtime_error(
1488 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1489 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1492 if (!pwalletMain->IsCrypted())
1493 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1495 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1496 // Alternately, find a way to make params[0] mlock()'d to begin with.
1497 SecureString strOldWalletPass;
1498 strOldWalletPass.reserve(100);
1499 strOldWalletPass = params[0].get_str().c_str();
1501 SecureString strNewWalletPass;
1502 strNewWalletPass.reserve(100);
1503 strNewWalletPass = params[1].get_str().c_str();
1505 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1506 throw runtime_error(
1507 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1508 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1510 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1511 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1517 Value walletlock(const Array& params, bool fHelp)
1519 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1520 throw runtime_error(
1522 "Removes the wallet encryption key from memory, locking the wallet.\n"
1523 "After calling this method, you will need to call walletpassphrase again\n"
1524 "before being able to call any methods which require the wallet to be unlocked.");
1527 if (!pwalletMain->IsCrypted())
1528 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called.");
1530 pwalletMain->Lock();
1531 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1533 nWalletUnlockTime = 0;
1540 Value encryptwallet(const Array& params, bool fHelp)
1542 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1543 throw runtime_error(
1544 "encryptwallet <passphrase>\n"
1545 "Encrypts the wallet with <passphrase>.");
1548 if (pwalletMain->IsCrypted())
1549 throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
1552 // shutting down via RPC while the GUI is running does not work (yet):
1553 throw runtime_error("Not Yet Implemented: use GUI to encrypt wallet, not RPC command");
1556 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1557 // Alternately, find a way to make params[0] mlock()'d to begin with.
1558 SecureString strWalletPass;
1559 strWalletPass.reserve(100);
1560 strWalletPass = params[0].get_str().c_str();
1562 if (strWalletPass.length() < 1)
1563 throw runtime_error(
1564 "encryptwallet <passphrase>\n"
1565 "Encrypts the wallet with <passphrase>.");
1567 if (!pwalletMain->EncryptWallet(strWalletPass))
1568 throw JSONRPCError(-16, "Error: Failed to encrypt the wallet.");
1570 // BDB seems to have a bad habit of writing old data into
1571 // slack space in .dat files; that is bad if the old data is
1572 // unencrypted private keys. So:
1573 CreateThread(Shutdown, NULL);
1574 return "wallet encrypted; bitcoin server stopping, restart to run with encrypted wallet";
1578 Value validateaddress(const Array& params, bool fHelp)
1580 if (fHelp || params.size() != 1)
1581 throw runtime_error(
1582 "validateaddress <bitcoinaddress>\n"
1583 "Return information about <bitcoinaddress>.");
1585 CBitcoinAddress address(params[0].get_str());
1586 bool isValid = address.IsValid();
1589 ret.push_back(Pair("isvalid", isValid));
1592 // Call Hash160ToAddress() so we always return current ADDRESSVERSION
1593 // version of the address:
1594 string currentAddress = address.ToString();
1595 ret.push_back(Pair("address", currentAddress));
1596 ret.push_back(Pair("ismine", (pwalletMain->HaveKey(address) > 0)));
1597 if (pwalletMain->mapAddressBook.count(address))
1598 ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
1604 Value getwork(const Array& params, bool fHelp)
1606 if (fHelp || params.size() > 1)
1607 throw runtime_error(
1609 "If [data] is not specified, returns formatted hash data to work on:\n"
1610 " \"midstate\" : precomputed hash state after hashing the first half of the data (DEPRECATED)\n" // deprecated
1611 " \"data\" : block data\n"
1612 " \"hash1\" : formatted hash buffer for second hash (DEPRECATED)\n" // deprecated
1613 " \"target\" : little endian hash target\n"
1614 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1617 throw JSONRPCError(-9, "Bitcoin is not connected!");
1619 if (IsInitialBlockDownload())
1620 throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
1622 typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
1623 static mapNewBlock_t mapNewBlock;
1624 static vector<CBlock*> vNewBlock;
1625 static CReserveKey reservekey(pwalletMain);
1627 if (params.size() == 0)
1630 static unsigned int nTransactionsUpdatedLast;
1631 static CBlockIndex* pindexPrev;
1632 static int64 nStart;
1633 static CBlock* pblock;
1634 if (pindexPrev != pindexBest ||
1635 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
1637 if (pindexPrev != pindexBest)
1639 // Deallocate old blocks since they're obsolete now
1640 mapNewBlock.clear();
1641 BOOST_FOREACH(CBlock* pblock, vNewBlock)
1645 nTransactionsUpdatedLast = nTransactionsUpdated;
1646 pindexPrev = pindexBest;
1650 pblock = CreateNewBlock(reservekey);
1652 throw JSONRPCError(-7, "Out of memory");
1653 vNewBlock.push_back(pblock);
1657 pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
1660 // Update nExtraNonce
1661 static unsigned int nExtraNonce = 0;
1662 IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
1665 mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
1667 // Prebuild hash buffers
1671 FormatHashBuffers(pblock, pmidstate, pdata, phash1);
1673 uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
1676 result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate)))); // deprecated
1677 result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata))));
1678 result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1)))); // deprecated
1679 result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
1685 vector<unsigned char> vchData = ParseHex(params[0].get_str());
1686 if (vchData.size() != 128)
1687 throw JSONRPCError(-8, "Invalid parameter");
1688 CBlock* pdata = (CBlock*)&vchData[0];
1691 for (int i = 0; i < 128/4; i++)
1692 ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]);
1695 if (!mapNewBlock.count(pdata->hashMerkleRoot))
1697 CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
1699 pblock->nTime = pdata->nTime;
1700 pblock->nNonce = pdata->nNonce;
1701 pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
1702 pblock->hashMerkleRoot = pblock->BuildMerkleTree();
1704 return CheckWork(pblock, *pwalletMain, reservekey);
1709 Value getmemorypool(const Array& params, bool fHelp)
1711 if (fHelp || params.size() > 1)
1712 throw runtime_error(
1713 "getmemorypool [data]\n"
1714 "If [data] is not specified, returns data needed to construct a block to work on:\n"
1715 " \"version\" : block version\n"
1716 " \"previousblockhash\" : hash of current highest block\n"
1717 " \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
1718 " \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
1719 " \"time\" : timestamp appropriate for next block\n"
1720 " \"bits\" : compressed target of next block\n"
1721 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1723 if (params.size() == 0)
1726 throw JSONRPCError(-9, "Bitcoin is not connected!");
1728 if (IsInitialBlockDownload())
1729 throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
1731 static CReserveKey reservekey(pwalletMain);
1734 static unsigned int nTransactionsUpdatedLast;
1735 static CBlockIndex* pindexPrev;
1736 static int64 nStart;
1737 static CBlock* pblock;
1738 if (pindexPrev != pindexBest ||
1739 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5))
1741 nTransactionsUpdatedLast = nTransactionsUpdated;
1742 pindexPrev = pindexBest;
1748 pblock = CreateNewBlock(reservekey);
1750 throw JSONRPCError(-7, "Out of memory");
1754 pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
1758 BOOST_FOREACH(CTransaction tx, pblock->vtx) {
1765 transactions.push_back(HexStr(ssTx.begin(), ssTx.end()));
1769 result.push_back(Pair("version", pblock->nVersion));
1770 result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
1771 result.push_back(Pair("transactions", transactions));
1772 result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
1773 result.push_back(Pair("time", (int64_t)pblock->nTime));
1779 uBits.nBits = htonl((int32_t)pblock->nBits);
1780 result.push_back(Pair("bits", HexStr(BEGIN(uBits.cBits), END(uBits.cBits))));
1787 CDataStream ssBlock(ParseHex(params[0].get_str()));
1791 return ProcessBlock(NULL, &pblock);
1809 pair<string, rpcfn_type> pCallTable[] =
1811 make_pair("help", &help),
1812 make_pair("stop", &stop),
1813 make_pair("getblockcount", &getblockcount),
1814 make_pair("getblocknumber", &getblocknumber),
1815 make_pair("getconnectioncount", &getconnectioncount),
1816 make_pair("getdifficulty", &getdifficulty),
1817 make_pair("getgenerate", &getgenerate),
1818 make_pair("setgenerate", &setgenerate),
1819 make_pair("gethashespersec", &gethashespersec),
1820 make_pair("getinfo", &getinfo),
1821 make_pair("getnewaddress", &getnewaddress),
1822 make_pair("getaccountaddress", &getaccountaddress),
1823 make_pair("setaccount", &setaccount),
1824 make_pair("getaccount", &getaccount),
1825 make_pair("getaddressesbyaccount", &getaddressesbyaccount),
1826 make_pair("sendtoaddress", &sendtoaddress),
1827 make_pair("getreceivedbyaddress", &getreceivedbyaddress),
1828 make_pair("getreceivedbyaccount", &getreceivedbyaccount),
1829 make_pair("listreceivedbyaddress", &listreceivedbyaddress),
1830 make_pair("listreceivedbyaccount", &listreceivedbyaccount),
1831 make_pair("backupwallet", &backupwallet),
1832 make_pair("keypoolrefill", &keypoolrefill),
1833 make_pair("walletpassphrase", &walletpassphrase),
1834 make_pair("walletpassphrasechange", &walletpassphrasechange),
1835 make_pair("walletlock", &walletlock),
1836 make_pair("encryptwallet", &encryptwallet),
1837 make_pair("validateaddress", &validateaddress),
1838 make_pair("getbalance", &getbalance),
1839 make_pair("move", &movecmd),
1840 make_pair("sendfrom", &sendfrom),
1841 make_pair("sendmany", &sendmany),
1842 make_pair("gettransaction", &gettransaction),
1843 make_pair("listtransactions", &listtransactions),
1844 make_pair("signmessage", &signmessage),
1845 make_pair("verifymessage", &verifymessage),
1846 make_pair("getwork", &getwork),
1847 make_pair("listaccounts", &listaccounts),
1848 make_pair("settxfee", &settxfee),
1849 make_pair("getmemorypool", &getmemorypool),
1850 make_pair("listsinceblock", &listsinceblock),
1852 map<string, rpcfn_type> mapCallTable(pCallTable, pCallTable + sizeof(pCallTable)/sizeof(pCallTable[0]));
1854 string pAllowInSafeMode[] =
1859 "getblocknumber", // deprecated
1860 "getconnectioncount",
1867 "getaccountaddress",
1869 "getaddressesbyaccount",
1878 set<string> setAllowInSafeMode(pAllowInSafeMode, pAllowInSafeMode + sizeof(pAllowInSafeMode)/sizeof(pAllowInSafeMode[0]));
1886 // This ain't Apache. We're just using HTTP header for the length field
1887 // and to be compatible with other JSON-RPC implementations.
1890 string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
1893 s << "POST / HTTP/1.1\r\n"
1894 << "User-Agent: bitcoin-json-rpc/" << FormatFullVersion() << "\r\n"
1895 << "Host: 127.0.0.1\r\n"
1896 << "Content-Type: application/json\r\n"
1897 << "Content-Length: " << strMsg.size() << "\r\n"
1898 << "Connection: close\r\n"
1899 << "Accept: application/json\r\n";
1900 BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
1901 s << item.first << ": " << item.second << "\r\n";
1902 s << "\r\n" << strMsg;
1907 string rfc1123Time()
1912 struct tm* now_gmt = gmtime(&now);
1913 string locale(setlocale(LC_TIME, NULL));
1914 setlocale(LC_TIME, "C"); // we want posix (aka "C") weekday/month strings
1915 strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt);
1916 setlocale(LC_TIME, locale.c_str());
1917 return string(buffer);
1920 static string HTTPReply(int nStatus, const string& strMsg)
1923 return strprintf("HTTP/1.0 401 Authorization Required\r\n"
1925 "Server: bitcoin-json-rpc/%s\r\n"
1926 "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
1927 "Content-Type: text/html\r\n"
1928 "Content-Length: 296\r\n"
1930 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
1931 "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
1934 "<TITLE>Error</TITLE>\r\n"
1935 "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
1937 "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
1938 "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
1939 const char *cStatus;
1940 if (nStatus == 200) cStatus = "OK";
1941 else if (nStatus == 400) cStatus = "Bad Request";
1942 else if (nStatus == 403) cStatus = "Forbidden";
1943 else if (nStatus == 404) cStatus = "Not Found";
1944 else if (nStatus == 500) cStatus = "Internal Server Error";
1947 "HTTP/1.1 %d %s\r\n"
1949 "Connection: close\r\n"
1950 "Content-Length: %d\r\n"
1951 "Content-Type: application/json\r\n"
1952 "Server: bitcoin-json-rpc/%s\r\n"
1957 rfc1123Time().c_str(),
1959 FormatFullVersion().c_str(),
1963 int ReadHTTPStatus(std::basic_istream<char>& stream)
1966 getline(stream, str);
1967 vector<string> vWords;
1968 boost::split(vWords, str, boost::is_any_of(" "));
1969 if (vWords.size() < 2)
1971 return atoi(vWords[1].c_str());
1974 int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
1980 std::getline(stream, str);
1981 if (str.empty() || str == "\r")
1983 string::size_type nColon = str.find(":");
1984 if (nColon != string::npos)
1986 string strHeader = str.substr(0, nColon);
1987 boost::trim(strHeader);
1988 boost::to_lower(strHeader);
1989 string strValue = str.substr(nColon+1);
1990 boost::trim(strValue);
1991 mapHeadersRet[strHeader] = strValue;
1992 if (strHeader == "content-length")
1993 nLen = atoi(strValue.c_str());
1999 int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
2001 mapHeadersRet.clear();
2005 int nStatus = ReadHTTPStatus(stream);
2008 int nLen = ReadHTTPHeader(stream, mapHeadersRet);
2009 if (nLen < 0 || nLen > MAX_SIZE)
2015 vector<char> vch(nLen);
2016 stream.read(&vch[0], nLen);
2017 strMessageRet = string(vch.begin(), vch.end());
2023 bool HTTPAuthorized(map<string, string>& mapHeaders)
2025 string strAuth = mapHeaders["authorization"];
2026 if (strAuth.substr(0,6) != "Basic ")
2028 string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
2029 string strUserPass = DecodeBase64(strUserPass64);
2030 return strUserPass == strRPCUserColonPass;
2034 // JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
2035 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
2036 // unspecified (HTTP errors and contents of 'error').
2038 // 1.0 spec: http://json-rpc.org/wiki/specification
2039 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
2040 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
2043 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
2046 request.push_back(Pair("method", strMethod));
2047 request.push_back(Pair("params", params));
2048 request.push_back(Pair("id", id));
2049 return write_string(Value(request), false) + "\n";
2052 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
2055 if (error.type() != null_type)
2056 reply.push_back(Pair("result", Value::null));
2058 reply.push_back(Pair("result", result));
2059 reply.push_back(Pair("error", error));
2060 reply.push_back(Pair("id", id));
2061 return write_string(Value(reply), false) + "\n";
2064 void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
2066 // Send error reply from json-rpc error object
2068 int code = find_value(objError, "code").get_int();
2069 if (code == -32600) nStatus = 400;
2070 else if (code == -32601) nStatus = 404;
2071 string strReply = JSONRPCReply(Value::null, objError, id);
2072 stream << HTTPReply(nStatus, strReply) << std::flush;
2075 bool ClientAllowed(const string& strAddress)
2077 if (strAddress == asio::ip::address_v4::loopback().to_string())
2079 const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
2080 BOOST_FOREACH(string strAllow, vAllow)
2081 if (WildcardMatch(strAddress, strAllow))
2088 // IOStream device that speaks SSL but can also speak non-SSL
2090 class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
2092 SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
2094 fUseSSL = fUseSSLIn;
2095 fNeedHandshake = fUseSSLIn;
2098 void handshake(ssl::stream_base::handshake_type role)
2100 if (!fNeedHandshake) return;
2101 fNeedHandshake = false;
2102 stream.handshake(role);
2104 std::streamsize read(char* s, std::streamsize n)
2106 handshake(ssl::stream_base::server); // HTTPS servers read first
2107 if (fUseSSL) return stream.read_some(asio::buffer(s, n));
2108 return stream.next_layer().read_some(asio::buffer(s, n));
2110 std::streamsize write(const char* s, std::streamsize n)
2112 handshake(ssl::stream_base::client); // HTTPS clients write first
2113 if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
2114 return asio::write(stream.next_layer(), asio::buffer(s, n));
2116 bool connect(const std::string& server, const std::string& port)
2118 ip::tcp::resolver resolver(stream.get_io_service());
2119 ip::tcp::resolver::query query(server.c_str(), port.c_str());
2120 ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
2121 ip::tcp::resolver::iterator end;
2122 boost::system::error_code error = asio::error::host_not_found;
2123 while (error && endpoint_iterator != end)
2125 stream.lowest_layer().close();
2126 stream.lowest_layer().connect(*endpoint_iterator++, error);
2134 bool fNeedHandshake;
2140 void ThreadRPCServer(void* parg)
2142 IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
2145 vnThreadsRunning[4]++;
2146 ThreadRPCServer2(parg);
2147 vnThreadsRunning[4]--;
2149 catch (std::exception& e) {
2150 vnThreadsRunning[4]--;
2151 PrintException(&e, "ThreadRPCServer()");
2153 vnThreadsRunning[4]--;
2154 PrintException(NULL, "ThreadRPCServer()");
2156 printf("ThreadRPCServer exiting\n");
2159 void ThreadRPCServer2(void* parg)
2161 printf("ThreadRPCServer started\n");
2163 strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
2164 if (strRPCUserColonPass == ":")
2166 string strWhatAmI = "To use bitcoind";
2167 if (mapArgs.count("-server"))
2168 strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
2169 else if (mapArgs.count("-daemon"))
2170 strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
2172 _("Error: %s, you must set rpcpassword=<password>\nin the configuration file: %s\n"
2173 "If the file does not exist, create it with owner-readable-only file permissions.\n"),
2175 GetConfigFile().c_str());
2177 CreateThread(Shutdown, NULL);
2182 bool fUseSSL = GetBoolArg("-rpcssl");
2183 asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
2185 asio::io_service io_service;
2186 ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", RPC_PORT));
2187 ip::tcp::acceptor acceptor(io_service, endpoint);
2189 acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
2192 ssl::context context(io_service, ssl::context::sslv23);
2195 context.set_options(ssl::context::no_sslv2);
2196 filesystem::path certfile = GetArg("-rpcsslcertificatechainfile", "server.cert");
2197 if (!certfile.is_complete()) certfile = filesystem::path(GetDataDir()) / certfile;
2198 if (filesystem::exists(certfile)) context.use_certificate_chain_file(certfile.string().c_str());
2199 else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", certfile.string().c_str());
2200 filesystem::path pkfile = GetArg("-rpcsslprivatekeyfile", "server.pem");
2201 if (!pkfile.is_complete()) pkfile = filesystem::path(GetDataDir()) / pkfile;
2202 if (filesystem::exists(pkfile)) context.use_private_key_file(pkfile.string().c_str(), ssl::context::pem);
2203 else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pkfile.string().c_str());
2205 string ciphers = GetArg("-rpcsslciphers",
2206 "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
2207 SSL_CTX_set_cipher_list(context.impl(), ciphers.c_str());
2211 throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
2216 // Accept connection
2218 SSLStream sslStream(io_service, context);
2219 SSLIOStreamDevice d(sslStream, fUseSSL);
2220 iostreams::stream<SSLIOStreamDevice> stream(d);
2222 ip::tcp::iostream stream;
2225 ip::tcp::endpoint peer;
2226 vnThreadsRunning[4]--;
2228 acceptor.accept(sslStream.lowest_layer(), peer);
2230 acceptor.accept(*stream.rdbuf(), peer);
2232 vnThreadsRunning[4]++;
2236 // Restrict callers by IP
2237 if (!ClientAllowed(peer.address().to_string()))
2239 // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
2241 stream << HTTPReply(403, "") << std::flush;
2245 map<string, string> mapHeaders;
2248 boost::thread api_caller(ReadHTTP, boost::ref(stream), boost::ref(mapHeaders), boost::ref(strRequest));
2249 if (!api_caller.timed_join(boost::posix_time::seconds(GetArg("-rpctimeout", 30))))
2252 printf("ThreadRPCServer ReadHTTP timeout\n");
2256 // Check authorization
2257 if (mapHeaders.count("authorization") == 0)
2259 stream << HTTPReply(401, "") << std::flush;
2262 if (!HTTPAuthorized(mapHeaders))
2264 // Deter brute-forcing short passwords
2265 if (mapArgs["-rpcpassword"].size() < 15)
2268 stream << HTTPReply(401, "") << std::flush;
2269 printf("ThreadRPCServer incorrect password attempt\n");
2273 Value id = Value::null;
2278 if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
2279 throw JSONRPCError(-32700, "Parse error");
2280 const Object& request = valRequest.get_obj();
2282 // Parse id now so errors from here on will have the id
2283 id = find_value(request, "id");
2286 Value valMethod = find_value(request, "method");
2287 if (valMethod.type() == null_type)
2288 throw JSONRPCError(-32600, "Missing method");
2289 if (valMethod.type() != str_type)
2290 throw JSONRPCError(-32600, "Method must be a string");
2291 string strMethod = valMethod.get_str();
2292 if (strMethod != "getwork" && strMethod != "getmemorypool")
2293 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
2296 Value valParams = find_value(request, "params");
2298 if (valParams.type() == array_type)
2299 params = valParams.get_array();
2300 else if (valParams.type() == null_type)
2303 throw JSONRPCError(-32600, "Params must be an array");
2306 map<string, rpcfn_type>::iterator mi = mapCallTable.find(strMethod);
2307 if (mi == mapCallTable.end())
2308 throw JSONRPCError(-32601, "Method not found");
2310 // Observe safe mode
2311 string strWarning = GetWarnings("rpc");
2312 if (strWarning != "" && !GetBoolArg("-disablesafemode") && !setAllowInSafeMode.count(strMethod))
2313 throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
2319 CRITICAL_BLOCK(cs_main)
2320 CRITICAL_BLOCK(pwalletMain->cs_wallet)
2321 result = (*(*mi).second)(params, false);
2324 string strReply = JSONRPCReply(result, Value::null, id);
2325 stream << HTTPReply(200, strReply) << std::flush;
2327 catch (std::exception& e)
2329 ErrorReply(stream, JSONRPCError(-1, e.what()), id);
2332 catch (Object& objError)
2334 ErrorReply(stream, objError, id);
2336 catch (std::exception& e)
2338 ErrorReply(stream, JSONRPCError(-32700, e.what()), id);
2346 Object CallRPC(const string& strMethod, const Array& params)
2348 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2349 throw runtime_error(strprintf(
2350 _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
2351 "If the file does not exist, create it with owner-readable-only file permissions."),
2352 GetConfigFile().c_str()));
2354 // Connect to localhost
2355 bool fUseSSL = GetBoolArg("-rpcssl");
2357 asio::io_service io_service;
2358 ssl::context context(io_service, ssl::context::sslv23);
2359 context.set_options(ssl::context::no_sslv2);
2360 SSLStream sslStream(io_service, context);
2361 SSLIOStreamDevice d(sslStream, fUseSSL);
2362 iostreams::stream<SSLIOStreamDevice> stream(d);
2363 if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", CBigNum(RPC_PORT).ToString().c_str())))
2364 throw runtime_error("couldn't connect to server");
2367 throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
2369 ip::tcp::iostream stream(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", CBigNum(RPC_PORT).ToString().c_str()));
2371 throw runtime_error("couldn't connect to server");
2375 // HTTP basic authentication
2376 string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
2377 map<string, string> mapRequestHeaders;
2378 mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
2381 string strRequest = JSONRPCRequest(strMethod, params, 1);
2382 string strPost = HTTPPost(strRequest, mapRequestHeaders);
2383 stream << strPost << std::flush;
2386 map<string, string> mapHeaders;
2388 int nStatus = ReadHTTP(stream, mapHeaders, strReply);
2390 throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
2391 else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
2392 throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
2393 else if (strReply.empty())
2394 throw runtime_error("no response from server");
2398 if (!read_string(strReply, valReply))
2399 throw runtime_error("couldn't parse reply from server");
2400 const Object& reply = valReply.get_obj();
2402 throw runtime_error("expected reply to have result, error and id properties");
2410 template<typename T>
2411 void ConvertTo(Value& value)
2413 if (value.type() == str_type)
2415 // reinterpret string as unquoted json value
2417 if (!read_string(value.get_str(), value2))
2418 throw runtime_error("type mismatch");
2419 value = value2.get_value<T>();
2423 value = value.get_value<T>();
2427 int CommandLineRPC(int argc, char *argv[])
2434 while (argc > 1 && IsSwitchChar(argv[1][0]))
2442 throw runtime_error("too few parameters");
2443 string strMethod = argv[1];
2445 // Parameters default to strings
2447 for (int i = 2; i < argc; i++)
2448 params.push_back(argv[i]);
2449 int n = params.size();
2452 // Special case non-string parameter types
2454 if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
2455 if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2456 if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
2457 if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]);
2458 if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2459 if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2460 if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2461 if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
2462 if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2463 if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
2464 if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2465 if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]);
2466 if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2467 if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]);
2468 if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2469 if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2470 if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2471 if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2472 if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2473 if (strMethod == "listsinceblock" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2474 if (strMethod == "sendmany" && n > 1)
2476 string s = params[1].get_str();
2478 if (!read_string(s, v) || v.type() != obj_type)
2479 throw runtime_error("type mismatch");
2480 params[1] = v.get_obj();
2482 if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2485 Object reply = CallRPC(strMethod, params);
2488 const Value& result = find_value(reply, "result");
2489 const Value& error = find_value(reply, "error");
2491 if (error.type() != null_type)
2494 strPrint = "error: " + write_string(error, false);
2495 int code = find_value(error.get_obj(), "code").get_int();
2501 if (result.type() == null_type)
2503 else if (result.type() == str_type)
2504 strPrint = result.get_str();
2506 strPrint = write_string(result, true);
2509 catch (std::exception& e)
2511 strPrint = string("error: ") + e.what();
2516 PrintException(NULL, "CommandLineRPC()");
2521 fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
2530 int main(int argc, char *argv[])
2533 // Turn off microsoft heap dump noise
2534 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
2535 _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
2537 setbuf(stdin, NULL);
2538 setbuf(stdout, NULL);
2539 setbuf(stderr, NULL);
2543 if (argc >= 2 && string(argv[1]) == "-server")
2545 printf("server ready\n");
2546 ThreadRPCServer(NULL);
2550 return CommandLineRPC(argc, argv);
2553 catch (std::exception& e) {
2554 PrintException(&e, "main()");
2556 PrintException(NULL, "main()");