1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Copyright (c) 2011 The Bitcoin developers
3 // Distributed under the MIT/X11 software license, see the accompanying
4 // file license.txt or http://www.opensource.org/licenses/mit-license.php.
11 #include <boost/asio.hpp>
12 #include <boost/iostreams/concepts.hpp>
13 #include <boost/iostreams/stream.hpp>
14 #include <boost/algorithm/string.hpp>
16 #include <boost/asio/ssl.hpp>
17 #include <boost/filesystem.hpp>
18 #include <boost/filesystem/fstream.hpp>
19 typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> SSLStream;
21 #include "json/json_spirit_reader_template.h"
22 #include "json/json_spirit_writer_template.h"
23 #include "json/json_spirit_utils.h"
24 #define printf OutputDebugStringF
25 // MinGW 3.4.5 gets "fatal error: had to relocate PCH" if the json headers are
26 // precompiled in headers.h. The problem might be when the pch file goes over
27 // a certain size around 145MB. If we need access to json_spirit outside this
28 // file, we could use the compiled json_spirit option.
31 using namespace boost;
32 using namespace boost::asio;
33 using namespace json_spirit;
35 void ThreadRPCServer2(void* parg);
36 typedef Value(*rpcfn_type)(const Array& params, bool fHelp);
37 extern map<string, rpcfn_type> mapCallTable;
39 static int64 nWalletUnlockTime;
40 static CCriticalSection cs_nWalletUnlockTime;
43 Object JSONRPCError(int code, const string& message)
46 error.push_back(Pair("code", code));
47 error.push_back(Pair("message", message));
52 void PrintConsole(const std::string &format, ...)
55 int limit = sizeof(buffer);
57 va_start(arg_ptr, format);
58 int ret = _vsnprintf(buffer, limit, format.c_str(), arg_ptr);
60 if (ret < 0 || ret >= limit)
66 fprintf(stdout, "%s", buffer);
70 int64 AmountFromValue(const Value& value)
72 double dAmount = value.get_real();
73 if (dAmount <= 0.0 || dAmount > 21000000.0)
74 throw JSONRPCError(-3, "Invalid amount");
75 int64 nAmount = roundint64(dAmount * COIN);
76 if (!MoneyRange(nAmount))
77 throw JSONRPCError(-3, "Invalid amount");
81 Value ValueFromAmount(int64 amount)
83 return (double)amount / (double)COIN;
86 void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
88 entry.push_back(Pair("confirmations", wtx.GetDepthInMainChain()));
89 entry.push_back(Pair("txid", wtx.GetHash().GetHex()));
90 entry.push_back(Pair("time", (boost::int64_t)wtx.GetTxTime()));
91 BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
92 entry.push_back(Pair(item.first, item.second));
95 string AccountFromValue(const Value& value)
97 string strAccount = value.get_str();
98 if (strAccount == "*")
99 throw JSONRPCError(-11, "Invalid account name");
106 /// Note: This interface may still be subject to change.
110 Value help(const Array& params, bool fHelp)
112 if (fHelp || params.size() > 1)
115 "List commands, or get help for a command.");
118 if (params.size() > 0)
119 strCommand = params[0].get_str();
122 set<rpcfn_type> setDone;
123 for (map<string, rpcfn_type>::iterator mi = mapCallTable.begin(); mi != mapCallTable.end(); ++mi)
125 string strMethod = (*mi).first;
126 // We already filter duplicates, but these deprecated screw up the sort order
127 if (strMethod == "getamountreceived" ||
128 strMethod == "getallreceived" ||
129 (strMethod.find("label") != string::npos))
131 if (strCommand != "" && strMethod != strCommand)
136 rpcfn_type pfn = (*mi).second;
137 if (setDone.insert(pfn).second)
138 (*pfn)(params, true);
140 catch (std::exception& e)
142 // Help text is returned in an exception
143 string strHelp = string(e.what());
144 if (strCommand == "")
145 if (strHelp.find('\n') != -1)
146 strHelp = strHelp.substr(0, strHelp.find('\n'));
147 strRet += strHelp + "\n";
151 strRet = strprintf("help: unknown command: %s\n", strCommand.c_str());
152 strRet = strRet.substr(0,strRet.size()-1);
157 Value stop(const Array& params, bool fHelp)
159 if (fHelp || params.size() != 0)
162 "Stop bitcoin server.");
164 // Shutdown will take long enough that the response should get back
165 CreateThread(Shutdown, NULL);
166 return "bitcoin server stopping";
170 Value getblockcount(const Array& params, bool fHelp)
172 if (fHelp || params.size() != 0)
175 "Returns the number of blocks in the longest block chain.");
181 Value getblocknumber(const Array& params, bool fHelp)
183 if (fHelp || params.size() != 0)
186 "Returns the block number of the latest block in the longest block chain.");
192 Value getconnectioncount(const Array& params, bool fHelp)
194 if (fHelp || params.size() != 0)
196 "getconnectioncount\n"
197 "Returns the number of connections to other nodes.");
199 return (int)vNodes.size();
203 double GetDifficulty()
205 // Floating point number that is a multiple of the minimum difficulty,
206 // minimum difficulty = 1.0.
208 if (pindexBest == NULL)
210 int nShift = (pindexBest->nBits >> 24) & 0xff;
213 (double)0x0000ffff / (double)(pindexBest->nBits & 0x00ffffff);
229 Value getdifficulty(const Array& params, bool fHelp)
231 if (fHelp || params.size() != 0)
234 "Returns the proof-of-work difficulty as a multiple of the minimum difficulty.");
236 return GetDifficulty();
240 Value getgenerate(const Array& params, bool fHelp)
242 if (fHelp || params.size() != 0)
245 "Returns true or false.");
247 return (bool)fGenerateBitcoins;
251 Value setgenerate(const Array& params, bool fHelp)
253 if (fHelp || params.size() < 1 || params.size() > 2)
255 "setgenerate <generate> [genproclimit]\n"
256 "<generate> is true or false to turn generation on or off.\n"
257 "Generation is limited to [genproclimit] processors, -1 is unlimited.");
259 bool fGenerate = true;
260 if (params.size() > 0)
261 fGenerate = params[0].get_bool();
263 if (params.size() > 1)
265 int nGenProcLimit = params[1].get_int();
266 fLimitProcessors = (nGenProcLimit != -1);
267 WriteSetting("fLimitProcessors", fLimitProcessors);
268 if (nGenProcLimit != -1)
269 WriteSetting("nLimitProcessors", nLimitProcessors = nGenProcLimit);
270 if (nGenProcLimit == 0)
274 GenerateBitcoins(fGenerate, pwalletMain);
279 Value gethashespersec(const Array& params, bool fHelp)
281 if (fHelp || params.size() != 0)
284 "Returns a recent hashes per second performance measurement while generating.");
286 if (GetTimeMillis() - nHPSTimerStart > 8000)
287 return (boost::int64_t)0;
288 return (boost::int64_t)dHashesPerSec;
292 Value getinfo(const Array& params, bool fHelp)
294 if (fHelp || params.size() != 0)
297 "Returns an object containing various state info.");
300 obj.push_back(Pair("version", (int)VERSION));
301 obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
302 obj.push_back(Pair("blocks", (int)nBestHeight));
303 obj.push_back(Pair("connections", (int)vNodes.size()));
304 obj.push_back(Pair("proxy", (fUseProxy ? addrProxy.ToStringIPPort() : string())));
305 obj.push_back(Pair("generate", (bool)fGenerateBitcoins));
306 obj.push_back(Pair("genproclimit", (int)(fLimitProcessors ? nLimitProcessors : -1)));
307 obj.push_back(Pair("difficulty", (double)GetDifficulty()));
308 obj.push_back(Pair("hashespersec", gethashespersec(params, false)));
309 obj.push_back(Pair("testnet", fTestNet));
310 obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));
311 obj.push_back(Pair("keypoolsize", pwalletMain->GetKeyPoolSize()));
312 obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee)));
313 if (pwalletMain->IsCrypted())
314 obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime));
315 obj.push_back(Pair("errors", GetWarnings("statusbar")));
320 Value getnewaddress(const Array& params, bool fHelp)
322 if (fHelp || params.size() > 1)
324 "getnewaddress [account]\n"
325 "Returns a new bitcoin address for receiving payments. "
326 "If [account] is specified (recommended), it is added to the address book "
327 "so payments received with the address will be credited to [account].");
329 // Parse the account first so we don't generate a key if there's an error
331 if (params.size() > 0)
332 strAccount = AccountFromValue(params[0]);
334 if (!pwalletMain->IsLocked())
335 pwalletMain->TopUpKeyPool();
337 // Generate a new key that is added to wallet
338 std::vector<unsigned char> newKey;
339 if (!pwalletMain->GetKeyFromPool(newKey, false))
340 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
341 CBitcoinAddress address(newKey);
343 pwalletMain->SetAddressBookName(address, strAccount);
345 return address.ToString();
349 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
351 CWalletDB walletdb(pwalletMain->strWalletFile);
354 walletdb.ReadAccount(strAccount, account);
356 bool bKeyUsed = false;
358 // Check if the current key has been used
359 if (!account.vchPubKey.empty())
361 CScript scriptPubKey;
362 scriptPubKey.SetBitcoinAddress(account.vchPubKey);
363 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
364 it != pwalletMain->mapWallet.end() && !account.vchPubKey.empty();
367 const CWalletTx& wtx = (*it).second;
368 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
369 if (txout.scriptPubKey == scriptPubKey)
374 // Generate a new key
375 if (account.vchPubKey.empty() || bForceNew || bKeyUsed)
377 if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false))
378 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
380 pwalletMain->SetAddressBookName(CBitcoinAddress(account.vchPubKey), strAccount);
381 walletdb.WriteAccount(strAccount, account);
384 return CBitcoinAddress(account.vchPubKey);
387 Value getaccountaddress(const Array& params, bool fHelp)
389 if (fHelp || params.size() != 1)
391 "getaccountaddress <account>\n"
392 "Returns the current bitcoin address for receiving payments to this account.");
394 // Parse the account first so we don't generate a key if there's an error
395 string strAccount = AccountFromValue(params[0]);
399 ret = GetAccountAddress(strAccount).ToString();
406 Value setaccount(const Array& params, bool fHelp)
408 if (fHelp || params.size() < 1 || params.size() > 2)
410 "setaccount <bitcoinaddress> <account>\n"
411 "Sets the account associated with the given address.");
413 CBitcoinAddress address(params[0].get_str());
414 if (!address.IsValid())
415 throw JSONRPCError(-5, "Invalid bitcoin address");
419 if (params.size() > 1)
420 strAccount = AccountFromValue(params[1]);
422 // Detect when changing the account of an address that is the 'unused current key' of another account:
423 if (pwalletMain->mapAddressBook.count(address))
425 string strOldAccount = pwalletMain->mapAddressBook[address];
426 if (address == GetAccountAddress(strOldAccount))
427 GetAccountAddress(strOldAccount, true);
430 pwalletMain->SetAddressBookName(address, strAccount);
436 Value getaccount(const Array& params, bool fHelp)
438 if (fHelp || params.size() != 1)
440 "getaccount <bitcoinaddress>\n"
441 "Returns the account associated with the given address.");
443 CBitcoinAddress address(params[0].get_str());
444 if (!address.IsValid())
445 throw JSONRPCError(-5, "Invalid bitcoin address");
448 map<CBitcoinAddress, string>::iterator mi = pwalletMain->mapAddressBook.find(address);
449 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
450 strAccount = (*mi).second;
455 Value getaddressesbyaccount(const Array& params, bool fHelp)
457 if (fHelp || params.size() != 1)
459 "getaddressesbyaccount <account>\n"
460 "Returns the list of addresses for the given account.");
462 string strAccount = AccountFromValue(params[0]);
464 // Find all addresses that have the given account
466 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
468 const CBitcoinAddress& address = item.first;
469 const string& strName = item.second;
470 if (strName == strAccount)
471 ret.push_back(address.ToString());
476 Value settxfee(const Array& params, bool fHelp)
478 if (fHelp || params.size() < 1 || params.size() > 1)
480 "settxfee <amount>\n"
481 "<amount> is a real and is rounded to the nearest 0.00000001");
485 if (params[0].get_real() != 0.0)
486 nAmount = AmountFromValue(params[0]); // rejects 0.0 amounts
488 nTransactionFee = nAmount;
492 Value sendtoaddress(const Array& params, bool fHelp)
494 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
496 "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
497 "<amount> is a real and is rounded to the nearest 0.00000001\n"
498 "requires wallet passphrase to be set with walletpassphrase first");
499 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
501 "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
502 "<amount> is a real and is rounded to the nearest 0.00000001");
504 CBitcoinAddress address(params[0].get_str());
505 if (!address.IsValid())
506 throw JSONRPCError(-5, "Invalid bitcoin address");
509 int64 nAmount = AmountFromValue(params[1]);
513 if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
514 wtx.mapValue["comment"] = params[2].get_str();
515 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
516 wtx.mapValue["to"] = params[3].get_str();
518 if (pwalletMain->IsLocked())
519 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
521 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
523 throw JSONRPCError(-4, strError);
525 return wtx.GetHash().GetHex();
528 static const string strMessageMagic = "Bitcoin Signed Message:\n";
530 Value signmessage(const Array& params, bool fHelp)
532 if (fHelp || params.size() != 2)
534 "signmessage <bitcoinaddress> <message>\n"
535 "Sign a message with the private key of an address");
537 if (pwalletMain->IsLocked())
538 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
540 string strAddress = params[0].get_str();
541 string strMessage = params[1].get_str();
543 CBitcoinAddress addr(strAddress);
545 throw JSONRPCError(-3, "Invalid address");
548 if (!pwalletMain->GetKey(addr, key))
549 throw JSONRPCError(-4, "Private key not available");
551 CDataStream ss(SER_GETHASH);
552 ss << strMessageMagic;
555 vector<unsigned char> vchSig;
556 if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig))
557 throw JSONRPCError(-5, "Sign failed");
559 return EncodeBase64(&vchSig[0], vchSig.size());
562 Value verifymessage(const Array& params, bool fHelp)
564 if (fHelp || params.size() != 3)
566 "verifymessage <bitcoinaddress> <signature> <message>\n"
567 "Verify a signed message");
569 string strAddress = params[0].get_str();
570 string strSign = params[1].get_str();
571 string strMessage = params[2].get_str();
573 CBitcoinAddress addr(strAddress);
575 throw JSONRPCError(-3, "Invalid address");
577 bool fInvalid = false;
578 vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
581 throw JSONRPCError(-5, "Malformed base64 encoding");
583 CDataStream ss(SER_GETHASH);
584 ss << strMessageMagic;
588 if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
591 return (key.GetAddress() == addr);
595 Value getreceivedbyaddress(const Array& params, bool fHelp)
597 if (fHelp || params.size() < 1 || params.size() > 2)
599 "getreceivedbyaddress <bitcoinaddress> [minconf=1]\n"
600 "Returns the total amount received by <bitcoinaddress> in transactions with at least [minconf] confirmations.");
603 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
604 CScript scriptPubKey;
605 if (!address.IsValid())
606 throw JSONRPCError(-5, "Invalid bitcoin address");
607 scriptPubKey.SetBitcoinAddress(address);
608 if (!IsMine(*pwalletMain,scriptPubKey))
611 // Minimum confirmations
613 if (params.size() > 1)
614 nMinDepth = params[1].get_int();
618 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
620 const CWalletTx& wtx = (*it).second;
621 if (wtx.IsCoinBase() || !wtx.IsFinal())
624 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
625 if (txout.scriptPubKey == scriptPubKey)
626 if (wtx.GetDepthInMainChain() >= nMinDepth)
627 nAmount += txout.nValue;
630 return ValueFromAmount(nAmount);
634 void GetAccountAddresses(string strAccount, set<CBitcoinAddress>& setAddress)
636 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
638 const CBitcoinAddress& address = item.first;
639 const string& strName = item.second;
640 if (strName == strAccount)
641 setAddress.insert(address);
646 Value getreceivedbyaccount(const Array& params, bool fHelp)
648 if (fHelp || params.size() < 1 || params.size() > 2)
650 "getreceivedbyaccount <account> [minconf=1]\n"
651 "Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.");
653 // Minimum confirmations
655 if (params.size() > 1)
656 nMinDepth = params[1].get_int();
658 // Get the set of pub keys that have the label
659 string strAccount = AccountFromValue(params[0]);
660 set<CBitcoinAddress> setAddress;
661 GetAccountAddresses(strAccount, setAddress);
665 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
667 const CWalletTx& wtx = (*it).second;
668 if (wtx.IsCoinBase() || !wtx.IsFinal())
671 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
673 CBitcoinAddress address;
674 if (ExtractAddress(txout.scriptPubKey, pwalletMain, address) && setAddress.count(address))
675 if (wtx.GetDepthInMainChain() >= nMinDepth)
676 nAmount += txout.nValue;
680 return (double)nAmount / (double)COIN;
684 int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth)
688 // Tally wallet transactions
689 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
691 const CWalletTx& wtx = (*it).second;
695 int64 nGenerated, nReceived, nSent, nFee;
696 wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee);
698 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
699 nBalance += nReceived;
700 nBalance += nGenerated - nSent - nFee;
703 // Tally internal accounting entries
704 nBalance += walletdb.GetAccountCreditDebit(strAccount);
709 int64 GetAccountBalance(const string& strAccount, int nMinDepth)
711 CWalletDB walletdb(pwalletMain->strWalletFile);
712 return GetAccountBalance(walletdb, strAccount, nMinDepth);
716 Value getbalance(const Array& params, bool fHelp)
718 if (fHelp || params.size() > 2)
720 "getbalance [account] [minconf=1]\n"
721 "If [account] is not specified, returns the server's total available balance.\n"
722 "If [account] is specified, returns the balance in the account.");
724 if (params.size() == 0)
725 return ValueFromAmount(pwalletMain->GetBalance());
728 if (params.size() > 1)
729 nMinDepth = params[1].get_int();
731 if (params[0].get_str() == "*") {
732 // Calculate total balance a different way from GetBalance()
733 // (GetBalance() sums up all unspent TxOuts)
734 // getbalance and getbalance '*' should always return the same number.
736 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
738 const CWalletTx& wtx = (*it).second;
742 int64 allGeneratedImmature, allGeneratedMature, allFee;
743 allGeneratedImmature = allGeneratedMature = allFee = 0;
744 string strSentAccount;
745 list<pair<CBitcoinAddress, int64> > listReceived;
746 list<pair<CBitcoinAddress, int64> > listSent;
747 wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
748 if (wtx.GetDepthInMainChain() >= nMinDepth)
749 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listReceived)
750 nBalance += r.second;
751 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listSent)
752 nBalance -= r.second;
754 nBalance += allGeneratedMature;
756 return ValueFromAmount(nBalance);
759 string strAccount = AccountFromValue(params[0]);
761 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
763 return ValueFromAmount(nBalance);
767 Value movecmd(const Array& params, bool fHelp)
769 if (fHelp || params.size() < 3 || params.size() > 5)
771 "move <fromaccount> <toaccount> <amount> [minconf=1] [comment]\n"
772 "Move from one account in your wallet to another.");
774 string strFrom = AccountFromValue(params[0]);
775 string strTo = AccountFromValue(params[1]);
776 int64 nAmount = AmountFromValue(params[2]);
777 if (params.size() > 3)
778 // unused parameter, used to be nMinDepth, keep type-checking it though
779 (void)params[3].get_int();
781 if (params.size() > 4)
782 strComment = params[4].get_str();
784 CWalletDB walletdb(pwalletMain->strWalletFile);
787 int64 nNow = GetAdjustedTime();
790 CAccountingEntry debit;
791 debit.strAccount = strFrom;
792 debit.nCreditDebit = -nAmount;
794 debit.strOtherAccount = strTo;
795 debit.strComment = strComment;
796 walletdb.WriteAccountingEntry(debit);
799 CAccountingEntry credit;
800 credit.strAccount = strTo;
801 credit.nCreditDebit = nAmount;
803 credit.strOtherAccount = strFrom;
804 credit.strComment = strComment;
805 walletdb.WriteAccountingEntry(credit);
807 walletdb.TxnCommit();
813 Value sendfrom(const Array& params, bool fHelp)
815 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
817 "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
818 "<amount> is a real and is rounded to the nearest 0.00000001\n"
819 "requires wallet passphrase to be set with walletpassphrase first");
820 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
822 "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
823 "<amount> is a real and is rounded to the nearest 0.00000001");
825 string strAccount = AccountFromValue(params[0]);
826 CBitcoinAddress address(params[1].get_str());
827 if (!address.IsValid())
828 throw JSONRPCError(-5, "Invalid bitcoin address");
829 int64 nAmount = AmountFromValue(params[2]);
831 if (params.size() > 3)
832 nMinDepth = params[3].get_int();
835 wtx.strFromAccount = strAccount;
836 if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
837 wtx.mapValue["comment"] = params[4].get_str();
838 if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
839 wtx.mapValue["to"] = params[5].get_str();
841 if (pwalletMain->IsLocked())
842 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
845 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
846 if (nAmount > nBalance)
847 throw JSONRPCError(-6, "Account has insufficient funds");
850 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
852 throw JSONRPCError(-4, strError);
854 return wtx.GetHash().GetHex();
858 Value sendmany(const Array& params, bool fHelp)
860 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
862 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
863 "amounts are double-precision floating point numbers\n"
864 "requires wallet passphrase to be set with walletpassphrase first");
865 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
867 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
868 "amounts are double-precision floating point numbers");
870 string strAccount = AccountFromValue(params[0]);
871 Object sendTo = params[1].get_obj();
873 if (params.size() > 2)
874 nMinDepth = params[2].get_int();
877 wtx.strFromAccount = strAccount;
878 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
879 wtx.mapValue["comment"] = params[3].get_str();
881 set<CBitcoinAddress> setAddress;
882 vector<pair<CScript, int64> > vecSend;
884 int64 totalAmount = 0;
885 BOOST_FOREACH(const Pair& s, sendTo)
887 CBitcoinAddress address(s.name_);
888 if (!address.IsValid())
889 throw JSONRPCError(-5, string("Invalid bitcoin address:")+s.name_);
891 if (setAddress.count(address))
892 throw JSONRPCError(-8, string("Invalid parameter, duplicated address: ")+s.name_);
893 setAddress.insert(address);
895 CScript scriptPubKey;
896 scriptPubKey.SetBitcoinAddress(address);
897 int64 nAmount = AmountFromValue(s.value_);
898 totalAmount += nAmount;
900 vecSend.push_back(make_pair(scriptPubKey, nAmount));
903 if (pwalletMain->IsLocked())
904 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
907 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
908 if (totalAmount > nBalance)
909 throw JSONRPCError(-6, "Account has insufficient funds");
912 CReserveKey keyChange(pwalletMain);
913 int64 nFeeRequired = 0;
914 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
917 if (totalAmount + nFeeRequired > pwalletMain->GetBalance())
918 throw JSONRPCError(-6, "Insufficient funds");
919 throw JSONRPCError(-4, "Transaction creation failed");
921 if (!pwalletMain->CommitTransaction(wtx, keyChange))
922 throw JSONRPCError(-4, "Transaction commit failed");
924 return wtx.GetHash().GetHex();
939 Value ListReceived(const Array& params, bool fByAccounts)
941 // Minimum confirmations
943 if (params.size() > 0)
944 nMinDepth = params[0].get_int();
946 // Whether to include empty accounts
947 bool fIncludeEmpty = false;
948 if (params.size() > 1)
949 fIncludeEmpty = params[1].get_bool();
952 map<CBitcoinAddress, tallyitem> mapTally;
953 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
955 const CWalletTx& wtx = (*it).second;
956 if (wtx.IsCoinBase() || !wtx.IsFinal())
959 int nDepth = wtx.GetDepthInMainChain();
960 if (nDepth < nMinDepth)
963 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
965 CBitcoinAddress address;
966 if (!ExtractAddress(txout.scriptPubKey, pwalletMain, address) || !address.IsValid())
969 tallyitem& item = mapTally[address];
970 item.nAmount += txout.nValue;
971 item.nConf = min(item.nConf, nDepth);
977 map<string, tallyitem> mapAccountTally;
978 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
980 const CBitcoinAddress& address = item.first;
981 const string& strAccount = item.second;
982 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
983 if (it == mapTally.end() && !fIncludeEmpty)
988 if (it != mapTally.end())
990 nAmount = (*it).second.nAmount;
991 nConf = (*it).second.nConf;
996 tallyitem& item = mapAccountTally[strAccount];
997 item.nAmount += nAmount;
998 item.nConf = min(item.nConf, nConf);
1003 obj.push_back(Pair("address", address.ToString()));
1004 obj.push_back(Pair("account", strAccount));
1005 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1006 obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
1013 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
1015 int64 nAmount = (*it).second.nAmount;
1016 int nConf = (*it).second.nConf;
1018 obj.push_back(Pair("account", (*it).first));
1019 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1020 obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
1028 Value listreceivedbyaddress(const Array& params, bool fHelp)
1030 if (fHelp || params.size() > 2)
1031 throw runtime_error(
1032 "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
1033 "[minconf] is the minimum number of confirmations before payments are included.\n"
1034 "[includeempty] whether to include addresses that haven't received any payments.\n"
1035 "Returns an array of objects containing:\n"
1036 " \"address\" : receiving address\n"
1037 " \"account\" : the account of the receiving address\n"
1038 " \"amount\" : total amount received by the address\n"
1039 " \"confirmations\" : number of confirmations of the most recent transaction included");
1041 return ListReceived(params, false);
1044 Value listreceivedbyaccount(const Array& params, bool fHelp)
1046 if (fHelp || params.size() > 2)
1047 throw runtime_error(
1048 "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
1049 "[minconf] is the minimum number of confirmations before payments are included.\n"
1050 "[includeempty] whether to include accounts that haven't received any payments.\n"
1051 "Returns an array of objects containing:\n"
1052 " \"account\" : the account of the receiving addresses\n"
1053 " \"amount\" : total amount received by addresses with this account\n"
1054 " \"confirmations\" : number of confirmations of the most recent transaction included");
1056 return ListReceived(params, true);
1059 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret)
1061 int64 nGeneratedImmature, nGeneratedMature, nFee;
1062 string strSentAccount;
1063 list<pair<CBitcoinAddress, int64> > listReceived;
1064 list<pair<CBitcoinAddress, int64> > listSent;
1065 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1067 bool fAllAccounts = (strAccount == string("*"));
1069 // Generated blocks assigned to account ""
1070 if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == ""))
1073 entry.push_back(Pair("account", string("")));
1074 if (nGeneratedImmature)
1076 entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
1077 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
1081 entry.push_back(Pair("category", "generate"));
1082 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
1085 WalletTxToJSON(wtx, entry);
1086 ret.push_back(entry);
1090 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1092 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1095 entry.push_back(Pair("account", strSentAccount));
1096 entry.push_back(Pair("address", s.first.ToString()));
1097 entry.push_back(Pair("category", "send"));
1098 entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1099 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1101 WalletTxToJSON(wtx, entry);
1102 ret.push_back(entry);
1107 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1108 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1111 if (pwalletMain->mapAddressBook.count(r.first))
1112 account = pwalletMain->mapAddressBook[r.first];
1113 if (fAllAccounts || (account == strAccount))
1116 entry.push_back(Pair("account", account));
1117 entry.push_back(Pair("address", r.first.ToString()));
1118 entry.push_back(Pair("category", "receive"));
1119 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1121 WalletTxToJSON(wtx, entry);
1122 ret.push_back(entry);
1127 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1129 bool fAllAccounts = (strAccount == string("*"));
1131 if (fAllAccounts || acentry.strAccount == strAccount)
1134 entry.push_back(Pair("account", acentry.strAccount));
1135 entry.push_back(Pair("category", "move"));
1136 entry.push_back(Pair("time", (boost::int64_t)acentry.nTime));
1137 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1138 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1139 entry.push_back(Pair("comment", acentry.strComment));
1140 ret.push_back(entry);
1144 Value listtransactions(const Array& params, bool fHelp)
1146 if (fHelp || params.size() > 3)
1147 throw runtime_error(
1148 "listtransactions [account] [count=10] [from=0]\n"
1149 "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1151 string strAccount = "*";
1152 if (params.size() > 0)
1153 strAccount = params[0].get_str();
1155 if (params.size() > 1)
1156 nCount = params[1].get_int();
1158 if (params.size() > 2)
1159 nFrom = params[2].get_int();
1162 CWalletDB walletdb(pwalletMain->strWalletFile);
1164 // Firs: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap:
1165 typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
1166 typedef multimap<int64, TxPair > TxItems;
1169 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1171 CWalletTx* wtx = &((*it).second);
1172 txByTime.insert(make_pair(wtx->GetTxTime(), TxPair(wtx, (CAccountingEntry*)0)));
1174 list<CAccountingEntry> acentries;
1175 walletdb.ListAccountCreditDebit(strAccount, acentries);
1176 BOOST_FOREACH(CAccountingEntry& entry, acentries)
1178 txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
1181 // Now: iterate backwards until we have nCount items to return:
1182 TxItems::reverse_iterator it = txByTime.rbegin();
1183 if (txByTime.size() > nFrom) std::advance(it, nFrom);
1184 for (; it != txByTime.rend(); ++it)
1186 CWalletTx *const pwtx = (*it).second.first;
1188 ListTransactions(*pwtx, strAccount, 0, true, ret);
1189 CAccountingEntry *const pacentry = (*it).second.second;
1191 AcentryToJSON(*pacentry, strAccount, ret);
1193 if (ret.size() >= nCount) break;
1195 // ret is now newest to oldest
1197 // Make sure we return only last nCount items (sends-to-self might give us an extra):
1198 if (ret.size() > nCount)
1200 Array::iterator last = ret.begin();
1201 std::advance(last, nCount);
1202 ret.erase(last, ret.end());
1204 std::reverse(ret.begin(), ret.end()); // oldest to newest
1209 Value listaccounts(const Array& params, bool fHelp)
1211 if (fHelp || params.size() > 1)
1212 throw runtime_error(
1213 "listaccounts [minconf=1]\n"
1214 "Returns Object that has account names as keys, account balances as values.");
1217 if (params.size() > 0)
1218 nMinDepth = params[0].get_int();
1220 map<string, int64> mapAccountBalances;
1221 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& entry, pwalletMain->mapAddressBook) {
1222 if (pwalletMain->HaveKey(entry.first)) // This address belongs to me
1223 mapAccountBalances[entry.second] = 0;
1226 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1228 const CWalletTx& wtx = (*it).second;
1229 int64 nGeneratedImmature, nGeneratedMature, nFee;
1230 string strSentAccount;
1231 list<pair<CBitcoinAddress, int64> > listReceived;
1232 list<pair<CBitcoinAddress, int64> > listSent;
1233 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1234 mapAccountBalances[strSentAccount] -= nFee;
1235 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1236 mapAccountBalances[strSentAccount] -= s.second;
1237 if (wtx.GetDepthInMainChain() >= nMinDepth)
1239 mapAccountBalances[""] += nGeneratedMature;
1240 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1241 if (pwalletMain->mapAddressBook.count(r.first))
1242 mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1244 mapAccountBalances[""] += r.second;
1248 list<CAccountingEntry> acentries;
1249 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1250 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1251 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1254 BOOST_FOREACH(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) {
1255 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1260 Value gettransaction(const Array& params, bool fHelp)
1262 if (fHelp || params.size() != 1)
1263 throw runtime_error(
1264 "gettransaction <txid>\n"
1265 "Get detailed information about <txid>");
1268 hash.SetHex(params[0].get_str());
1272 if (!pwalletMain->mapWallet.count(hash))
1273 throw JSONRPCError(-5, "Invalid or non-wallet transaction id");
1274 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1276 int64 nCredit = wtx.GetCredit();
1277 int64 nDebit = wtx.GetDebit();
1278 int64 nNet = nCredit - nDebit;
1279 int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
1281 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1283 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1285 WalletTxToJSON(pwalletMain->mapWallet[hash], entry);
1288 ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
1289 entry.push_back(Pair("details", details));
1295 Value backupwallet(const Array& params, bool fHelp)
1297 if (fHelp || params.size() != 1)
1298 throw runtime_error(
1299 "backupwallet <destination>\n"
1300 "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1302 string strDest = params[0].get_str();
1303 BackupWallet(*pwalletMain, strDest);
1309 Value keypoolrefill(const Array& params, bool fHelp)
1311 if (pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1312 throw runtime_error(
1314 "Fills the keypool, requires wallet passphrase to be set.");
1315 if (!pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1316 throw runtime_error(
1318 "Fills the keypool.");
1320 if (pwalletMain->IsLocked())
1321 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
1323 pwalletMain->TopUpKeyPool();
1325 if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100))
1326 throw JSONRPCError(-4, "Error refreshing keypool.");
1332 void ThreadTopUpKeyPool(void* parg)
1334 pwalletMain->TopUpKeyPool();
1337 void ThreadCleanWalletPassphrase(void* parg)
1339 int64 nMyWakeTime = GetTime() + *((int*)parg);
1341 if (nWalletUnlockTime == 0)
1343 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1345 nWalletUnlockTime = nMyWakeTime;
1348 while (GetTime() < nWalletUnlockTime)
1349 Sleep(GetTime() - nWalletUnlockTime);
1351 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1353 nWalletUnlockTime = 0;
1358 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1360 if (nWalletUnlockTime < nMyWakeTime)
1361 nWalletUnlockTime = nMyWakeTime;
1367 pwalletMain->Lock();
1372 Value walletpassphrase(const Array& params, bool fHelp)
1374 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1375 throw runtime_error(
1376 "walletpassphrase <passphrase> <timeout>\n"
1377 "Stores the wallet decryption key in memory for <timeout> seconds.");
1380 if (!pwalletMain->IsCrypted())
1381 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1383 if (!pwalletMain->IsLocked())
1384 throw JSONRPCError(-17, "Error: Wallet is already unlocked.");
1386 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1387 string strWalletPass;
1388 strWalletPass.reserve(100);
1389 mlock(&strWalletPass[0], strWalletPass.capacity());
1390 strWalletPass = params[0].get_str();
1392 if (strWalletPass.length() > 0)
1394 if (!pwalletMain->Unlock(strWalletPass))
1396 fill(strWalletPass.begin(), strWalletPass.end(), '\0');
1397 munlock(&strWalletPass[0], strWalletPass.capacity());
1398 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1400 fill(strWalletPass.begin(), strWalletPass.end(), '\0');
1401 munlock(&strWalletPass[0], strWalletPass.capacity());
1404 throw runtime_error(
1405 "walletpassphrase <passphrase> <timeout>\n"
1406 "Stores the wallet decryption key in memory for <timeout> seconds.");
1408 CreateThread(ThreadTopUpKeyPool, NULL);
1409 int* pnSleepTime = new int(params[1].get_int());
1410 CreateThread(ThreadCleanWalletPassphrase, pnSleepTime);
1416 Value walletpassphrasechange(const Array& params, bool fHelp)
1418 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1419 throw runtime_error(
1420 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1421 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1424 if (!pwalletMain->IsCrypted())
1425 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1427 string strOldWalletPass;
1428 strOldWalletPass.reserve(100);
1429 mlock(&strOldWalletPass[0], strOldWalletPass.capacity());
1430 strOldWalletPass = params[0].get_str();
1432 string strNewWalletPass;
1433 strNewWalletPass.reserve(100);
1434 mlock(&strNewWalletPass[0], strNewWalletPass.capacity());
1435 strNewWalletPass = params[1].get_str();
1437 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1438 throw runtime_error(
1439 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1440 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1442 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1444 fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0');
1445 fill(strNewWalletPass.begin(), strNewWalletPass.end(), '\0');
1446 munlock(&strOldWalletPass[0], strOldWalletPass.capacity());
1447 munlock(&strNewWalletPass[0], strNewWalletPass.capacity());
1448 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1450 fill(strNewWalletPass.begin(), strNewWalletPass.end(), '\0');
1451 fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0');
1452 munlock(&strOldWalletPass[0], strOldWalletPass.capacity());
1453 munlock(&strNewWalletPass[0], strNewWalletPass.capacity());
1459 Value walletlock(const Array& params, bool fHelp)
1461 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1462 throw runtime_error(
1464 "Removes the wallet encryption key from memory, locking the wallet.\n"
1465 "After calling this method, you will need to call walletpassphrase again\n"
1466 "before being able to call any methods which require the wallet to be unlocked.");
1469 if (!pwalletMain->IsCrypted())
1470 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called.");
1472 pwalletMain->Lock();
1473 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1475 nWalletUnlockTime = 0;
1482 Value encryptwallet(const Array& params, bool fHelp)
1484 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1485 throw runtime_error(
1486 "encryptwallet <passphrase>\n"
1487 "Encrypts the wallet with <passphrase>.");
1490 if (pwalletMain->IsCrypted())
1491 throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
1493 string strWalletPass;
1494 strWalletPass.reserve(100);
1495 mlock(&strWalletPass[0], strWalletPass.capacity());
1496 strWalletPass = params[0].get_str();
1498 if (strWalletPass.length() < 1)
1499 throw runtime_error(
1500 "encryptwallet <passphrase>\n"
1501 "Encrypts the wallet with <passphrase>.");
1503 if (!pwalletMain->EncryptWallet(strWalletPass))
1505 fill(strWalletPass.begin(), strWalletPass.end(), '\0');
1506 munlock(&strWalletPass[0], strWalletPass.capacity());
1507 throw JSONRPCError(-16, "Error: Failed to encrypt the wallet.");
1509 fill(strWalletPass.begin(), strWalletPass.end(), '\0');
1510 munlock(&strWalletPass[0], strWalletPass.capacity());
1516 Value validateaddress(const Array& params, bool fHelp)
1518 if (fHelp || params.size() != 1)
1519 throw runtime_error(
1520 "validateaddress <bitcoinaddress>\n"
1521 "Return information about <bitcoinaddress>.");
1523 CBitcoinAddress address(params[0].get_str());
1524 bool isValid = address.IsValid();
1527 ret.push_back(Pair("isvalid", isValid));
1530 // Call Hash160ToAddress() so we always return current ADDRESSVERSION
1531 // version of the address:
1532 string currentAddress = address.ToString();
1533 ret.push_back(Pair("address", currentAddress));
1534 ret.push_back(Pair("ismine", (pwalletMain->HaveKey(address) > 0)));
1535 if (pwalletMain->mapAddressBook.count(address))
1536 ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
1542 Value getwork(const Array& params, bool fHelp)
1544 if (fHelp || params.size() > 1)
1545 throw runtime_error(
1547 "If [data] is not specified, returns formatted hash data to work on:\n"
1548 " \"midstate\" : precomputed hash state after hashing the first half of the data (DEPRECATED)\n" // deprecated
1549 " \"data\" : block data\n"
1550 " \"hash1\" : formatted hash buffer for second hash (DEPRECATED)\n" // deprecated
1551 " \"target\" : little endian hash target\n"
1552 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1555 throw JSONRPCError(-9, "Bitcoin is not connected!");
1557 if (IsInitialBlockDownload())
1558 throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
1560 typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
1561 static mapNewBlock_t mapNewBlock;
1562 static vector<CBlock*> vNewBlock;
1563 static CReserveKey reservekey(pwalletMain);
1565 if (params.size() == 0)
1568 static unsigned int nTransactionsUpdatedLast;
1569 static CBlockIndex* pindexPrev;
1570 static int64 nStart;
1571 static CBlock* pblock;
1572 if (pindexPrev != pindexBest ||
1573 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
1575 if (pindexPrev != pindexBest)
1577 // Deallocate old blocks since they're obsolete now
1578 mapNewBlock.clear();
1579 BOOST_FOREACH(CBlock* pblock, vNewBlock)
1583 nTransactionsUpdatedLast = nTransactionsUpdated;
1584 pindexPrev = pindexBest;
1588 pblock = CreateNewBlock(reservekey);
1590 throw JSONRPCError(-7, "Out of memory");
1591 vNewBlock.push_back(pblock);
1595 pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
1598 // Update nExtraNonce
1599 static unsigned int nExtraNonce = 0;
1600 IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
1603 mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
1605 // Prebuild hash buffers
1609 FormatHashBuffers(pblock, pmidstate, pdata, phash1);
1611 uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
1614 result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate)))); // deprecated
1615 result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata))));
1616 result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1)))); // deprecated
1617 result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
1623 vector<unsigned char> vchData = ParseHex(params[0].get_str());
1624 if (vchData.size() != 128)
1625 throw JSONRPCError(-8, "Invalid parameter");
1626 CBlock* pdata = (CBlock*)&vchData[0];
1629 for (int i = 0; i < 128/4; i++)
1630 ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]);
1633 if (!mapNewBlock.count(pdata->hashMerkleRoot))
1635 CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
1637 pblock->nTime = pdata->nTime;
1638 pblock->nNonce = pdata->nNonce;
1639 pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
1640 pblock->hashMerkleRoot = pblock->BuildMerkleTree();
1642 return CheckWork(pblock, *pwalletMain, reservekey);
1660 pair<string, rpcfn_type> pCallTable[] =
1662 make_pair("help", &help),
1663 make_pair("stop", &stop),
1664 make_pair("getblockcount", &getblockcount),
1665 make_pair("getblocknumber", &getblocknumber),
1666 make_pair("getconnectioncount", &getconnectioncount),
1667 make_pair("getdifficulty", &getdifficulty),
1668 make_pair("getgenerate", &getgenerate),
1669 make_pair("setgenerate", &setgenerate),
1670 make_pair("gethashespersec", &gethashespersec),
1671 make_pair("getinfo", &getinfo),
1672 make_pair("getnewaddress", &getnewaddress),
1673 make_pair("getaccountaddress", &getaccountaddress),
1674 make_pair("setaccount", &setaccount),
1675 make_pair("getaccount", &getaccount),
1676 make_pair("getaddressesbyaccount", &getaddressesbyaccount),
1677 make_pair("sendtoaddress", &sendtoaddress),
1678 make_pair("getreceivedbyaddress", &getreceivedbyaddress),
1679 make_pair("getreceivedbyaccount", &getreceivedbyaccount),
1680 make_pair("listreceivedbyaddress", &listreceivedbyaddress),
1681 make_pair("listreceivedbyaccount", &listreceivedbyaccount),
1682 make_pair("backupwallet", &backupwallet),
1683 make_pair("keypoolrefill", &keypoolrefill),
1684 make_pair("walletpassphrase", &walletpassphrase),
1685 make_pair("walletpassphrasechange", &walletpassphrasechange),
1686 make_pair("walletlock", &walletlock),
1687 make_pair("encryptwallet", &encryptwallet),
1688 make_pair("validateaddress", &validateaddress),
1689 make_pair("getbalance", &getbalance),
1690 make_pair("move", &movecmd),
1691 make_pair("sendfrom", &sendfrom),
1692 make_pair("sendmany", &sendmany),
1693 make_pair("gettransaction", &gettransaction),
1694 make_pair("listtransactions", &listtransactions),
1695 make_pair("signmessage", &signmessage),
1696 make_pair("verifymessage", &verifymessage),
1697 make_pair("getwork", &getwork),
1698 make_pair("listaccounts", &listaccounts),
1699 make_pair("settxfee", &settxfee),
1701 map<string, rpcfn_type> mapCallTable(pCallTable, pCallTable + sizeof(pCallTable)/sizeof(pCallTable[0]));
1703 string pAllowInSafeMode[] =
1709 "getconnectioncount",
1716 "getaccountaddress",
1718 "getaddressesbyaccount",
1726 set<string> setAllowInSafeMode(pAllowInSafeMode, pAllowInSafeMode + sizeof(pAllowInSafeMode)/sizeof(pAllowInSafeMode[0]));
1734 // This ain't Apache. We're just using HTTP header for the length field
1735 // and to be compatible with other JSON-RPC implementations.
1738 string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
1741 s << "POST / HTTP/1.1\r\n"
1742 << "User-Agent: bitcoin-json-rpc/" << FormatFullVersion() << "\r\n"
1743 << "Host: 127.0.0.1\r\n"
1744 << "Content-Type: application/json\r\n"
1745 << "Content-Length: " << strMsg.size() << "\r\n"
1746 << "Accept: application/json\r\n";
1747 BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
1748 s << item.first << ": " << item.second << "\r\n";
1749 s << "\r\n" << strMsg;
1754 string rfc1123Time()
1759 struct tm* now_gmt = gmtime(&now);
1760 string locale(setlocale(LC_TIME, NULL));
1761 setlocale(LC_TIME, "C"); // we want posix (aka "C") weekday/month strings
1762 strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt);
1763 setlocale(LC_TIME, locale.c_str());
1764 return string(buffer);
1767 static string HTTPReply(int nStatus, const string& strMsg)
1770 return strprintf("HTTP/1.0 401 Authorization Required\r\n"
1772 "Server: bitcoin-json-rpc/%s\r\n"
1773 "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
1774 "Content-Type: text/html\r\n"
1775 "Content-Length: 296\r\n"
1777 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
1778 "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
1781 "<TITLE>Error</TITLE>\r\n"
1782 "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
1784 "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
1785 "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
1787 if (nStatus == 200) strStatus = "OK";
1788 else if (nStatus == 400) strStatus = "Bad Request";
1789 else if (nStatus == 403) strStatus = "Forbidden";
1790 else if (nStatus == 404) strStatus = "Not Found";
1791 else if (nStatus == 500) strStatus = "Internal Server Error";
1793 "HTTP/1.1 %d %s\r\n"
1795 "Connection: close\r\n"
1796 "Content-Length: %d\r\n"
1797 "Content-Type: application/json\r\n"
1798 "Server: bitcoin-json-rpc/%s\r\n"
1803 rfc1123Time().c_str(),
1805 FormatFullVersion().c_str(),
1809 int ReadHTTPStatus(std::basic_istream<char>& stream)
1812 getline(stream, str);
1813 vector<string> vWords;
1814 boost::split(vWords, str, boost::is_any_of(" "));
1815 if (vWords.size() < 2)
1817 return atoi(vWords[1].c_str());
1820 int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
1826 std::getline(stream, str);
1827 if (str.empty() || str == "\r")
1829 string::size_type nColon = str.find(":");
1830 if (nColon != string::npos)
1832 string strHeader = str.substr(0, nColon);
1833 boost::trim(strHeader);
1834 boost::to_lower(strHeader);
1835 string strValue = str.substr(nColon+1);
1836 boost::trim(strValue);
1837 mapHeadersRet[strHeader] = strValue;
1838 if (strHeader == "content-length")
1839 nLen = atoi(strValue.c_str());
1845 int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
1847 mapHeadersRet.clear();
1851 int nStatus = ReadHTTPStatus(stream);
1854 int nLen = ReadHTTPHeader(stream, mapHeadersRet);
1855 if (nLen < 0 || nLen > MAX_SIZE)
1861 vector<char> vch(nLen);
1862 stream.read(&vch[0], nLen);
1863 strMessageRet = string(vch.begin(), vch.end());
1869 bool HTTPAuthorized(map<string, string>& mapHeaders)
1871 string strAuth = mapHeaders["authorization"];
1872 if (strAuth.substr(0,6) != "Basic ")
1874 string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
1875 string strUserPass = DecodeBase64(strUserPass64);
1876 string::size_type nColon = strUserPass.find(":");
1877 if (nColon == string::npos)
1879 string strUser = strUserPass.substr(0, nColon);
1880 string strPassword = strUserPass.substr(nColon+1);
1881 return (strUser == mapArgs["-rpcuser"] && strPassword == mapArgs["-rpcpassword"]);
1885 // JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
1886 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
1887 // unspecified (HTTP errors and contents of 'error').
1889 // 1.0 spec: http://json-rpc.org/wiki/specification
1890 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
1891 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
1894 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
1897 request.push_back(Pair("method", strMethod));
1898 request.push_back(Pair("params", params));
1899 request.push_back(Pair("id", id));
1900 return write_string(Value(request), false) + "\n";
1903 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
1906 if (error.type() != null_type)
1907 reply.push_back(Pair("result", Value::null));
1909 reply.push_back(Pair("result", result));
1910 reply.push_back(Pair("error", error));
1911 reply.push_back(Pair("id", id));
1912 return write_string(Value(reply), false) + "\n";
1915 void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
1917 // Send error reply from json-rpc error object
1919 int code = find_value(objError, "code").get_int();
1920 if (code == -32600) nStatus = 400;
1921 else if (code == -32601) nStatus = 404;
1922 string strReply = JSONRPCReply(Value::null, objError, id);
1923 stream << HTTPReply(nStatus, strReply) << std::flush;
1926 bool ClientAllowed(const string& strAddress)
1928 if (strAddress == asio::ip::address_v4::loopback().to_string())
1930 const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
1931 BOOST_FOREACH(string strAllow, vAllow)
1932 if (WildcardMatch(strAddress, strAllow))
1939 // IOStream device that speaks SSL but can also speak non-SSL
1941 class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
1943 SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
1945 fUseSSL = fUseSSLIn;
1946 fNeedHandshake = fUseSSLIn;
1949 void handshake(ssl::stream_base::handshake_type role)
1951 if (!fNeedHandshake) return;
1952 fNeedHandshake = false;
1953 stream.handshake(role);
1955 std::streamsize read(char* s, std::streamsize n)
1957 handshake(ssl::stream_base::server); // HTTPS servers read first
1958 if (fUseSSL) return stream.read_some(asio::buffer(s, n));
1959 return stream.next_layer().read_some(asio::buffer(s, n));
1961 std::streamsize write(const char* s, std::streamsize n)
1963 handshake(ssl::stream_base::client); // HTTPS clients write first
1964 if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
1965 return asio::write(stream.next_layer(), asio::buffer(s, n));
1967 bool connect(const std::string& server, const std::string& port)
1969 ip::tcp::resolver resolver(stream.get_io_service());
1970 ip::tcp::resolver::query query(server.c_str(), port.c_str());
1971 ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
1972 ip::tcp::resolver::iterator end;
1973 boost::system::error_code error = asio::error::host_not_found;
1974 while (error && endpoint_iterator != end)
1976 stream.lowest_layer().close();
1977 stream.lowest_layer().connect(*endpoint_iterator++, error);
1985 bool fNeedHandshake;
1991 void ThreadRPCServer(void* parg)
1993 IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
1996 vnThreadsRunning[4]++;
1997 ThreadRPCServer2(parg);
1998 vnThreadsRunning[4]--;
2000 catch (std::exception& e) {
2001 vnThreadsRunning[4]--;
2002 PrintException(&e, "ThreadRPCServer()");
2004 vnThreadsRunning[4]--;
2005 PrintException(NULL, "ThreadRPCServer()");
2007 printf("ThreadRPCServer exiting\n");
2010 void ThreadRPCServer2(void* parg)
2012 printf("ThreadRPCServer started\n");
2014 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2016 string strWhatAmI = "To use bitcoind";
2017 if (mapArgs.count("-server"))
2018 strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
2019 else if (mapArgs.count("-daemon"))
2020 strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
2022 _("Warning: %s, you must set rpcpassword=<password>\nin the configuration file: %s\n"
2023 "If the file does not exist, create it with owner-readable-only file permissions.\n"),
2025 GetConfigFile().c_str());
2026 CreateThread(Shutdown, NULL);
2030 bool fUseSSL = GetBoolArg("-rpcssl");
2031 asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
2033 asio::io_service io_service;
2034 ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", 8332));
2035 ip::tcp::acceptor acceptor(io_service, endpoint);
2037 acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
2040 ssl::context context(io_service, ssl::context::sslv23);
2043 context.set_options(ssl::context::no_sslv2);
2044 filesystem::path certfile = GetArg("-rpcsslcertificatechainfile", "server.cert");
2045 if (!certfile.is_complete()) certfile = filesystem::path(GetDataDir()) / certfile;
2046 if (filesystem::exists(certfile)) context.use_certificate_chain_file(certfile.string().c_str());
2047 else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", certfile.string().c_str());
2048 filesystem::path pkfile = GetArg("-rpcsslprivatekeyfile", "server.pem");
2049 if (!pkfile.is_complete()) pkfile = filesystem::path(GetDataDir()) / pkfile;
2050 if (filesystem::exists(pkfile)) context.use_private_key_file(pkfile.string().c_str(), ssl::context::pem);
2051 else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pkfile.string().c_str());
2053 string ciphers = GetArg("-rpcsslciphers",
2054 "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
2055 SSL_CTX_set_cipher_list(context.impl(), ciphers.c_str());
2059 throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
2064 // Accept connection
2066 SSLStream sslStream(io_service, context);
2067 SSLIOStreamDevice d(sslStream, fUseSSL);
2068 iostreams::stream<SSLIOStreamDevice> stream(d);
2070 ip::tcp::iostream stream;
2073 ip::tcp::endpoint peer;
2074 vnThreadsRunning[4]--;
2076 acceptor.accept(sslStream.lowest_layer(), peer);
2078 acceptor.accept(*stream.rdbuf(), peer);
2080 vnThreadsRunning[4]++;
2084 // Restrict callers by IP
2085 if (!ClientAllowed(peer.address().to_string()))
2087 // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
2089 stream << HTTPReply(403, "") << std::flush;
2093 map<string, string> mapHeaders;
2096 boost::thread api_caller(ReadHTTP, boost::ref(stream), boost::ref(mapHeaders), boost::ref(strRequest));
2097 if (!api_caller.timed_join(boost::posix_time::seconds(GetArg("-rpctimeout", 30))))
2100 printf("ThreadRPCServer ReadHTTP timeout\n");
2104 // Check authorization
2105 if (mapHeaders.count("authorization") == 0)
2107 stream << HTTPReply(401, "") << std::flush;
2110 if (!HTTPAuthorized(mapHeaders))
2112 // Deter brute-forcing short passwords
2113 if (mapArgs["-rpcpassword"].size() < 15)
2116 stream << HTTPReply(401, "") << std::flush;
2117 printf("ThreadRPCServer incorrect password attempt\n");
2121 Value id = Value::null;
2126 if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
2127 throw JSONRPCError(-32700, "Parse error");
2128 const Object& request = valRequest.get_obj();
2130 // Parse id now so errors from here on will have the id
2131 id = find_value(request, "id");
2134 Value valMethod = find_value(request, "method");
2135 if (valMethod.type() == null_type)
2136 throw JSONRPCError(-32600, "Missing method");
2137 if (valMethod.type() != str_type)
2138 throw JSONRPCError(-32600, "Method must be a string");
2139 string strMethod = valMethod.get_str();
2140 if (strMethod != "getwork")
2141 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
2144 Value valParams = find_value(request, "params");
2146 if (valParams.type() == array_type)
2147 params = valParams.get_array();
2148 else if (valParams.type() == null_type)
2151 throw JSONRPCError(-32600, "Params must be an array");
2154 map<string, rpcfn_type>::iterator mi = mapCallTable.find(strMethod);
2155 if (mi == mapCallTable.end())
2156 throw JSONRPCError(-32601, "Method not found");
2158 // Observe safe mode
2159 string strWarning = GetWarnings("rpc");
2160 if (strWarning != "" && !GetBoolArg("-disablesafemode") && !setAllowInSafeMode.count(strMethod))
2161 throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
2167 CRITICAL_BLOCK(cs_main)
2168 CRITICAL_BLOCK(pwalletMain->cs_wallet)
2169 result = (*(*mi).second)(params, false);
2172 string strReply = JSONRPCReply(result, Value::null, id);
2173 stream << HTTPReply(200, strReply) << std::flush;
2175 catch (std::exception& e)
2177 ErrorReply(stream, JSONRPCError(-1, e.what()), id);
2180 catch (Object& objError)
2182 ErrorReply(stream, objError, id);
2184 catch (std::exception& e)
2186 ErrorReply(stream, JSONRPCError(-32700, e.what()), id);
2194 Object CallRPC(const string& strMethod, const Array& params)
2196 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2197 throw runtime_error(strprintf(
2198 _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
2199 "If the file does not exist, create it with owner-readable-only file permissions."),
2200 GetConfigFile().c_str()));
2202 // Connect to localhost
2203 bool fUseSSL = GetBoolArg("-rpcssl");
2205 asio::io_service io_service;
2206 ssl::context context(io_service, ssl::context::sslv23);
2207 context.set_options(ssl::context::no_sslv2);
2208 SSLStream sslStream(io_service, context);
2209 SSLIOStreamDevice d(sslStream, fUseSSL);
2210 iostreams::stream<SSLIOStreamDevice> stream(d);
2211 if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332")))
2212 throw runtime_error("couldn't connect to server");
2215 throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
2217 ip::tcp::iostream stream(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332"));
2219 throw runtime_error("couldn't connect to server");
2223 // HTTP basic authentication
2224 string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
2225 map<string, string> mapRequestHeaders;
2226 mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
2229 string strRequest = JSONRPCRequest(strMethod, params, 1);
2230 string strPost = HTTPPost(strRequest, mapRequestHeaders);
2231 stream << strPost << std::flush;
2234 map<string, string> mapHeaders;
2236 int nStatus = ReadHTTP(stream, mapHeaders, strReply);
2238 throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
2239 else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
2240 throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
2241 else if (strReply.empty())
2242 throw runtime_error("no response from server");
2246 if (!read_string(strReply, valReply))
2247 throw runtime_error("couldn't parse reply from server");
2248 const Object& reply = valReply.get_obj();
2250 throw runtime_error("expected reply to have result, error and id properties");
2258 template<typename T>
2259 void ConvertTo(Value& value)
2261 if (value.type() == str_type)
2263 // reinterpret string as unquoted json value
2265 if (!read_string(value.get_str(), value2))
2266 throw runtime_error("type mismatch");
2267 value = value2.get_value<T>();
2271 value = value.get_value<T>();
2275 int CommandLineRPC(int argc, char *argv[])
2282 while (argc > 1 && IsSwitchChar(argv[1][0]))
2290 throw runtime_error("too few parameters");
2291 string strMethod = argv[1];
2293 // Parameters default to strings
2295 for (int i = 2; i < argc; i++)
2296 params.push_back(argv[i]);
2297 int n = params.size();
2300 // Special case non-string parameter types
2302 if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
2303 if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2304 if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
2305 if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]);
2306 if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2307 if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2308 if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2309 if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
2310 if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2311 if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
2312 if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2313 if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]);
2314 if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2315 if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]);
2316 if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2317 if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2318 if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2319 if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2320 if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2321 if (strMethod == "sendmany" && n > 1)
2323 string s = params[1].get_str();
2325 if (!read_string(s, v) || v.type() != obj_type)
2326 throw runtime_error("type mismatch");
2327 params[1] = v.get_obj();
2329 if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2332 Object reply = CallRPC(strMethod, params);
2335 const Value& result = find_value(reply, "result");
2336 const Value& error = find_value(reply, "error");
2338 if (error.type() != null_type)
2341 strPrint = "error: " + write_string(error, false);
2342 int code = find_value(error.get_obj(), "code").get_int();
2348 if (result.type() == null_type)
2350 else if (result.type() == str_type)
2351 strPrint = result.get_str();
2353 strPrint = write_string(result, true);
2356 catch (std::exception& e)
2358 strPrint = string("error: ") + e.what();
2363 PrintException(NULL, "CommandLineRPC()");
2368 fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
2377 int main(int argc, char *argv[])
2380 // Turn off microsoft heap dump noise
2381 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
2382 _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
2384 setbuf(stdin, NULL);
2385 setbuf(stdout, NULL);
2386 setbuf(stderr, NULL);
2390 if (argc >= 2 && string(argv[1]) == "-server")
2392 printf("server ready\n");
2393 ThreadRPCServer(NULL);
2397 return CommandLineRPC(argc, argv);
2400 catch (std::exception& e) {
2401 PrintException(&e, "main()");
2403 PrintException(NULL, "main()");