1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Copyright (c) 2011 The Bitcoin developers
3 // Distributed under the MIT/X11 software license, see the accompanying
4 // file license.txt or http://www.opensource.org/licenses/mit-license.php.
7 #include "cryptopp/sha.h"
12 #include <boost/asio.hpp>
13 #include <boost/iostreams/concepts.hpp>
14 #include <boost/iostreams/stream.hpp>
15 #include <boost/algorithm/string.hpp>
17 #include <boost/asio/ssl.hpp>
18 #include <boost/filesystem.hpp>
19 #include <boost/filesystem/fstream.hpp>
20 typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> SSLStream;
22 #include "json/json_spirit_reader_template.h"
23 #include "json/json_spirit_writer_template.h"
24 #include "json/json_spirit_utils.h"
25 #define printf OutputDebugStringF
26 // MinGW 3.4.5 gets "fatal error: had to relocate PCH" if the json headers are
27 // precompiled in headers.h. The problem might be when the pch file goes over
28 // a certain size around 145MB. If we need access to json_spirit outside this
29 // file, we could use the compiled json_spirit option.
32 using namespace boost;
33 using namespace boost::asio;
34 using namespace json_spirit;
36 void ThreadRPCServer2(void* parg);
37 typedef Value(*rpcfn_type)(const Array& params, bool fHelp);
38 extern map<string, rpcfn_type> mapCallTable;
40 static int64 nWalletUnlockTime;
41 static CCriticalSection cs_nWalletUnlockTime;
44 Object JSONRPCError(int code, const string& message)
47 error.push_back(Pair("code", code));
48 error.push_back(Pair("message", message));
53 void PrintConsole(const std::string &format, ...)
56 int limit = sizeof(buffer);
58 va_start(arg_ptr, format);
59 int ret = _vsnprintf(buffer, limit, format.c_str(), arg_ptr);
61 if (ret < 0 || ret >= limit)
67 fprintf(stdout, "%s", buffer);
71 int64 AmountFromValue(const Value& value)
73 double dAmount = value.get_real();
74 if (dAmount <= 0.0 || dAmount > 21000000.0)
75 throw JSONRPCError(-3, "Invalid amount");
76 int64 nAmount = roundint64(dAmount * COIN);
77 if (!MoneyRange(nAmount))
78 throw JSONRPCError(-3, "Invalid amount");
82 Value ValueFromAmount(int64 amount)
84 return (double)amount / (double)COIN;
87 void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
89 entry.push_back(Pair("confirmations", wtx.GetDepthInMainChain()));
90 entry.push_back(Pair("txid", wtx.GetHash().GetHex()));
91 entry.push_back(Pair("time", (boost::int64_t)wtx.GetTxTime()));
92 BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
93 entry.push_back(Pair(item.first, item.second));
96 string AccountFromValue(const Value& value)
98 string strAccount = value.get_str();
99 if (strAccount == "*")
100 throw JSONRPCError(-11, "Invalid account name");
107 /// Note: This interface may still be subject to change.
111 Value help(const Array& params, bool fHelp)
113 if (fHelp || params.size() > 1)
116 "List commands, or get help for a command.");
119 if (params.size() > 0)
120 strCommand = params[0].get_str();
123 set<rpcfn_type> setDone;
124 for (map<string, rpcfn_type>::iterator mi = mapCallTable.begin(); mi != mapCallTable.end(); ++mi)
126 string strMethod = (*mi).first;
127 // We already filter duplicates, but these deprecated screw up the sort order
128 if (strMethod == "getamountreceived" ||
129 strMethod == "getallreceived" ||
130 (strMethod.find("label") != string::npos))
132 if (strCommand != "" && strMethod != strCommand)
137 rpcfn_type pfn = (*mi).second;
138 if (setDone.insert(pfn).second)
139 (*pfn)(params, true);
141 catch (std::exception& e)
143 // Help text is returned in an exception
144 string strHelp = string(e.what());
145 if (strCommand == "")
146 if (strHelp.find('\n') != -1)
147 strHelp = strHelp.substr(0, strHelp.find('\n'));
148 strRet += strHelp + "\n";
152 strRet = strprintf("help: unknown command: %s\n", strCommand.c_str());
153 strRet = strRet.substr(0,strRet.size()-1);
158 Value stop(const Array& params, bool fHelp)
160 if (fHelp || params.size() != 0)
163 "Stop bitcoin server.");
165 // Shutdown will take long enough that the response should get back
166 CreateThread(Shutdown, NULL);
167 return "bitcoin server stopping";
171 Value getblockcount(const Array& params, bool fHelp)
173 if (fHelp || params.size() != 0)
176 "Returns the number of blocks in the longest block chain.");
182 Value getblocknumber(const Array& params, bool fHelp)
184 if (fHelp || params.size() != 0)
187 "Returns the block number of the latest block in the longest block chain.");
193 Value getconnectioncount(const Array& params, bool fHelp)
195 if (fHelp || params.size() != 0)
197 "getconnectioncount\n"
198 "Returns the number of connections to other nodes.");
200 return (int)vNodes.size();
204 double GetDifficulty()
206 // Floating point number that is a multiple of the minimum difficulty,
207 // minimum difficulty = 1.0.
209 if (pindexBest == NULL)
211 int nShift = (pindexBest->nBits >> 24) & 0xff;
214 (double)0x0000ffff / (double)(pindexBest->nBits & 0x00ffffff);
230 Value getdifficulty(const Array& params, bool fHelp)
232 if (fHelp || params.size() != 0)
235 "Returns the proof-of-work difficulty as a multiple of the minimum difficulty.");
237 return GetDifficulty();
241 Value getgenerate(const Array& params, bool fHelp)
243 if (fHelp || params.size() != 0)
246 "Returns true or false.");
248 return (bool)fGenerateBitcoins;
252 Value setgenerate(const Array& params, bool fHelp)
254 if (fHelp || params.size() < 1 || params.size() > 2)
256 "setgenerate <generate> [genproclimit]\n"
257 "<generate> is true or false to turn generation on or off.\n"
258 "Generation is limited to [genproclimit] processors, -1 is unlimited.");
260 bool fGenerate = true;
261 if (params.size() > 0)
262 fGenerate = params[0].get_bool();
264 if (params.size() > 1)
266 int nGenProcLimit = params[1].get_int();
267 fLimitProcessors = (nGenProcLimit != -1);
268 WriteSetting("fLimitProcessors", fLimitProcessors);
269 if (nGenProcLimit != -1)
270 WriteSetting("nLimitProcessors", nLimitProcessors = nGenProcLimit);
271 if (nGenProcLimit == 0)
275 GenerateBitcoins(fGenerate, pwalletMain);
280 Value gethashespersec(const Array& params, bool fHelp)
282 if (fHelp || params.size() != 0)
285 "Returns a recent hashes per second performance measurement while generating.");
287 if (GetTimeMillis() - nHPSTimerStart > 8000)
288 return (boost::int64_t)0;
289 return (boost::int64_t)dHashesPerSec;
293 Value getinfo(const Array& params, bool fHelp)
295 if (fHelp || params.size() != 0)
298 "Returns an object containing various state info.");
301 obj.push_back(Pair("version", (int)VERSION));
302 obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
303 obj.push_back(Pair("blocks", (int)nBestHeight));
304 obj.push_back(Pair("connections", (int)vNodes.size()));
305 obj.push_back(Pair("proxy", (fUseProxy ? addrProxy.ToStringIPPort() : string())));
306 obj.push_back(Pair("generate", (bool)fGenerateBitcoins));
307 obj.push_back(Pair("genproclimit", (int)(fLimitProcessors ? nLimitProcessors : -1)));
308 obj.push_back(Pair("difficulty", (double)GetDifficulty()));
309 obj.push_back(Pair("hashespersec", gethashespersec(params, false)));
310 obj.push_back(Pair("testnet", fTestNet));
311 obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));
312 obj.push_back(Pair("keypoolsize", pwalletMain->GetKeyPoolSize()));
313 obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee)));
314 if (pwalletMain->IsCrypted())
315 obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime));
316 obj.push_back(Pair("errors", GetWarnings("statusbar")));
321 Value getnewaddress(const Array& params, bool fHelp)
323 if (fHelp || params.size() > 1)
325 "getnewaddress [account]\n"
326 "Returns a new bitcoin address for receiving payments. "
327 "If [account] is specified (recommended), it is added to the address book "
328 "so payments received with the address will be credited to [account].");
330 // Parse the account first so we don't generate a key if there's an error
332 if (params.size() > 0)
333 strAccount = AccountFromValue(params[0]);
335 if (!pwalletMain->IsLocked())
336 pwalletMain->TopUpKeyPool();
338 // Generate a new key that is added to wallet
339 std::vector<unsigned char> newKey;
340 if (!pwalletMain->GetKeyFromPool(newKey, false))
341 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
342 CBitcoinAddress address(newKey);
344 pwalletMain->SetAddressBookName(address, strAccount);
346 return address.ToString();
350 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
352 CWalletDB walletdb(pwalletMain->strWalletFile);
355 walletdb.ReadAccount(strAccount, account);
357 bool bKeyUsed = false;
359 // Check if the current key has been used
360 if (!account.vchPubKey.empty())
362 CScript scriptPubKey;
363 scriptPubKey.SetBitcoinAddress(account.vchPubKey);
364 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
365 it != pwalletMain->mapWallet.end() && !account.vchPubKey.empty();
368 const CWalletTx& wtx = (*it).second;
369 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
370 if (txout.scriptPubKey == scriptPubKey)
375 // Generate a new key
376 if (account.vchPubKey.empty() || bForceNew || bKeyUsed)
378 if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false))
379 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
381 pwalletMain->SetAddressBookName(CBitcoinAddress(account.vchPubKey), strAccount);
382 walletdb.WriteAccount(strAccount, account);
385 return CBitcoinAddress(account.vchPubKey);
388 Value getaccountaddress(const Array& params, bool fHelp)
390 if (fHelp || params.size() != 1)
392 "getaccountaddress <account>\n"
393 "Returns the current bitcoin address for receiving payments to this account.");
395 // Parse the account first so we don't generate a key if there's an error
396 string strAccount = AccountFromValue(params[0]);
400 ret = GetAccountAddress(strAccount).ToString();
407 Value setaccount(const Array& params, bool fHelp)
409 if (fHelp || params.size() < 1 || params.size() > 2)
411 "setaccount <bitcoinaddress> <account>\n"
412 "Sets the account associated with the given address.");
414 CBitcoinAddress address(params[0].get_str());
415 if (!address.IsValid())
416 throw JSONRPCError(-5, "Invalid bitcoin address");
420 if (params.size() > 1)
421 strAccount = AccountFromValue(params[1]);
423 // Detect when changing the account of an address that is the 'unused current key' of another account:
424 if (pwalletMain->mapAddressBook.count(address))
426 string strOldAccount = pwalletMain->mapAddressBook[address];
427 if (address == GetAccountAddress(strOldAccount))
428 GetAccountAddress(strOldAccount, true);
431 pwalletMain->SetAddressBookName(address, strAccount);
437 Value getaccount(const Array& params, bool fHelp)
439 if (fHelp || params.size() != 1)
441 "getaccount <bitcoinaddress>\n"
442 "Returns the account associated with the given address.");
444 CBitcoinAddress address(params[0].get_str());
445 if (!address.IsValid())
446 throw JSONRPCError(-5, "Invalid bitcoin address");
449 map<CBitcoinAddress, string>::iterator mi = pwalletMain->mapAddressBook.find(address);
450 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
451 strAccount = (*mi).second;
456 Value getaddressesbyaccount(const Array& params, bool fHelp)
458 if (fHelp || params.size() != 1)
460 "getaddressesbyaccount <account>\n"
461 "Returns the list of addresses for the given account.");
463 string strAccount = AccountFromValue(params[0]);
465 // Find all addresses that have the given account
467 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
469 const CBitcoinAddress& address = item.first;
470 const string& strName = item.second;
471 if (strName == strAccount)
472 ret.push_back(address.ToString());
477 Value settxfee(const Array& params, bool fHelp)
479 if (fHelp || params.size() < 1 || params.size() > 1)
481 "settxfee <amount>\n"
482 "<amount> is a real and is rounded to the nearest 0.00000001");
486 if (params[0].get_real() != 0.0)
487 nAmount = AmountFromValue(params[0]); // rejects 0.0 amounts
489 nTransactionFee = nAmount;
493 Value sendtoaddress(const Array& params, bool fHelp)
495 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
497 "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
498 "<amount> is a real and is rounded to the nearest 0.00000001\n"
499 "requires wallet passphrase to be set with walletpassphrase first");
500 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
502 "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
503 "<amount> is a real and is rounded to the nearest 0.00000001");
505 CBitcoinAddress address(params[0].get_str());
506 if (!address.IsValid())
507 throw JSONRPCError(-5, "Invalid bitcoin address");
510 int64 nAmount = AmountFromValue(params[1]);
514 if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
515 wtx.mapValue["comment"] = params[2].get_str();
516 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
517 wtx.mapValue["to"] = params[3].get_str();
519 if (pwalletMain->IsLocked())
520 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
522 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
524 throw JSONRPCError(-4, strError);
526 return wtx.GetHash().GetHex();
529 static const string strMessageMagic = "Bitcoin Signed Message:\n";
531 Value signmessage(const Array& params, bool fHelp)
533 if (fHelp || params.size() != 2)
535 "signmessage <bitcoinaddress> <message>\n"
536 "Sign a message with the private key of an address");
538 if (pwalletMain->IsLocked())
539 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
541 string strAddress = params[0].get_str();
542 string strMessage = params[1].get_str();
544 CBitcoinAddress addr(strAddress);
546 throw JSONRPCError(-3, "Invalid address");
549 if (!pwalletMain->GetKey(addr, key))
550 throw JSONRPCError(-4, "Private key not available");
552 CDataStream ss(SER_GETHASH);
553 ss << strMessageMagic;
556 vector<unsigned char> vchSig;
557 if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig))
558 throw JSONRPCError(-5, "Sign failed");
560 return EncodeBase64(&vchSig[0], vchSig.size());
563 Value verifymessage(const Array& params, bool fHelp)
565 if (fHelp || params.size() != 3)
567 "verifymessage <bitcoinaddress> <signature> <message>\n"
568 "Verify a signed message");
570 string strAddress = params[0].get_str();
571 string strSign = params[1].get_str();
572 string strMessage = params[2].get_str();
574 CBitcoinAddress addr(strAddress);
576 throw JSONRPCError(-3, "Invalid address");
578 bool fInvalid = false;
579 vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
582 throw JSONRPCError(-5, "Malformed base64 encoding");
584 CDataStream ss(SER_GETHASH);
585 ss << strMessageMagic;
589 if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
592 return (key.GetAddress() == addr);
596 Value getreceivedbyaddress(const Array& params, bool fHelp)
598 if (fHelp || params.size() < 1 || params.size() > 2)
600 "getreceivedbyaddress <bitcoinaddress> [minconf=1]\n"
601 "Returns the total amount received by <bitcoinaddress> in transactions with at least [minconf] confirmations.");
604 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
605 CScript scriptPubKey;
606 if (!address.IsValid())
607 throw JSONRPCError(-5, "Invalid bitcoin address");
608 scriptPubKey.SetBitcoinAddress(address);
609 if (!IsMine(*pwalletMain,scriptPubKey))
612 // Minimum confirmations
614 if (params.size() > 1)
615 nMinDepth = params[1].get_int();
619 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
621 const CWalletTx& wtx = (*it).second;
622 if (wtx.IsCoinBase() || !wtx.IsFinal())
625 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
626 if (txout.scriptPubKey == scriptPubKey)
627 if (wtx.GetDepthInMainChain() >= nMinDepth)
628 nAmount += txout.nValue;
631 return ValueFromAmount(nAmount);
635 void GetAccountAddresses(string strAccount, set<CBitcoinAddress>& setAddress)
637 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
639 const CBitcoinAddress& address = item.first;
640 const string& strName = item.second;
641 if (strName == strAccount)
642 setAddress.insert(address);
647 Value getreceivedbyaccount(const Array& params, bool fHelp)
649 if (fHelp || params.size() < 1 || params.size() > 2)
651 "getreceivedbyaccount <account> [minconf=1]\n"
652 "Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.");
654 // Minimum confirmations
656 if (params.size() > 1)
657 nMinDepth = params[1].get_int();
659 // Get the set of pub keys that have the label
660 string strAccount = AccountFromValue(params[0]);
661 set<CBitcoinAddress> setAddress;
662 GetAccountAddresses(strAccount, setAddress);
666 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
668 const CWalletTx& wtx = (*it).second;
669 if (wtx.IsCoinBase() || !wtx.IsFinal())
672 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
674 CBitcoinAddress address;
675 if (ExtractAddress(txout.scriptPubKey, pwalletMain, address) && setAddress.count(address))
676 if (wtx.GetDepthInMainChain() >= nMinDepth)
677 nAmount += txout.nValue;
681 return (double)nAmount / (double)COIN;
685 int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth)
689 // Tally wallet transactions
690 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
692 const CWalletTx& wtx = (*it).second;
696 int64 nGenerated, nReceived, nSent, nFee;
697 wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee);
699 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
700 nBalance += nReceived;
701 nBalance += nGenerated - nSent - nFee;
704 // Tally internal accounting entries
705 nBalance += walletdb.GetAccountCreditDebit(strAccount);
710 int64 GetAccountBalance(const string& strAccount, int nMinDepth)
712 CWalletDB walletdb(pwalletMain->strWalletFile);
713 return GetAccountBalance(walletdb, strAccount, nMinDepth);
717 Value getbalance(const Array& params, bool fHelp)
719 if (fHelp || params.size() > 2)
721 "getbalance [account] [minconf=1]\n"
722 "If [account] is not specified, returns the server's total available balance.\n"
723 "If [account] is specified, returns the balance in the account.");
725 if (params.size() == 0)
726 return ValueFromAmount(pwalletMain->GetBalance());
729 if (params.size() > 1)
730 nMinDepth = params[1].get_int();
732 if (params[0].get_str() == "*") {
733 // Calculate total balance a different way from GetBalance()
734 // (GetBalance() sums up all unspent TxOuts)
735 // getbalance and getbalance '*' should always return the same number.
737 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
739 const CWalletTx& wtx = (*it).second;
743 int64 allGeneratedImmature, allGeneratedMature, allFee;
744 allGeneratedImmature = allGeneratedMature = allFee = 0;
745 string strSentAccount;
746 list<pair<CBitcoinAddress, int64> > listReceived;
747 list<pair<CBitcoinAddress, int64> > listSent;
748 wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
749 if (wtx.GetDepthInMainChain() >= nMinDepth)
750 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listReceived)
751 nBalance += r.second;
752 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listSent)
753 nBalance -= r.second;
755 nBalance += allGeneratedMature;
757 return ValueFromAmount(nBalance);
760 string strAccount = AccountFromValue(params[0]);
762 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
764 return ValueFromAmount(nBalance);
768 Value movecmd(const Array& params, bool fHelp)
770 if (fHelp || params.size() < 3 || params.size() > 5)
772 "move <fromaccount> <toaccount> <amount> [minconf=1] [comment]\n"
773 "Move from one account in your wallet to another.");
775 string strFrom = AccountFromValue(params[0]);
776 string strTo = AccountFromValue(params[1]);
777 int64 nAmount = AmountFromValue(params[2]);
778 if (params.size() > 3)
779 // unused parameter, used to be nMinDepth, keep type-checking it though
780 (void)params[3].get_int();
782 if (params.size() > 4)
783 strComment = params[4].get_str();
785 CWalletDB walletdb(pwalletMain->strWalletFile);
788 int64 nNow = GetAdjustedTime();
791 CAccountingEntry debit;
792 debit.strAccount = strFrom;
793 debit.nCreditDebit = -nAmount;
795 debit.strOtherAccount = strTo;
796 debit.strComment = strComment;
797 walletdb.WriteAccountingEntry(debit);
800 CAccountingEntry credit;
801 credit.strAccount = strTo;
802 credit.nCreditDebit = nAmount;
804 credit.strOtherAccount = strFrom;
805 credit.strComment = strComment;
806 walletdb.WriteAccountingEntry(credit);
808 walletdb.TxnCommit();
814 Value sendfrom(const Array& params, bool fHelp)
816 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
818 "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
819 "<amount> is a real and is rounded to the nearest 0.00000001\n"
820 "requires wallet passphrase to be set with walletpassphrase first");
821 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
823 "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
824 "<amount> is a real and is rounded to the nearest 0.00000001");
826 string strAccount = AccountFromValue(params[0]);
827 CBitcoinAddress address(params[1].get_str());
828 if (!address.IsValid())
829 throw JSONRPCError(-5, "Invalid bitcoin address");
830 int64 nAmount = AmountFromValue(params[2]);
832 if (params.size() > 3)
833 nMinDepth = params[3].get_int();
836 wtx.strFromAccount = strAccount;
837 if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
838 wtx.mapValue["comment"] = params[4].get_str();
839 if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
840 wtx.mapValue["to"] = params[5].get_str();
842 if (pwalletMain->IsLocked())
843 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
846 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
847 if (nAmount > nBalance)
848 throw JSONRPCError(-6, "Account has insufficient funds");
851 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
853 throw JSONRPCError(-4, strError);
855 return wtx.GetHash().GetHex();
859 Value sendmany(const Array& params, bool fHelp)
861 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
863 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
864 "amounts are double-precision floating point numbers\n"
865 "requires wallet passphrase to be set with walletpassphrase first");
866 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
868 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
869 "amounts are double-precision floating point numbers");
871 string strAccount = AccountFromValue(params[0]);
872 Object sendTo = params[1].get_obj();
874 if (params.size() > 2)
875 nMinDepth = params[2].get_int();
878 wtx.strFromAccount = strAccount;
879 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
880 wtx.mapValue["comment"] = params[3].get_str();
882 set<CBitcoinAddress> setAddress;
883 vector<pair<CScript, int64> > vecSend;
885 int64 totalAmount = 0;
886 BOOST_FOREACH(const Pair& s, sendTo)
888 CBitcoinAddress address(s.name_);
889 if (!address.IsValid())
890 throw JSONRPCError(-5, string("Invalid bitcoin address:")+s.name_);
892 if (setAddress.count(address))
893 throw JSONRPCError(-8, string("Invalid parameter, duplicated address: ")+s.name_);
894 setAddress.insert(address);
896 CScript scriptPubKey;
897 scriptPubKey.SetBitcoinAddress(address);
898 int64 nAmount = AmountFromValue(s.value_);
899 totalAmount += nAmount;
901 vecSend.push_back(make_pair(scriptPubKey, nAmount));
904 if (pwalletMain->IsLocked())
905 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
908 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
909 if (totalAmount > nBalance)
910 throw JSONRPCError(-6, "Account has insufficient funds");
913 CReserveKey keyChange(pwalletMain);
914 int64 nFeeRequired = 0;
915 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
918 if (totalAmount + nFeeRequired > pwalletMain->GetBalance())
919 throw JSONRPCError(-6, "Insufficient funds");
920 throw JSONRPCError(-4, "Transaction creation failed");
922 if (!pwalletMain->CommitTransaction(wtx, keyChange))
923 throw JSONRPCError(-4, "Transaction commit failed");
925 return wtx.GetHash().GetHex();
940 Value ListReceived(const Array& params, bool fByAccounts)
942 // Minimum confirmations
944 if (params.size() > 0)
945 nMinDepth = params[0].get_int();
947 // Whether to include empty accounts
948 bool fIncludeEmpty = false;
949 if (params.size() > 1)
950 fIncludeEmpty = params[1].get_bool();
953 map<CBitcoinAddress, tallyitem> mapTally;
954 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
956 const CWalletTx& wtx = (*it).second;
957 if (wtx.IsCoinBase() || !wtx.IsFinal())
960 int nDepth = wtx.GetDepthInMainChain();
961 if (nDepth < nMinDepth)
964 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
966 CBitcoinAddress address;
967 if (!ExtractAddress(txout.scriptPubKey, pwalletMain, address) || !address.IsValid())
970 tallyitem& item = mapTally[address];
971 item.nAmount += txout.nValue;
972 item.nConf = min(item.nConf, nDepth);
978 map<string, tallyitem> mapAccountTally;
979 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
981 const CBitcoinAddress& address = item.first;
982 const string& strAccount = item.second;
983 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
984 if (it == mapTally.end() && !fIncludeEmpty)
989 if (it != mapTally.end())
991 nAmount = (*it).second.nAmount;
992 nConf = (*it).second.nConf;
997 tallyitem& item = mapAccountTally[strAccount];
998 item.nAmount += nAmount;
999 item.nConf = min(item.nConf, nConf);
1004 obj.push_back(Pair("address", address.ToString()));
1005 obj.push_back(Pair("account", strAccount));
1006 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1007 obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
1014 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
1016 int64 nAmount = (*it).second.nAmount;
1017 int nConf = (*it).second.nConf;
1019 obj.push_back(Pair("account", (*it).first));
1020 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1021 obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
1029 Value listreceivedbyaddress(const Array& params, bool fHelp)
1031 if (fHelp || params.size() > 2)
1032 throw runtime_error(
1033 "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
1034 "[minconf] is the minimum number of confirmations before payments are included.\n"
1035 "[includeempty] whether to include addresses that haven't received any payments.\n"
1036 "Returns an array of objects containing:\n"
1037 " \"address\" : receiving address\n"
1038 " \"account\" : the account of the receiving address\n"
1039 " \"amount\" : total amount received by the address\n"
1040 " \"confirmations\" : number of confirmations of the most recent transaction included");
1042 return ListReceived(params, false);
1045 Value listreceivedbyaccount(const Array& params, bool fHelp)
1047 if (fHelp || params.size() > 2)
1048 throw runtime_error(
1049 "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
1050 "[minconf] is the minimum number of confirmations before payments are included.\n"
1051 "[includeempty] whether to include accounts that haven't received any payments.\n"
1052 "Returns an array of objects containing:\n"
1053 " \"account\" : the account of the receiving addresses\n"
1054 " \"amount\" : total amount received by addresses with this account\n"
1055 " \"confirmations\" : number of confirmations of the most recent transaction included");
1057 return ListReceived(params, true);
1060 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret)
1062 int64 nGeneratedImmature, nGeneratedMature, nFee;
1063 string strSentAccount;
1064 list<pair<CBitcoinAddress, int64> > listReceived;
1065 list<pair<CBitcoinAddress, int64> > listSent;
1066 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1068 bool fAllAccounts = (strAccount == string("*"));
1070 // Generated blocks assigned to account ""
1071 if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == ""))
1074 entry.push_back(Pair("account", string("")));
1075 if (nGeneratedImmature)
1077 entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
1078 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
1082 entry.push_back(Pair("category", "generate"));
1083 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
1086 WalletTxToJSON(wtx, entry);
1087 ret.push_back(entry);
1091 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1093 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1096 entry.push_back(Pair("account", strSentAccount));
1097 entry.push_back(Pair("address", s.first.ToString()));
1098 entry.push_back(Pair("category", "send"));
1099 entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1100 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1102 WalletTxToJSON(wtx, entry);
1103 ret.push_back(entry);
1108 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1109 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1112 if (pwalletMain->mapAddressBook.count(r.first))
1113 account = pwalletMain->mapAddressBook[r.first];
1114 if (fAllAccounts || (account == strAccount))
1117 entry.push_back(Pair("account", account));
1118 entry.push_back(Pair("address", r.first.ToString()));
1119 entry.push_back(Pair("category", "receive"));
1120 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1122 WalletTxToJSON(wtx, entry);
1123 ret.push_back(entry);
1128 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1130 bool fAllAccounts = (strAccount == string("*"));
1132 if (fAllAccounts || acentry.strAccount == strAccount)
1135 entry.push_back(Pair("account", acentry.strAccount));
1136 entry.push_back(Pair("category", "move"));
1137 entry.push_back(Pair("time", (boost::int64_t)acentry.nTime));
1138 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1139 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1140 entry.push_back(Pair("comment", acentry.strComment));
1141 ret.push_back(entry);
1145 Value listtransactions(const Array& params, bool fHelp)
1147 if (fHelp || params.size() > 3)
1148 throw runtime_error(
1149 "listtransactions [account] [count=10] [from=0]\n"
1150 "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1152 string strAccount = "*";
1153 if (params.size() > 0)
1154 strAccount = params[0].get_str();
1156 if (params.size() > 1)
1157 nCount = params[1].get_int();
1159 if (params.size() > 2)
1160 nFrom = params[2].get_int();
1163 CWalletDB walletdb(pwalletMain->strWalletFile);
1165 // Firs: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap:
1166 typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
1167 typedef multimap<int64, TxPair > TxItems;
1170 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1172 CWalletTx* wtx = &((*it).second);
1173 txByTime.insert(make_pair(wtx->GetTxTime(), TxPair(wtx, (CAccountingEntry*)0)));
1175 list<CAccountingEntry> acentries;
1176 walletdb.ListAccountCreditDebit(strAccount, acentries);
1177 BOOST_FOREACH(CAccountingEntry& entry, acentries)
1179 txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
1182 // Now: iterate backwards until we have nCount items to return:
1183 TxItems::reverse_iterator it = txByTime.rbegin();
1184 if (txByTime.size() > nFrom) std::advance(it, nFrom);
1185 for (; it != txByTime.rend(); ++it)
1187 CWalletTx *const pwtx = (*it).second.first;
1189 ListTransactions(*pwtx, strAccount, 0, true, ret);
1190 CAccountingEntry *const pacentry = (*it).second.second;
1192 AcentryToJSON(*pacentry, strAccount, ret);
1194 if (ret.size() >= nCount) break;
1196 // ret is now newest to oldest
1198 // Make sure we return only last nCount items (sends-to-self might give us an extra):
1199 if (ret.size() > nCount)
1201 Array::iterator last = ret.begin();
1202 std::advance(last, nCount);
1203 ret.erase(last, ret.end());
1205 std::reverse(ret.begin(), ret.end()); // oldest to newest
1210 Value listaccounts(const Array& params, bool fHelp)
1212 if (fHelp || params.size() > 1)
1213 throw runtime_error(
1214 "listaccounts [minconf=1]\n"
1215 "Returns Object that has account names as keys, account balances as values.");
1218 if (params.size() > 0)
1219 nMinDepth = params[0].get_int();
1221 map<string, int64> mapAccountBalances;
1222 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& entry, pwalletMain->mapAddressBook) {
1223 if (pwalletMain->HaveKey(entry.first)) // This address belongs to me
1224 mapAccountBalances[entry.second] = 0;
1227 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1229 const CWalletTx& wtx = (*it).second;
1230 int64 nGeneratedImmature, nGeneratedMature, nFee;
1231 string strSentAccount;
1232 list<pair<CBitcoinAddress, int64> > listReceived;
1233 list<pair<CBitcoinAddress, int64> > listSent;
1234 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1235 mapAccountBalances[strSentAccount] -= nFee;
1236 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1237 mapAccountBalances[strSentAccount] -= s.second;
1238 if (wtx.GetDepthInMainChain() >= nMinDepth)
1240 mapAccountBalances[""] += nGeneratedMature;
1241 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1242 if (pwalletMain->mapAddressBook.count(r.first))
1243 mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1245 mapAccountBalances[""] += r.second;
1249 list<CAccountingEntry> acentries;
1250 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1251 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1252 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1255 BOOST_FOREACH(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) {
1256 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1261 Value gettransaction(const Array& params, bool fHelp)
1263 if (fHelp || params.size() != 1)
1264 throw runtime_error(
1265 "gettransaction <txid>\n"
1266 "Get detailed information about <txid>");
1269 hash.SetHex(params[0].get_str());
1273 if (!pwalletMain->mapWallet.count(hash))
1274 throw JSONRPCError(-5, "Invalid or non-wallet transaction id");
1275 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1277 int64 nCredit = wtx.GetCredit();
1278 int64 nDebit = wtx.GetDebit();
1279 int64 nNet = nCredit - nDebit;
1280 int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
1282 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1284 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1286 WalletTxToJSON(pwalletMain->mapWallet[hash], entry);
1289 ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
1290 entry.push_back(Pair("details", details));
1296 Value backupwallet(const Array& params, bool fHelp)
1298 if (fHelp || params.size() != 1)
1299 throw runtime_error(
1300 "backupwallet <destination>\n"
1301 "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1303 string strDest = params[0].get_str();
1304 BackupWallet(*pwalletMain, strDest);
1310 Value keypoolrefill(const Array& params, bool fHelp)
1312 if (pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1313 throw runtime_error(
1315 "Fills the keypool, requires wallet passphrase to be set.");
1316 if (!pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1317 throw runtime_error(
1319 "Fills the keypool.");
1321 if (pwalletMain->IsLocked())
1322 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
1324 pwalletMain->TopUpKeyPool();
1326 if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100))
1327 throw JSONRPCError(-4, "Error refreshing keypool.");
1333 void ThreadTopUpKeyPool(void* parg)
1335 pwalletMain->TopUpKeyPool();
1338 void ThreadCleanWalletPassphrase(void* parg)
1340 int64 nMyWakeTime = GetTime() + *((int*)parg);
1342 if (nWalletUnlockTime == 0)
1344 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1346 nWalletUnlockTime = nMyWakeTime;
1349 while (GetTime() < nWalletUnlockTime)
1350 Sleep(GetTime() - nWalletUnlockTime);
1352 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1354 nWalletUnlockTime = 0;
1359 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1361 if (nWalletUnlockTime < nMyWakeTime)
1362 nWalletUnlockTime = nMyWakeTime;
1368 pwalletMain->Lock();
1373 Value walletpassphrase(const Array& params, bool fHelp)
1375 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1376 throw runtime_error(
1377 "walletpassphrase <passphrase> <timeout>\n"
1378 "Stores the wallet decryption key in memory for <timeout> seconds.");
1381 if (!pwalletMain->IsCrypted())
1382 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1384 if (!pwalletMain->IsLocked())
1385 throw JSONRPCError(-17, "Error: Wallet is already unlocked.");
1387 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1388 string strWalletPass;
1389 strWalletPass.reserve(100);
1390 mlock(&strWalletPass[0], strWalletPass.capacity());
1391 strWalletPass = params[0].get_str();
1393 if (strWalletPass.length() > 0)
1395 if (!pwalletMain->Unlock(strWalletPass))
1397 fill(strWalletPass.begin(), strWalletPass.end(), '\0');
1398 munlock(&strWalletPass[0], strWalletPass.capacity());
1399 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1401 fill(strWalletPass.begin(), strWalletPass.end(), '\0');
1402 munlock(&strWalletPass[0], strWalletPass.capacity());
1405 throw runtime_error(
1406 "walletpassphrase <passphrase> <timeout>\n"
1407 "Stores the wallet decryption key in memory for <timeout> seconds.");
1409 CreateThread(ThreadTopUpKeyPool, NULL);
1410 int* pnSleepTime = new int(params[1].get_int());
1411 CreateThread(ThreadCleanWalletPassphrase, pnSleepTime);
1417 Value walletpassphrasechange(const Array& params, bool fHelp)
1419 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1420 throw runtime_error(
1421 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1422 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1425 if (!pwalletMain->IsCrypted())
1426 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1428 string strOldWalletPass;
1429 strOldWalletPass.reserve(100);
1430 mlock(&strOldWalletPass[0], strOldWalletPass.capacity());
1431 strOldWalletPass = params[0].get_str();
1433 string strNewWalletPass;
1434 strNewWalletPass.reserve(100);
1435 mlock(&strNewWalletPass[0], strNewWalletPass.capacity());
1436 strNewWalletPass = params[1].get_str();
1438 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1439 throw runtime_error(
1440 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1441 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1443 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1445 fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0');
1446 fill(strNewWalletPass.begin(), strNewWalletPass.end(), '\0');
1447 munlock(&strOldWalletPass[0], strOldWalletPass.capacity());
1448 munlock(&strNewWalletPass[0], strNewWalletPass.capacity());
1449 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1451 fill(strNewWalletPass.begin(), strNewWalletPass.end(), '\0');
1452 fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0');
1453 munlock(&strOldWalletPass[0], strOldWalletPass.capacity());
1454 munlock(&strNewWalletPass[0], strNewWalletPass.capacity());
1460 Value walletlock(const Array& params, bool fHelp)
1462 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1463 throw runtime_error(
1465 "Removes the wallet encryption key from memory, locking the wallet.\n"
1466 "After calling this method, you will need to call walletpassphrase again\n"
1467 "before being able to call any methods which require the wallet to be unlocked.");
1470 if (!pwalletMain->IsCrypted())
1471 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called.");
1473 pwalletMain->Lock();
1474 CRITICAL_BLOCK(cs_nWalletUnlockTime)
1476 nWalletUnlockTime = 0;
1483 Value encryptwallet(const Array& params, bool fHelp)
1485 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1486 throw runtime_error(
1487 "encryptwallet <passphrase>\n"
1488 "Encrypts the wallet with <passphrase>.");
1491 if (pwalletMain->IsCrypted())
1492 throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
1494 string strWalletPass;
1495 strWalletPass.reserve(100);
1496 mlock(&strWalletPass[0], strWalletPass.capacity());
1497 strWalletPass = params[0].get_str();
1499 if (strWalletPass.length() < 1)
1500 throw runtime_error(
1501 "encryptwallet <passphrase>\n"
1502 "Encrypts the wallet with <passphrase>.");
1504 if (!pwalletMain->EncryptWallet(strWalletPass))
1506 fill(strWalletPass.begin(), strWalletPass.end(), '\0');
1507 munlock(&strWalletPass[0], strWalletPass.capacity());
1508 throw JSONRPCError(-16, "Error: Failed to encrypt the wallet.");
1510 fill(strWalletPass.begin(), strWalletPass.end(), '\0');
1511 munlock(&strWalletPass[0], strWalletPass.capacity());
1517 Value validateaddress(const Array& params, bool fHelp)
1519 if (fHelp || params.size() != 1)
1520 throw runtime_error(
1521 "validateaddress <bitcoinaddress>\n"
1522 "Return information about <bitcoinaddress>.");
1524 CBitcoinAddress address(params[0].get_str());
1525 bool isValid = address.IsValid();
1528 ret.push_back(Pair("isvalid", isValid));
1531 // Call Hash160ToAddress() so we always return current ADDRESSVERSION
1532 // version of the address:
1533 string currentAddress = address.ToString();
1534 ret.push_back(Pair("address", currentAddress));
1535 ret.push_back(Pair("ismine", (pwalletMain->HaveKey(address) > 0)));
1536 if (pwalletMain->mapAddressBook.count(address))
1537 ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
1543 Value getwork(const Array& params, bool fHelp)
1545 if (fHelp || params.size() > 1)
1546 throw runtime_error(
1548 "If [data] is not specified, returns formatted hash data to work on:\n"
1549 " \"midstate\" : precomputed hash state after hashing the first half of the data (DEPRECATED)\n" // deprecated
1550 " \"data\" : block data\n"
1551 " \"hash1\" : formatted hash buffer for second hash (DEPRECATED)\n" // deprecated
1552 " \"target\" : little endian hash target\n"
1553 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1556 throw JSONRPCError(-9, "Bitcoin is not connected!");
1558 if (IsInitialBlockDownload())
1559 throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
1561 typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
1562 static mapNewBlock_t mapNewBlock;
1563 static vector<CBlock*> vNewBlock;
1564 static CReserveKey reservekey(pwalletMain);
1566 if (params.size() == 0)
1569 static unsigned int nTransactionsUpdatedLast;
1570 static CBlockIndex* pindexPrev;
1571 static int64 nStart;
1572 static CBlock* pblock;
1573 if (pindexPrev != pindexBest ||
1574 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
1576 if (pindexPrev != pindexBest)
1578 // Deallocate old blocks since they're obsolete now
1579 mapNewBlock.clear();
1580 BOOST_FOREACH(CBlock* pblock, vNewBlock)
1584 nTransactionsUpdatedLast = nTransactionsUpdated;
1585 pindexPrev = pindexBest;
1589 pblock = CreateNewBlock(reservekey);
1591 throw JSONRPCError(-7, "Out of memory");
1592 vNewBlock.push_back(pblock);
1596 pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
1599 // Update nExtraNonce
1600 static unsigned int nExtraNonce = 0;
1601 IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
1604 mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
1606 // Prebuild hash buffers
1610 FormatHashBuffers(pblock, pmidstate, pdata, phash1);
1612 uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
1615 result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate)))); // deprecated
1616 result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata))));
1617 result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1)))); // deprecated
1618 result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
1624 vector<unsigned char> vchData = ParseHex(params[0].get_str());
1625 if (vchData.size() != 128)
1626 throw JSONRPCError(-8, "Invalid parameter");
1627 CBlock* pdata = (CBlock*)&vchData[0];
1630 for (int i = 0; i < 128/4; i++)
1631 ((unsigned int*)pdata)[i] = CryptoPP::ByteReverse(((unsigned int*)pdata)[i]);
1634 if (!mapNewBlock.count(pdata->hashMerkleRoot))
1636 CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
1638 pblock->nTime = pdata->nTime;
1639 pblock->nNonce = pdata->nNonce;
1640 pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
1641 pblock->hashMerkleRoot = pblock->BuildMerkleTree();
1643 return CheckWork(pblock, *pwalletMain, reservekey);
1661 pair<string, rpcfn_type> pCallTable[] =
1663 make_pair("help", &help),
1664 make_pair("stop", &stop),
1665 make_pair("getblockcount", &getblockcount),
1666 make_pair("getblocknumber", &getblocknumber),
1667 make_pair("getconnectioncount", &getconnectioncount),
1668 make_pair("getdifficulty", &getdifficulty),
1669 make_pair("getgenerate", &getgenerate),
1670 make_pair("setgenerate", &setgenerate),
1671 make_pair("gethashespersec", &gethashespersec),
1672 make_pair("getinfo", &getinfo),
1673 make_pair("getnewaddress", &getnewaddress),
1674 make_pair("getaccountaddress", &getaccountaddress),
1675 make_pair("setaccount", &setaccount),
1676 make_pair("getaccount", &getaccount),
1677 make_pair("getaddressesbyaccount", &getaddressesbyaccount),
1678 make_pair("sendtoaddress", &sendtoaddress),
1679 make_pair("getreceivedbyaddress", &getreceivedbyaddress),
1680 make_pair("getreceivedbyaccount", &getreceivedbyaccount),
1681 make_pair("listreceivedbyaddress", &listreceivedbyaddress),
1682 make_pair("listreceivedbyaccount", &listreceivedbyaccount),
1683 make_pair("backupwallet", &backupwallet),
1684 make_pair("keypoolrefill", &keypoolrefill),
1685 make_pair("walletpassphrase", &walletpassphrase),
1686 make_pair("walletpassphrasechange", &walletpassphrasechange),
1687 make_pair("walletlock", &walletlock),
1688 make_pair("encryptwallet", &encryptwallet),
1689 make_pair("validateaddress", &validateaddress),
1690 make_pair("getbalance", &getbalance),
1691 make_pair("move", &movecmd),
1692 make_pair("sendfrom", &sendfrom),
1693 make_pair("sendmany", &sendmany),
1694 make_pair("gettransaction", &gettransaction),
1695 make_pair("listtransactions", &listtransactions),
1696 make_pair("signmessage", &signmessage),
1697 make_pair("verifymessage", &verifymessage),
1698 make_pair("getwork", &getwork),
1699 make_pair("listaccounts", &listaccounts),
1700 make_pair("settxfee", &settxfee),
1702 map<string, rpcfn_type> mapCallTable(pCallTable, pCallTable + sizeof(pCallTable)/sizeof(pCallTable[0]));
1704 string pAllowInSafeMode[] =
1710 "getconnectioncount",
1717 "getaccountaddress",
1719 "getaddressesbyaccount",
1727 set<string> setAllowInSafeMode(pAllowInSafeMode, pAllowInSafeMode + sizeof(pAllowInSafeMode)/sizeof(pAllowInSafeMode[0]));
1735 // This ain't Apache. We're just using HTTP header for the length field
1736 // and to be compatible with other JSON-RPC implementations.
1739 string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
1742 s << "POST / HTTP/1.1\r\n"
1743 << "User-Agent: bitcoin-json-rpc/" << FormatFullVersion() << "\r\n"
1744 << "Host: 127.0.0.1\r\n"
1745 << "Content-Type: application/json\r\n"
1746 << "Content-Length: " << strMsg.size() << "\r\n"
1747 << "Accept: application/json\r\n";
1748 BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
1749 s << item.first << ": " << item.second << "\r\n";
1750 s << "\r\n" << strMsg;
1755 string rfc1123Time()
1760 struct tm* now_gmt = gmtime(&now);
1761 string locale(setlocale(LC_TIME, NULL));
1762 setlocale(LC_TIME, "C"); // we want posix (aka "C") weekday/month strings
1763 strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt);
1764 setlocale(LC_TIME, locale.c_str());
1765 return string(buffer);
1768 static string HTTPReply(int nStatus, const string& strMsg)
1771 return strprintf("HTTP/1.0 401 Authorization Required\r\n"
1773 "Server: bitcoin-json-rpc/%s\r\n"
1774 "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
1775 "Content-Type: text/html\r\n"
1776 "Content-Length: 296\r\n"
1778 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
1779 "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
1782 "<TITLE>Error</TITLE>\r\n"
1783 "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
1785 "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
1786 "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
1788 if (nStatus == 200) strStatus = "OK";
1789 else if (nStatus == 400) strStatus = "Bad Request";
1790 else if (nStatus == 403) strStatus = "Forbidden";
1791 else if (nStatus == 404) strStatus = "Not Found";
1792 else if (nStatus == 500) strStatus = "Internal Server Error";
1794 "HTTP/1.1 %d %s\r\n"
1796 "Connection: close\r\n"
1797 "Content-Length: %d\r\n"
1798 "Content-Type: application/json\r\n"
1799 "Server: bitcoin-json-rpc/%s\r\n"
1804 rfc1123Time().c_str(),
1806 FormatFullVersion().c_str(),
1810 int ReadHTTPStatus(std::basic_istream<char>& stream)
1813 getline(stream, str);
1814 vector<string> vWords;
1815 boost::split(vWords, str, boost::is_any_of(" "));
1816 if (vWords.size() < 2)
1818 return atoi(vWords[1].c_str());
1821 int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
1827 std::getline(stream, str);
1828 if (str.empty() || str == "\r")
1830 string::size_type nColon = str.find(":");
1831 if (nColon != string::npos)
1833 string strHeader = str.substr(0, nColon);
1834 boost::trim(strHeader);
1835 boost::to_lower(strHeader);
1836 string strValue = str.substr(nColon+1);
1837 boost::trim(strValue);
1838 mapHeadersRet[strHeader] = strValue;
1839 if (strHeader == "content-length")
1840 nLen = atoi(strValue.c_str());
1846 int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
1848 mapHeadersRet.clear();
1852 int nStatus = ReadHTTPStatus(stream);
1855 int nLen = ReadHTTPHeader(stream, mapHeadersRet);
1856 if (nLen < 0 || nLen > MAX_SIZE)
1862 vector<char> vch(nLen);
1863 stream.read(&vch[0], nLen);
1864 strMessageRet = string(vch.begin(), vch.end());
1870 bool HTTPAuthorized(map<string, string>& mapHeaders)
1872 string strAuth = mapHeaders["authorization"];
1873 if (strAuth.substr(0,6) != "Basic ")
1875 string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
1876 string strUserPass = DecodeBase64(strUserPass64);
1877 string::size_type nColon = strUserPass.find(":");
1878 if (nColon == string::npos)
1880 string strUser = strUserPass.substr(0, nColon);
1881 string strPassword = strUserPass.substr(nColon+1);
1882 return (strUser == mapArgs["-rpcuser"] && strPassword == mapArgs["-rpcpassword"]);
1886 // JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
1887 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
1888 // unspecified (HTTP errors and contents of 'error').
1890 // 1.0 spec: http://json-rpc.org/wiki/specification
1891 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
1892 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
1895 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
1898 request.push_back(Pair("method", strMethod));
1899 request.push_back(Pair("params", params));
1900 request.push_back(Pair("id", id));
1901 return write_string(Value(request), false) + "\n";
1904 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
1907 if (error.type() != null_type)
1908 reply.push_back(Pair("result", Value::null));
1910 reply.push_back(Pair("result", result));
1911 reply.push_back(Pair("error", error));
1912 reply.push_back(Pair("id", id));
1913 return write_string(Value(reply), false) + "\n";
1916 void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
1918 // Send error reply from json-rpc error object
1920 int code = find_value(objError, "code").get_int();
1921 if (code == -32600) nStatus = 400;
1922 else if (code == -32601) nStatus = 404;
1923 string strReply = JSONRPCReply(Value::null, objError, id);
1924 stream << HTTPReply(nStatus, strReply) << std::flush;
1927 bool ClientAllowed(const string& strAddress)
1929 if (strAddress == asio::ip::address_v4::loopback().to_string())
1931 const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
1932 BOOST_FOREACH(string strAllow, vAllow)
1933 if (WildcardMatch(strAddress, strAllow))
1940 // IOStream device that speaks SSL but can also speak non-SSL
1942 class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
1944 SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
1946 fUseSSL = fUseSSLIn;
1947 fNeedHandshake = fUseSSLIn;
1950 void handshake(ssl::stream_base::handshake_type role)
1952 if (!fNeedHandshake) return;
1953 fNeedHandshake = false;
1954 stream.handshake(role);
1956 std::streamsize read(char* s, std::streamsize n)
1958 handshake(ssl::stream_base::server); // HTTPS servers read first
1959 if (fUseSSL) return stream.read_some(asio::buffer(s, n));
1960 return stream.next_layer().read_some(asio::buffer(s, n));
1962 std::streamsize write(const char* s, std::streamsize n)
1964 handshake(ssl::stream_base::client); // HTTPS clients write first
1965 if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
1966 return asio::write(stream.next_layer(), asio::buffer(s, n));
1968 bool connect(const std::string& server, const std::string& port)
1970 ip::tcp::resolver resolver(stream.get_io_service());
1971 ip::tcp::resolver::query query(server.c_str(), port.c_str());
1972 ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
1973 ip::tcp::resolver::iterator end;
1974 boost::system::error_code error = asio::error::host_not_found;
1975 while (error && endpoint_iterator != end)
1977 stream.lowest_layer().close();
1978 stream.lowest_layer().connect(*endpoint_iterator++, error);
1986 bool fNeedHandshake;
1992 void ThreadRPCServer(void* parg)
1994 IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
1997 vnThreadsRunning[4]++;
1998 ThreadRPCServer2(parg);
1999 vnThreadsRunning[4]--;
2001 catch (std::exception& e) {
2002 vnThreadsRunning[4]--;
2003 PrintException(&e, "ThreadRPCServer()");
2005 vnThreadsRunning[4]--;
2006 PrintException(NULL, "ThreadRPCServer()");
2008 printf("ThreadRPCServer exiting\n");
2011 void ThreadRPCServer2(void* parg)
2013 printf("ThreadRPCServer started\n");
2015 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2017 string strWhatAmI = "To use bitcoind";
2018 if (mapArgs.count("-server"))
2019 strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
2020 else if (mapArgs.count("-daemon"))
2021 strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
2023 _("Warning: %s, you must set rpcpassword=<password>\nin the configuration file: %s\n"
2024 "If the file does not exist, create it with owner-readable-only file permissions.\n"),
2026 GetConfigFile().c_str());
2027 CreateThread(Shutdown, NULL);
2031 bool fUseSSL = GetBoolArg("-rpcssl");
2032 asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
2034 asio::io_service io_service;
2035 ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", 8332));
2036 ip::tcp::acceptor acceptor(io_service, endpoint);
2038 acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
2041 ssl::context context(io_service, ssl::context::sslv23);
2044 context.set_options(ssl::context::no_sslv2);
2045 filesystem::path certfile = GetArg("-rpcsslcertificatechainfile", "server.cert");
2046 if (!certfile.is_complete()) certfile = filesystem::path(GetDataDir()) / certfile;
2047 if (filesystem::exists(certfile)) context.use_certificate_chain_file(certfile.string().c_str());
2048 else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", certfile.string().c_str());
2049 filesystem::path pkfile = GetArg("-rpcsslprivatekeyfile", "server.pem");
2050 if (!pkfile.is_complete()) pkfile = filesystem::path(GetDataDir()) / pkfile;
2051 if (filesystem::exists(pkfile)) context.use_private_key_file(pkfile.string().c_str(), ssl::context::pem);
2052 else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pkfile.string().c_str());
2054 string ciphers = GetArg("-rpcsslciphers",
2055 "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
2056 SSL_CTX_set_cipher_list(context.impl(), ciphers.c_str());
2060 throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
2065 // Accept connection
2067 SSLStream sslStream(io_service, context);
2068 SSLIOStreamDevice d(sslStream, fUseSSL);
2069 iostreams::stream<SSLIOStreamDevice> stream(d);
2071 ip::tcp::iostream stream;
2074 ip::tcp::endpoint peer;
2075 vnThreadsRunning[4]--;
2077 acceptor.accept(sslStream.lowest_layer(), peer);
2079 acceptor.accept(*stream.rdbuf(), peer);
2081 vnThreadsRunning[4]++;
2085 // Restrict callers by IP
2086 if (!ClientAllowed(peer.address().to_string()))
2088 // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
2090 stream << HTTPReply(403, "") << std::flush;
2094 map<string, string> mapHeaders;
2097 boost::thread api_caller(ReadHTTP, boost::ref(stream), boost::ref(mapHeaders), boost::ref(strRequest));
2098 if (!api_caller.timed_join(boost::posix_time::seconds(GetArg("-rpctimeout", 30))))
2101 printf("ThreadRPCServer ReadHTTP timeout\n");
2105 // Check authorization
2106 if (mapHeaders.count("authorization") == 0)
2108 stream << HTTPReply(401, "") << std::flush;
2111 if (!HTTPAuthorized(mapHeaders))
2113 // Deter brute-forcing short passwords
2114 if (mapArgs["-rpcpassword"].size() < 15)
2117 stream << HTTPReply(401, "") << std::flush;
2118 printf("ThreadRPCServer incorrect password attempt\n");
2122 Value id = Value::null;
2127 if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
2128 throw JSONRPCError(-32700, "Parse error");
2129 const Object& request = valRequest.get_obj();
2131 // Parse id now so errors from here on will have the id
2132 id = find_value(request, "id");
2135 Value valMethod = find_value(request, "method");
2136 if (valMethod.type() == null_type)
2137 throw JSONRPCError(-32600, "Missing method");
2138 if (valMethod.type() != str_type)
2139 throw JSONRPCError(-32600, "Method must be a string");
2140 string strMethod = valMethod.get_str();
2141 if (strMethod != "getwork")
2142 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
2145 Value valParams = find_value(request, "params");
2147 if (valParams.type() == array_type)
2148 params = valParams.get_array();
2149 else if (valParams.type() == null_type)
2152 throw JSONRPCError(-32600, "Params must be an array");
2155 map<string, rpcfn_type>::iterator mi = mapCallTable.find(strMethod);
2156 if (mi == mapCallTable.end())
2157 throw JSONRPCError(-32601, "Method not found");
2159 // Observe safe mode
2160 string strWarning = GetWarnings("rpc");
2161 if (strWarning != "" && !GetBoolArg("-disablesafemode") && !setAllowInSafeMode.count(strMethod))
2162 throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
2168 CRITICAL_BLOCK(cs_main)
2169 CRITICAL_BLOCK(pwalletMain->cs_wallet)
2170 result = (*(*mi).second)(params, false);
2173 string strReply = JSONRPCReply(result, Value::null, id);
2174 stream << HTTPReply(200, strReply) << std::flush;
2176 catch (std::exception& e)
2178 ErrorReply(stream, JSONRPCError(-1, e.what()), id);
2181 catch (Object& objError)
2183 ErrorReply(stream, objError, id);
2185 catch (std::exception& e)
2187 ErrorReply(stream, JSONRPCError(-32700, e.what()), id);
2195 Object CallRPC(const string& strMethod, const Array& params)
2197 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2198 throw runtime_error(strprintf(
2199 _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
2200 "If the file does not exist, create it with owner-readable-only file permissions."),
2201 GetConfigFile().c_str()));
2203 // Connect to localhost
2204 bool fUseSSL = GetBoolArg("-rpcssl");
2206 asio::io_service io_service;
2207 ssl::context context(io_service, ssl::context::sslv23);
2208 context.set_options(ssl::context::no_sslv2);
2209 SSLStream sslStream(io_service, context);
2210 SSLIOStreamDevice d(sslStream, fUseSSL);
2211 iostreams::stream<SSLIOStreamDevice> stream(d);
2212 if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332")))
2213 throw runtime_error("couldn't connect to server");
2216 throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
2218 ip::tcp::iostream stream(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332"));
2220 throw runtime_error("couldn't connect to server");
2224 // HTTP basic authentication
2225 string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
2226 map<string, string> mapRequestHeaders;
2227 mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
2230 string strRequest = JSONRPCRequest(strMethod, params, 1);
2231 string strPost = HTTPPost(strRequest, mapRequestHeaders);
2232 stream << strPost << std::flush;
2235 map<string, string> mapHeaders;
2237 int nStatus = ReadHTTP(stream, mapHeaders, strReply);
2239 throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
2240 else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
2241 throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
2242 else if (strReply.empty())
2243 throw runtime_error("no response from server");
2247 if (!read_string(strReply, valReply))
2248 throw runtime_error("couldn't parse reply from server");
2249 const Object& reply = valReply.get_obj();
2251 throw runtime_error("expected reply to have result, error and id properties");
2259 template<typename T>
2260 void ConvertTo(Value& value)
2262 if (value.type() == str_type)
2264 // reinterpret string as unquoted json value
2266 if (!read_string(value.get_str(), value2))
2267 throw runtime_error("type mismatch");
2268 value = value2.get_value<T>();
2272 value = value.get_value<T>();
2276 int CommandLineRPC(int argc, char *argv[])
2283 while (argc > 1 && IsSwitchChar(argv[1][0]))
2291 throw runtime_error("too few parameters");
2292 string strMethod = argv[1];
2294 // Parameters default to strings
2296 for (int i = 2; i < argc; i++)
2297 params.push_back(argv[i]);
2298 int n = params.size();
2301 // Special case non-string parameter types
2303 if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
2304 if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2305 if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
2306 if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]);
2307 if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2308 if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2309 if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2310 if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
2311 if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2312 if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
2313 if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2314 if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]);
2315 if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2316 if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]);
2317 if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2318 if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2319 if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2320 if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2321 if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2322 if (strMethod == "sendmany" && n > 1)
2324 string s = params[1].get_str();
2326 if (!read_string(s, v) || v.type() != obj_type)
2327 throw runtime_error("type mismatch");
2328 params[1] = v.get_obj();
2330 if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2333 Object reply = CallRPC(strMethod, params);
2336 const Value& result = find_value(reply, "result");
2337 const Value& error = find_value(reply, "error");
2339 if (error.type() != null_type)
2342 strPrint = "error: " + write_string(error, false);
2343 int code = find_value(error.get_obj(), "code").get_int();
2349 if (result.type() == null_type)
2351 else if (result.type() == str_type)
2352 strPrint = result.get_str();
2354 strPrint = write_string(result, true);
2357 catch (std::exception& e)
2359 strPrint = string("error: ") + e.what();
2364 PrintException(NULL, "CommandLineRPC()");
2369 fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
2378 int main(int argc, char *argv[])
2381 // Turn off microsoft heap dump noise
2382 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
2383 _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
2385 setbuf(stdin, NULL);
2386 setbuf(stdout, NULL);
2387 setbuf(stderr, NULL);
2391 if (argc >= 2 && string(argv[1]) == "-server")
2393 printf("server ready\n");
2394 ThreadRPCServer(NULL);
2398 return CommandLineRPC(argc, argv);
2401 catch (std::exception& e) {
2402 PrintException(&e, "main()");
2404 PrintException(NULL, "main()");