1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2012 The Bitcoin developers
3 // Copyright (c) 2011-2012 The PPCoin developers
4 // Distributed under the MIT/X11 software license, see the accompanying
5 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
13 #include "checkpoints.h"
14 #include "ui_interface.h"
15 #include "bitcoinrpc.h"
18 #include <boost/asio.hpp>
19 #include <boost/filesystem.hpp>
20 #include <boost/iostreams/concepts.hpp>
21 #include <boost/iostreams/stream.hpp>
22 #include <boost/algorithm/string.hpp>
23 #include <boost/lexical_cast.hpp>
24 #include <boost/asio/ssl.hpp>
25 #include <boost/filesystem/fstream.hpp>
26 typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> SSLStream;
28 #define printf OutputDebugStringF
29 // MinGW 3.4.5 gets "fatal error: had to relocate PCH" if the json headers are
30 // precompiled in headers.h. The problem might be when the pch file goes over
31 // a certain size around 145MB. If we need access to json_spirit outside this
32 // file, we could use the compiled json_spirit option.
35 using namespace boost;
36 using namespace boost::asio;
37 using namespace json_spirit;
39 void ThreadRPCServer2(void* parg);
41 static std::string strRPCUserColonPass;
43 static int64 nWalletUnlockTime;
44 static CCriticalSection cs_nWalletUnlockTime;
46 extern Value dumpprivkey(const Array& params, bool fHelp);
47 extern Value importprivkey(const Array& params, bool fHelp);
49 Object JSONRPCError(int code, const string& message)
52 error.push_back(Pair("code", code));
53 error.push_back(Pair("message", message));
57 double GetDifficulty(const CBlockIndex* blockindex = NULL)
59 // Floating point number that is a multiple of the minimum difficulty,
60 // minimum difficulty = 1.0.
61 if (blockindex == NULL)
63 if (pindexBest == NULL)
66 blockindex = GetLastBlockIndex(pindexBest, false);
69 int nShift = (blockindex->nBits >> 24) & 0xff;
72 (double)0x0000ffff / (double)(blockindex->nBits & 0x00ffffff);
89 int64 AmountFromValue(const Value& value)
91 double dAmount = value.get_real();
92 if (dAmount <= 0.0 || dAmount > MAX_MONEY)
93 throw JSONRPCError(-3, "Invalid amount");
94 int64 nAmount = roundint64(dAmount * COIN);
95 if (!MoneyRange(nAmount))
96 throw JSONRPCError(-3, "Invalid amount");
100 Value ValueFromAmount(int64 amount)
102 return (double)amount / (double)COIN;
106 HexBits(unsigned int nBits)
112 uBits.nBits = htonl((int32_t)nBits);
113 return HexStr(BEGIN(uBits.cBits), END(uBits.cBits));
116 void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
118 int confirms = wtx.GetDepthInMainChain();
119 entry.push_back(Pair("confirmations", confirms));
122 entry.push_back(Pair("blockhash", wtx.hashBlock.GetHex()));
123 entry.push_back(Pair("blockindex", wtx.nIndex));
125 entry.push_back(Pair("txid", wtx.GetHash().GetHex()));
126 entry.push_back(Pair("time", (boost::int64_t)wtx.GetTxTime()));
127 BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
128 entry.push_back(Pair(item.first, item.second));
131 string AccountFromValue(const Value& value)
133 string strAccount = value.get_str();
134 if (strAccount == "*")
135 throw JSONRPCError(-11, "Invalid account name");
139 Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool fPrintTransactionDetail)
142 result.push_back(Pair("hash", block.GetHash().GetHex()));
143 result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION)));
144 result.push_back(Pair("height", blockindex->nHeight));
145 result.push_back(Pair("version", block.nVersion));
146 result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex()));
147 result.push_back(Pair("time", DateTimeStrFormat(block.GetBlockTime())));
148 result.push_back(Pair("nonce", (boost::uint64_t)block.nNonce));
149 result.push_back(Pair("bits", HexBits(block.nBits)));
150 result.push_back(Pair("difficulty", GetDifficulty(blockindex)));
151 result.push_back(Pair("mint", ValueFromAmount(blockindex->nMint)));
152 if (blockindex->pprev)
153 result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex()));
154 if (blockindex->pnext)
155 result.push_back(Pair("nextblockhash", blockindex->pnext->GetBlockHash().GetHex()));
157 BOOST_FOREACH (const CTransaction& tx, block.vtx)
159 if (fPrintTransactionDetail)
161 txinfo.push_back(tx.ToStringShort());
162 txinfo.push_back(DateTimeStrFormat(tx.nTime));
163 BOOST_FOREACH(const CTxIn& txin, tx.vin)
164 txinfo.push_back(txin.ToStringShort());
165 BOOST_FOREACH(const CTxOut& txout, tx.vout)
166 txinfo.push_back(txout.ToStringShort());
169 txinfo.push_back(tx.GetHash().GetHex());
171 result.push_back(Pair("tx", txinfo));
178 /// Note: This interface may still be subject to change.
181 string CRPCTable::help(string strCommand) const
184 set<rpcfn_type> setDone;
185 for (map<string, const CRPCCommand*>::const_iterator mi = mapCommands.begin(); mi != mapCommands.end(); ++mi)
187 const CRPCCommand *pcmd = mi->second;
188 string strMethod = mi->first;
189 // We already filter duplicates, but these deprecated screw up the sort order
190 if (strMethod == "getamountreceived" ||
191 strMethod == "getallreceived" ||
192 strMethod == "getblocknumber" || // deprecated
193 (strMethod.find("label") != string::npos))
195 if (strCommand != "" && strMethod != strCommand)
200 rpcfn_type pfn = pcmd->actor;
201 if (setDone.insert(pfn).second)
202 (*pfn)(params, true);
204 catch (std::exception& e)
206 // Help text is returned in an exception
207 string strHelp = string(e.what());
208 if (strCommand == "")
209 if (strHelp.find('\n') != string::npos)
210 strHelp = strHelp.substr(0, strHelp.find('\n'));
211 strRet += strHelp + "\n";
215 strRet = strprintf("help: unknown command: %s\n", strCommand.c_str());
216 strRet = strRet.substr(0,strRet.size()-1);
220 Value help(const Array& params, bool fHelp)
222 if (fHelp || params.size() > 1)
225 "List commands, or get help for a command.");
228 if (params.size() > 0)
229 strCommand = params[0].get_str();
231 return tableRPC.help(strCommand);
235 Value stop(const Array& params, bool fHelp)
237 if (fHelp || params.size() != 0)
240 "Stop ppcoin server.");
241 // Shutdown will take long enough that the response should get back
243 return "ppcoin server stopping";
247 Value getblockcount(const Array& params, bool fHelp)
249 if (fHelp || params.size() != 0)
252 "Returns the number of blocks in the longest block chain.");
259 Value getblocknumber(const Array& params, bool fHelp)
261 if (fHelp || params.size() != 0)
264 "Deprecated. Use getblockcount.");
270 Value getconnectioncount(const Array& params, bool fHelp)
272 if (fHelp || params.size() != 0)
274 "getconnectioncount\n"
275 "Returns the number of connections to other nodes.");
277 return (int)vNodes.size();
281 Value getdifficulty(const Array& params, bool fHelp)
283 if (fHelp || params.size() != 0)
286 "Returns difficulty as a multiple of the minimum difficulty.");
289 obj.push_back(Pair("proof-of-work", GetDifficulty()));
290 obj.push_back(Pair("proof-of-stake", GetDifficulty(GetLastBlockIndex(pindexBest, true))));
291 obj.push_back(Pair("search-interval", (int)nLastCoinStakeSearchInterval));
296 Value getgenerate(const Array& params, bool fHelp)
298 if (fHelp || params.size() != 0)
301 "Returns true or false.");
303 return GetBoolArg("-gen");
307 Value setgenerate(const Array& params, bool fHelp)
309 if (fHelp || params.size() < 1 || params.size() > 2)
311 "setgenerate <generate> [genproclimit]\n"
312 "<generate> is true or false to turn generation on or off.\n"
313 "Generation is limited to [genproclimit] processors, -1 is unlimited.");
315 bool fGenerate = true;
316 if (params.size() > 0)
317 fGenerate = params[0].get_bool();
319 if (params.size() > 1)
321 int nGenProcLimit = params[1].get_int();
322 mapArgs["-genproclimit"] = itostr(nGenProcLimit);
323 if (nGenProcLimit == 0)
326 mapArgs["-gen"] = (fGenerate ? "1" : "0");
328 GenerateBitcoins(fGenerate, pwalletMain);
333 Value gethashespersec(const Array& params, bool fHelp)
335 if (fHelp || params.size() != 0)
338 "Returns a recent hashes per second performance measurement while generating.");
340 if (GetTimeMillis() - nHPSTimerStart > 8000)
341 return (boost::int64_t)0;
342 return (boost::int64_t)dHashesPerSec;
346 Value getinfo(const Array& params, bool fHelp)
348 if (fHelp || params.size() != 0)
351 "Returns an object containing various state info.");
354 obj.push_back(Pair("version", FormatFullVersion()));
355 obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION));
356 obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
357 obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
358 obj.push_back(Pair("newmint", ValueFromAmount(pwalletMain->GetNewMint())));
359 obj.push_back(Pair("stake", ValueFromAmount(pwalletMain->GetStake())));
360 obj.push_back(Pair("blocks", (int)nBestHeight));
361 obj.push_back(Pair("moneysupply", ValueFromAmount(pindexBest->nMoneySupply)));
362 obj.push_back(Pair("connections", (int)vNodes.size()));
363 obj.push_back(Pair("proxy", (fUseProxy ? addrProxy.ToStringIPPort() : string())));
364 obj.push_back(Pair("ip", addrSeenByPeer.ToStringIP()));
365 obj.push_back(Pair("difficulty", (double)GetDifficulty()));
366 obj.push_back(Pair("testnet", fTestNet));
367 obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));
368 obj.push_back(Pair("keypoolsize", pwalletMain->GetKeyPoolSize()));
369 obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee)));
370 if (pwalletMain->IsCrypted())
371 obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime / 1000));
372 obj.push_back(Pair("errors", GetWarnings("statusbar")));
377 Value getmininginfo(const Array& params, bool fHelp)
379 if (fHelp || params.size() != 0)
382 "Returns an object containing mining-related information.");
385 obj.push_back(Pair("blocks", (int)nBestHeight));
386 obj.push_back(Pair("currentblocksize",(uint64_t)nLastBlockSize));
387 obj.push_back(Pair("currentblocktx",(uint64_t)nLastBlockTx));
388 obj.push_back(Pair("difficulty", (double)GetDifficulty()));
389 obj.push_back(Pair("errors", GetWarnings("statusbar")));
390 obj.push_back(Pair("generate", GetBoolArg("-gen")));
391 obj.push_back(Pair("genproclimit", (int)GetArg("-genproclimit", -1)));
392 obj.push_back(Pair("hashespersec", gethashespersec(params, false)));
393 obj.push_back(Pair("pooledtx", (uint64_t)mempool.size()));
394 obj.push_back(Pair("testnet", fTestNet));
399 Value getnewaddress(const Array& params, bool fHelp)
401 if (fHelp || params.size() > 1)
403 "getnewaddress [account]\n"
404 "Returns a new ppcoin address for receiving payments. "
405 "If [account] is specified (recommended), it is added to the address book "
406 "so payments received with the address will be credited to [account].");
408 // Parse the account first so we don't generate a key if there's an error
410 if (params.size() > 0)
411 strAccount = AccountFromValue(params[0]);
413 if (!pwalletMain->IsLocked())
414 pwalletMain->TopUpKeyPool();
416 // Generate a new key that is added to wallet
417 std::vector<unsigned char> newKey;
418 if (!pwalletMain->GetKeyFromPool(newKey, false))
419 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
420 CBitcoinAddress address(newKey);
422 pwalletMain->SetAddressBookName(address, strAccount);
424 return address.ToString();
428 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
430 CWalletDB walletdb(pwalletMain->strWalletFile);
433 walletdb.ReadAccount(strAccount, account);
435 bool bKeyUsed = false;
437 // Check if the current key has been used
438 if (!account.vchPubKey.empty())
440 CScript scriptPubKey;
441 scriptPubKey.SetBitcoinAddress(account.vchPubKey);
442 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
443 it != pwalletMain->mapWallet.end() && !account.vchPubKey.empty();
446 const CWalletTx& wtx = (*it).second;
447 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
448 if (txout.scriptPubKey == scriptPubKey)
453 // Generate a new key
454 if (account.vchPubKey.empty() || bForceNew || bKeyUsed)
456 if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false))
457 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
459 pwalletMain->SetAddressBookName(CBitcoinAddress(account.vchPubKey), strAccount);
460 walletdb.WriteAccount(strAccount, account);
463 return CBitcoinAddress(account.vchPubKey);
466 Value getaccountaddress(const Array& params, bool fHelp)
468 if (fHelp || params.size() != 1)
470 "getaccountaddress <account>\n"
471 "Returns the current ppcoin address for receiving payments to this account.");
473 // Parse the account first so we don't generate a key if there's an error
474 string strAccount = AccountFromValue(params[0]);
478 ret = GetAccountAddress(strAccount).ToString();
485 Value setaccount(const Array& params, bool fHelp)
487 if (fHelp || params.size() < 1 || params.size() > 2)
489 "setaccount <ppcoinaddress> <account>\n"
490 "Sets the account associated with the given address.");
492 CBitcoinAddress address(params[0].get_str());
493 if (!address.IsValid())
494 throw JSONRPCError(-5, "Invalid ppcoin address");
498 if (params.size() > 1)
499 strAccount = AccountFromValue(params[1]);
501 // Detect when changing the account of an address that is the 'unused current key' of another account:
502 if (pwalletMain->mapAddressBook.count(address))
504 string strOldAccount = pwalletMain->mapAddressBook[address];
505 if (address == GetAccountAddress(strOldAccount))
506 GetAccountAddress(strOldAccount, true);
509 pwalletMain->SetAddressBookName(address, strAccount);
515 Value getaccount(const Array& params, bool fHelp)
517 if (fHelp || params.size() != 1)
519 "getaccount <ppcoinaddress>\n"
520 "Returns the account associated with the given address.");
522 CBitcoinAddress address(params[0].get_str());
523 if (!address.IsValid())
524 throw JSONRPCError(-5, "Invalid ppcoin address");
527 map<CBitcoinAddress, string>::iterator mi = pwalletMain->mapAddressBook.find(address);
528 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
529 strAccount = (*mi).second;
534 Value getaddressesbyaccount(const Array& params, bool fHelp)
536 if (fHelp || params.size() != 1)
538 "getaddressesbyaccount <account>\n"
539 "Returns the list of addresses for the given account.");
541 string strAccount = AccountFromValue(params[0]);
543 // Find all addresses that have the given account
545 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
547 const CBitcoinAddress& address = item.first;
548 const string& strName = item.second;
549 if (strName == strAccount)
550 ret.push_back(address.ToString());
555 Value settxfee(const Array& params, bool fHelp)
557 if (fHelp || params.size() < 1 || params.size() > 1 || AmountFromValue(params[0]) < MIN_TX_FEE)
559 "settxfee <amount>\n"
560 "<amount> is a real and is rounded to 0.01 (cent)\n"
561 "Minimum and default transaction fee per KB is 1 cent");
563 nTransactionFee = AmountFromValue(params[0]);
564 nTransactionFee = (nTransactionFee / CENT) * CENT; // round to cent
568 Value sendtoaddress(const Array& params, bool fHelp)
570 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
572 "sendtoaddress <ppcoinaddress> <amount> [comment] [comment-to]\n"
573 "<amount> is a real and is rounded to the nearest 0.000001\n"
574 "requires wallet passphrase to be set with walletpassphrase first");
575 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
577 "sendtoaddress <ppcoinaddress> <amount> [comment] [comment-to]\n"
578 "<amount> is a real and is rounded to the nearest 0.000001");
580 CBitcoinAddress address(params[0].get_str());
581 if (!address.IsValid())
582 throw JSONRPCError(-5, "Invalid ppcoin address");
585 int64 nAmount = AmountFromValue(params[1]);
586 if (nAmount < MIN_TXOUT_AMOUNT)
587 throw JSONRPCError(-101, "Send amount too small");
591 if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
592 wtx.mapValue["comment"] = params[2].get_str();
593 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
594 wtx.mapValue["to"] = params[3].get_str();
596 if (pwalletMain->IsLocked())
597 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
599 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
601 throw JSONRPCError(-4, strError);
603 return wtx.GetHash().GetHex();
606 Value signmessage(const Array& params, bool fHelp)
608 if (fHelp || params.size() != 2)
610 "signmessage <ppcoinaddress> <message>\n"
611 "Sign a message with the private key of an address");
613 if (pwalletMain->IsLocked())
614 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
616 string strAddress = params[0].get_str();
617 string strMessage = params[1].get_str();
619 CBitcoinAddress addr(strAddress);
621 throw JSONRPCError(-3, "Invalid address");
624 if (!pwalletMain->GetKey(addr, key))
625 throw JSONRPCError(-4, "Private key not available");
627 CDataStream ss(SER_GETHASH, 0);
628 ss << strMessageMagic;
631 vector<unsigned char> vchSig;
632 if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig))
633 throw JSONRPCError(-5, "Sign failed");
635 return EncodeBase64(&vchSig[0], vchSig.size());
638 Value verifymessage(const Array& params, bool fHelp)
640 if (fHelp || params.size() != 3)
642 "verifymessage <ppcoinaddress> <signature> <message>\n"
643 "Verify a signed message");
645 string strAddress = params[0].get_str();
646 string strSign = params[1].get_str();
647 string strMessage = params[2].get_str();
649 CBitcoinAddress addr(strAddress);
651 throw JSONRPCError(-3, "Invalid address");
653 bool fInvalid = false;
654 vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
657 throw JSONRPCError(-5, "Malformed base64 encoding");
659 CDataStream ss(SER_GETHASH, 0);
660 ss << strMessageMagic;
664 if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
667 return (CBitcoinAddress(key.GetPubKey()) == addr);
671 Value getreceivedbyaddress(const Array& params, bool fHelp)
673 if (fHelp || params.size() < 1 || params.size() > 2)
675 "getreceivedbyaddress <ppcoinaddress> [minconf=1]\n"
676 "Returns the total amount received by <ppcoinaddress> in transactions with at least [minconf] confirmations.");
679 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
680 CScript scriptPubKey;
681 if (!address.IsValid())
682 throw JSONRPCError(-5, "Invalid ppcoin address");
683 scriptPubKey.SetBitcoinAddress(address);
684 if (!IsMine(*pwalletMain,scriptPubKey))
687 // Minimum confirmations
689 if (params.size() > 1)
690 nMinDepth = params[1].get_int();
694 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
696 const CWalletTx& wtx = (*it).second;
697 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
700 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
701 if (txout.scriptPubKey == scriptPubKey)
702 if (wtx.GetDepthInMainChain() >= nMinDepth)
703 nAmount += txout.nValue;
706 return ValueFromAmount(nAmount);
710 void GetAccountAddresses(string strAccount, set<CBitcoinAddress>& setAddress)
712 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
714 const CBitcoinAddress& address = item.first;
715 const string& strName = item.second;
716 if (strName == strAccount)
717 setAddress.insert(address);
722 Value getreceivedbyaccount(const Array& params, bool fHelp)
724 if (fHelp || params.size() < 1 || params.size() > 2)
726 "getreceivedbyaccount <account> [minconf=1]\n"
727 "Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.");
729 // Minimum confirmations
731 if (params.size() > 1)
732 nMinDepth = params[1].get_int();
734 // Get the set of pub keys assigned to account
735 string strAccount = AccountFromValue(params[0]);
736 set<CBitcoinAddress> setAddress;
737 GetAccountAddresses(strAccount, setAddress);
741 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
743 const CWalletTx& wtx = (*it).second;
744 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
747 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
749 CBitcoinAddress address;
750 if (ExtractAddress(txout.scriptPubKey, address) && pwalletMain->HaveKey(address) && setAddress.count(address))
751 if (wtx.GetDepthInMainChain() >= nMinDepth)
752 nAmount += txout.nValue;
756 return (double)nAmount / (double)COIN;
760 int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth)
764 // Tally wallet transactions
765 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
767 const CWalletTx& wtx = (*it).second;
771 int64 nGenerated, nReceived, nSent, nFee;
772 wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee);
774 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
775 nBalance += nReceived;
776 nBalance += nGenerated - nSent - nFee;
779 // Tally internal accounting entries
780 nBalance += walletdb.GetAccountCreditDebit(strAccount);
785 int64 GetAccountBalance(const string& strAccount, int nMinDepth)
787 CWalletDB walletdb(pwalletMain->strWalletFile);
788 return GetAccountBalance(walletdb, strAccount, nMinDepth);
792 Value getbalance(const Array& params, bool fHelp)
794 if (fHelp || params.size() > 2)
796 "getbalance [account] [minconf=1]\n"
797 "If [account] is not specified, returns the server's total available balance.\n"
798 "If [account] is specified, returns the balance in the account.");
800 if (params.size() == 0)
801 return ValueFromAmount(pwalletMain->GetBalance());
804 if (params.size() > 1)
805 nMinDepth = params[1].get_int();
807 if (params[0].get_str() == "*") {
808 // Calculate total balance a different way from GetBalance()
809 // (GetBalance() sums up all unspent TxOuts)
810 // getbalance and getbalance '*' should always return the same number.
812 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
814 const CWalletTx& wtx = (*it).second;
818 int64 allGeneratedImmature, allGeneratedMature, allFee;
819 allGeneratedImmature = allGeneratedMature = allFee = 0;
820 string strSentAccount;
821 list<pair<CBitcoinAddress, int64> > listReceived;
822 list<pair<CBitcoinAddress, int64> > listSent;
823 wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
824 if (wtx.GetDepthInMainChain() >= nMinDepth)
826 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listReceived)
827 nBalance += r.second;
829 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listSent)
830 nBalance -= r.second;
832 nBalance += allGeneratedMature;
834 return ValueFromAmount(nBalance);
837 string strAccount = AccountFromValue(params[0]);
839 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
841 return ValueFromAmount(nBalance);
845 Value movecmd(const Array& params, bool fHelp)
847 if (fHelp || params.size() < 3 || params.size() > 5)
849 "move <fromaccount> <toaccount> <amount> [minconf=1] [comment]\n"
850 "Move from one account in your wallet to another.");
852 string strFrom = AccountFromValue(params[0]);
853 string strTo = AccountFromValue(params[1]);
854 int64 nAmount = AmountFromValue(params[2]);
855 if (params.size() > 3)
856 // unused parameter, used to be nMinDepth, keep type-checking it though
857 (void)params[3].get_int();
859 if (params.size() > 4)
860 strComment = params[4].get_str();
862 CWalletDB walletdb(pwalletMain->strWalletFile);
863 if (!walletdb.TxnBegin())
864 throw JSONRPCError(-20, "database error");
866 int64 nNow = GetAdjustedTime();
869 CAccountingEntry debit;
870 debit.strAccount = strFrom;
871 debit.nCreditDebit = -nAmount;
873 debit.strOtherAccount = strTo;
874 debit.strComment = strComment;
875 walletdb.WriteAccountingEntry(debit);
878 CAccountingEntry credit;
879 credit.strAccount = strTo;
880 credit.nCreditDebit = nAmount;
882 credit.strOtherAccount = strFrom;
883 credit.strComment = strComment;
884 walletdb.WriteAccountingEntry(credit);
886 if (!walletdb.TxnCommit())
887 throw JSONRPCError(-20, "database error");
893 Value sendfrom(const Array& params, bool fHelp)
895 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
897 "sendfrom <fromaccount> <toppcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
898 "<amount> is a real and is rounded to the nearest 0.000001\n"
899 "requires wallet passphrase to be set with walletpassphrase first");
900 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
902 "sendfrom <fromaccount> <toppcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
903 "<amount> is a real and is rounded to the nearest 0.000001");
905 string strAccount = AccountFromValue(params[0]);
906 CBitcoinAddress address(params[1].get_str());
907 if (!address.IsValid())
908 throw JSONRPCError(-5, "Invalid ppcoin address");
909 int64 nAmount = AmountFromValue(params[2]);
910 if (nAmount < MIN_TXOUT_AMOUNT)
911 throw JSONRPCError(-101, "Send amount too small");
913 if (params.size() > 3)
914 nMinDepth = params[3].get_int();
917 wtx.strFromAccount = strAccount;
918 if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
919 wtx.mapValue["comment"] = params[4].get_str();
920 if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
921 wtx.mapValue["to"] = params[5].get_str();
923 if (pwalletMain->IsLocked())
924 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
927 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
928 if (nAmount > nBalance)
929 throw JSONRPCError(-6, "Account has insufficient funds");
932 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
934 throw JSONRPCError(-4, strError);
936 return wtx.GetHash().GetHex();
940 Value sendmany(const Array& params, bool fHelp)
942 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
944 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
945 "amounts are double-precision floating point numbers\n"
946 "requires wallet passphrase to be set with walletpassphrase first");
947 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
949 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
950 "amounts are double-precision floating point numbers");
952 string strAccount = AccountFromValue(params[0]);
953 Object sendTo = params[1].get_obj();
955 if (params.size() > 2)
956 nMinDepth = params[2].get_int();
959 wtx.strFromAccount = strAccount;
960 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
961 wtx.mapValue["comment"] = params[3].get_str();
963 set<CBitcoinAddress> setAddress;
964 vector<pair<CScript, int64> > vecSend;
966 int64 totalAmount = 0;
967 BOOST_FOREACH(const Pair& s, sendTo)
969 CBitcoinAddress address(s.name_);
970 if (!address.IsValid())
971 throw JSONRPCError(-5, string("Invalid ppcoin address:")+s.name_);
973 if (setAddress.count(address))
974 throw JSONRPCError(-8, string("Invalid parameter, duplicated address: ")+s.name_);
975 setAddress.insert(address);
977 CScript scriptPubKey;
978 scriptPubKey.SetBitcoinAddress(address);
979 int64 nAmount = AmountFromValue(s.value_);
980 if (nAmount < MIN_TXOUT_AMOUNT)
981 throw JSONRPCError(-101, "Send amount too small");
982 totalAmount += nAmount;
984 vecSend.push_back(make_pair(scriptPubKey, nAmount));
987 if (pwalletMain->IsLocked())
988 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
989 if (fWalletUnlockMintOnly)
990 throw JSONRPCError(-13, "Error: Wallet unlocked for block minting only.");
993 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
994 if (totalAmount > nBalance)
995 throw JSONRPCError(-6, "Account has insufficient funds");
998 CReserveKey keyChange(pwalletMain);
999 int64 nFeeRequired = 0;
1000 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
1003 if (totalAmount + nFeeRequired > pwalletMain->GetBalance())
1004 throw JSONRPCError(-6, "Insufficient funds");
1005 throw JSONRPCError(-4, "Transaction creation failed");
1007 if (!pwalletMain->CommitTransaction(wtx, keyChange))
1008 throw JSONRPCError(-4, "Transaction commit failed");
1010 return wtx.GetHash().GetHex();
1013 Value addmultisigaddress(const Array& params, bool fHelp)
1015 if (fHelp || params.size() < 2 || params.size() > 3)
1017 string msg = "addmultisigaddress <nrequired> <'[\"key\",\"key\"]'> [account]\n"
1018 "Add a nrequired-to-sign multisignature address to the wallet\"\n"
1019 "each key is a bitcoin address or hex-encoded public key\n"
1020 "If [account] is specified, assign address to [account].";
1021 throw runtime_error(msg);
1024 int nRequired = params[0].get_int();
1025 const Array& keys = params[1].get_array();
1027 if (params.size() > 2)
1028 strAccount = AccountFromValue(params[2]);
1030 // Gather public keys
1032 throw runtime_error("a multisignature address must require at least one key to redeem");
1033 if ((int)keys.size() < nRequired)
1034 throw runtime_error(
1035 strprintf("not enough keys supplied "
1036 "(got %d keys, but need at least %d to redeem)", keys.size(), nRequired));
1037 std::vector<CKey> pubkeys;
1038 pubkeys.resize(keys.size());
1039 for (unsigned int i = 0; i < keys.size(); i++)
1041 const std::string& ks = keys[i].get_str();
1043 // Case 1: bitcoin address and we have full public key:
1044 CBitcoinAddress address(ks);
1045 if (address.IsValid())
1047 if (address.IsScript())
1048 throw runtime_error(
1049 strprintf("%s is a pay-to-script address",ks.c_str()));
1050 std::vector<unsigned char> vchPubKey;
1051 if (!pwalletMain->GetPubKey(address, vchPubKey))
1052 throw runtime_error(
1053 strprintf("no full public key for address %s",ks.c_str()));
1054 if (vchPubKey.empty() || !pubkeys[i].SetPubKey(vchPubKey))
1055 throw runtime_error(" Invalid public key: "+ks);
1058 // Case 2: hex public key
1061 vector<unsigned char> vchPubKey = ParseHex(ks);
1062 if (vchPubKey.empty() || !pubkeys[i].SetPubKey(vchPubKey))
1063 throw runtime_error(" Invalid public key: "+ks);
1067 throw runtime_error(" Invalid public key: "+ks);
1071 // Construct using pay-to-script-hash:
1073 inner.SetMultisig(nRequired, pubkeys);
1075 uint160 scriptHash = Hash160(inner);
1076 CScript scriptPubKey;
1077 scriptPubKey.SetPayToScriptHash(inner);
1078 pwalletMain->AddCScript(inner);
1079 CBitcoinAddress address;
1080 address.SetScriptHash160(scriptHash);
1082 pwalletMain->SetAddressBookName(address, strAccount);
1083 return address.ToString();
1094 nConf = std::numeric_limits<int>::max();
1098 Value ListReceived(const Array& params, bool fByAccounts)
1100 // Minimum confirmations
1102 if (params.size() > 0)
1103 nMinDepth = params[0].get_int();
1105 // Whether to include empty accounts
1106 bool fIncludeEmpty = false;
1107 if (params.size() > 1)
1108 fIncludeEmpty = params[1].get_bool();
1111 map<CBitcoinAddress, tallyitem> mapTally;
1112 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1114 const CWalletTx& wtx = (*it).second;
1116 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
1119 int nDepth = wtx.GetDepthInMainChain();
1120 if (nDepth < nMinDepth)
1123 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
1125 CBitcoinAddress address;
1126 if (!ExtractAddress(txout.scriptPubKey, address) || !pwalletMain->HaveKey(address) || !address.IsValid())
1129 tallyitem& item = mapTally[address];
1130 item.nAmount += txout.nValue;
1131 item.nConf = min(item.nConf, nDepth);
1137 map<string, tallyitem> mapAccountTally;
1138 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
1140 const CBitcoinAddress& address = item.first;
1141 const string& strAccount = item.second;
1142 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
1143 if (it == mapTally.end() && !fIncludeEmpty)
1147 int nConf = std::numeric_limits<int>::max();
1148 if (it != mapTally.end())
1150 nAmount = (*it).second.nAmount;
1151 nConf = (*it).second.nConf;
1156 tallyitem& item = mapAccountTally[strAccount];
1157 item.nAmount += nAmount;
1158 item.nConf = min(item.nConf, nConf);
1163 obj.push_back(Pair("address", address.ToString()));
1164 obj.push_back(Pair("account", strAccount));
1165 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1166 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1173 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
1175 int64 nAmount = (*it).second.nAmount;
1176 int nConf = (*it).second.nConf;
1178 obj.push_back(Pair("account", (*it).first));
1179 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1180 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1188 Value listreceivedbyaddress(const Array& params, bool fHelp)
1190 if (fHelp || params.size() > 2)
1191 throw runtime_error(
1192 "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
1193 "[minconf] is the minimum number of confirmations before payments are included.\n"
1194 "[includeempty] whether to include addresses that haven't received any payments.\n"
1195 "Returns an array of objects containing:\n"
1196 " \"address\" : receiving address\n"
1197 " \"account\" : the account of the receiving address\n"
1198 " \"amount\" : total amount received by the address\n"
1199 " \"confirmations\" : number of confirmations of the most recent transaction included");
1201 return ListReceived(params, false);
1204 Value listreceivedbyaccount(const Array& params, bool fHelp)
1206 if (fHelp || params.size() > 2)
1207 throw runtime_error(
1208 "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
1209 "[minconf] is the minimum number of confirmations before payments are included.\n"
1210 "[includeempty] whether to include accounts that haven't received any payments.\n"
1211 "Returns an array of objects containing:\n"
1212 " \"account\" : the account of the receiving addresses\n"
1213 " \"amount\" : total amount received by addresses with this account\n"
1214 " \"confirmations\" : number of confirmations of the most recent transaction included");
1216 return ListReceived(params, true);
1219 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret)
1221 int64 nGeneratedImmature, nGeneratedMature, nFee;
1222 string strSentAccount;
1223 list<pair<CBitcoinAddress, int64> > listReceived;
1224 list<pair<CBitcoinAddress, int64> > listSent;
1226 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1228 bool fAllAccounts = (strAccount == string("*"));
1230 // Generated blocks assigned to account ""
1231 if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == ""))
1234 entry.push_back(Pair("account", string("")));
1235 if (nGeneratedImmature)
1237 entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
1238 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
1242 entry.push_back(Pair("category", "generate"));
1243 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
1246 WalletTxToJSON(wtx, entry);
1247 ret.push_back(entry);
1251 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1253 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1256 entry.push_back(Pair("account", strSentAccount));
1257 entry.push_back(Pair("address", s.first.ToString()));
1258 entry.push_back(Pair("category", "send"));
1259 entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1260 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1262 WalletTxToJSON(wtx, entry);
1263 ret.push_back(entry);
1268 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1270 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1273 if (pwalletMain->mapAddressBook.count(r.first))
1274 account = pwalletMain->mapAddressBook[r.first];
1275 if (fAllAccounts || (account == strAccount))
1278 entry.push_back(Pair("account", account));
1279 entry.push_back(Pair("address", r.first.ToString()));
1280 entry.push_back(Pair("category", "receive"));
1281 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1283 WalletTxToJSON(wtx, entry);
1284 ret.push_back(entry);
1290 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1292 bool fAllAccounts = (strAccount == string("*"));
1294 if (fAllAccounts || acentry.strAccount == strAccount)
1297 entry.push_back(Pair("account", acentry.strAccount));
1298 entry.push_back(Pair("category", "move"));
1299 entry.push_back(Pair("time", (boost::int64_t)acentry.nTime));
1300 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1301 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1302 entry.push_back(Pair("comment", acentry.strComment));
1303 ret.push_back(entry);
1307 Value listtransactions(const Array& params, bool fHelp)
1309 if (fHelp || params.size() > 3)
1310 throw runtime_error(
1311 "listtransactions [account] [count=10] [from=0]\n"
1312 "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1314 string strAccount = "*";
1315 if (params.size() > 0)
1316 strAccount = params[0].get_str();
1318 if (params.size() > 1)
1319 nCount = params[1].get_int();
1321 if (params.size() > 2)
1322 nFrom = params[2].get_int();
1325 throw JSONRPCError(-8, "Negative count");
1327 throw JSONRPCError(-8, "Negative from");
1330 CWalletDB walletdb(pwalletMain->strWalletFile);
1332 // First: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap.
1333 typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
1334 typedef multimap<int64, TxPair > TxItems;
1337 // Note: maintaining indices in the database of (account,time) --> txid and (account, time) --> acentry
1338 // would make this much faster for applications that do this a lot.
1339 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1341 CWalletTx* wtx = &((*it).second);
1342 txByTime.insert(make_pair(wtx->GetTxTime(), TxPair(wtx, (CAccountingEntry*)0)));
1344 list<CAccountingEntry> acentries;
1345 walletdb.ListAccountCreditDebit(strAccount, acentries);
1346 BOOST_FOREACH(CAccountingEntry& entry, acentries)
1348 txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
1351 // iterate backwards until we have nCount items to return:
1352 for (TxItems::reverse_iterator it = txByTime.rbegin(); it != txByTime.rend(); ++it)
1354 CWalletTx *const pwtx = (*it).second.first;
1356 ListTransactions(*pwtx, strAccount, 0, true, ret);
1357 CAccountingEntry *const pacentry = (*it).second.second;
1359 AcentryToJSON(*pacentry, strAccount, ret);
1361 if (ret.size() >= (nCount+nFrom)) break;
1363 // ret is newest to oldest
1365 if (nFrom > (int)ret.size())
1367 if ((nFrom + nCount) > (int)ret.size())
1368 nCount = ret.size() - nFrom;
1369 Array::iterator first = ret.begin();
1370 std::advance(first, nFrom);
1371 Array::iterator last = ret.begin();
1372 std::advance(last, nFrom+nCount);
1374 if (last != ret.end()) ret.erase(last, ret.end());
1375 if (first != ret.begin()) ret.erase(ret.begin(), first);
1377 std::reverse(ret.begin(), ret.end()); // Return oldest to newest
1382 Value listaccounts(const Array& params, bool fHelp)
1384 if (fHelp || params.size() > 1)
1385 throw runtime_error(
1386 "listaccounts [minconf=1]\n"
1387 "Returns Object that has account names as keys, account balances as values.");
1390 if (params.size() > 0)
1391 nMinDepth = params[0].get_int();
1393 map<string, int64> mapAccountBalances;
1394 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& entry, pwalletMain->mapAddressBook) {
1395 if (pwalletMain->HaveKey(entry.first)) // This address belongs to me
1396 mapAccountBalances[entry.second] = 0;
1399 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1401 const CWalletTx& wtx = (*it).second;
1402 int64 nGeneratedImmature, nGeneratedMature, nFee;
1403 string strSentAccount;
1404 list<pair<CBitcoinAddress, int64> > listReceived;
1405 list<pair<CBitcoinAddress, int64> > listSent;
1406 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1407 mapAccountBalances[strSentAccount] -= nFee;
1408 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1409 mapAccountBalances[strSentAccount] -= s.second;
1410 if (wtx.GetDepthInMainChain() >= nMinDepth)
1412 mapAccountBalances[""] += nGeneratedMature;
1413 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1414 if (pwalletMain->mapAddressBook.count(r.first))
1415 mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1417 mapAccountBalances[""] += r.second;
1421 list<CAccountingEntry> acentries;
1422 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1423 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1424 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1427 BOOST_FOREACH(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) {
1428 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1433 Value listsinceblock(const Array& params, bool fHelp)
1436 throw runtime_error(
1437 "listsinceblock [blockhash] [target-confirmations]\n"
1438 "Get all transactions in blocks since block [blockhash], or all transactions if omitted");
1440 CBlockIndex *pindex = NULL;
1441 int target_confirms = 1;
1443 if (params.size() > 0)
1445 uint256 blockId = 0;
1447 blockId.SetHex(params[0].get_str());
1448 pindex = CBlockLocator(blockId).GetBlockIndex();
1451 if (params.size() > 1)
1453 target_confirms = params[1].get_int();
1455 if (target_confirms < 1)
1456 throw JSONRPCError(-8, "Invalid parameter");
1459 int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1;
1463 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1465 CWalletTx tx = (*it).second;
1467 if (depth == -1 || tx.GetDepthInMainChain() < depth)
1468 ListTransactions(tx, "*", 0, true, transactions);
1473 if (target_confirms == 1)
1475 lastblock = hashBestChain;
1479 int target_height = pindexBest->nHeight + 1 - target_confirms;
1482 for (block = pindexBest;
1483 block && block->nHeight > target_height;
1484 block = block->pprev) { }
1486 lastblock = block ? block->GetBlockHash() : 0;
1490 ret.push_back(Pair("transactions", transactions));
1491 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1496 Value gettransaction(const Array& params, bool fHelp)
1498 if (fHelp || params.size() != 1)
1499 throw runtime_error(
1500 "gettransaction <txid>\n"
1501 "Get detailed information about <txid>");
1504 hash.SetHex(params[0].get_str());
1508 if (!pwalletMain->mapWallet.count(hash))
1509 throw JSONRPCError(-5, "Invalid or non-wallet transaction id");
1510 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1512 int64 nCredit = wtx.GetCredit();
1513 int64 nDebit = wtx.GetDebit();
1514 int64 nNet = nCredit - nDebit;
1515 int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
1517 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1519 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1521 WalletTxToJSON(pwalletMain->mapWallet[hash], entry);
1524 ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
1525 entry.push_back(Pair("details", details));
1531 Value backupwallet(const Array& params, bool fHelp)
1533 if (fHelp || params.size() != 1)
1534 throw runtime_error(
1535 "backupwallet <destination>\n"
1536 "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1538 string strDest = params[0].get_str();
1539 BackupWallet(*pwalletMain, strDest);
1545 Value keypoolrefill(const Array& params, bool fHelp)
1547 if (pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1548 throw runtime_error(
1550 "Fills the keypool, requires wallet passphrase to be set.");
1551 if (!pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1552 throw runtime_error(
1554 "Fills the keypool.");
1556 if (pwalletMain->IsLocked())
1557 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
1559 pwalletMain->TopUpKeyPool();
1561 if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100))
1562 throw JSONRPCError(-4, "Error refreshing keypool.");
1568 void ThreadTopUpKeyPool(void* parg)
1570 pwalletMain->TopUpKeyPool();
1573 void ThreadCleanWalletPassphrase(void* parg)
1575 int64 nMyWakeTime = GetTimeMillis() + *((int64*)parg) * 1000;
1577 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1579 if (nWalletUnlockTime == 0)
1581 nWalletUnlockTime = nMyWakeTime;
1585 if (nWalletUnlockTime==0)
1587 int64 nToSleep = nWalletUnlockTime - GetTimeMillis();
1591 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1593 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1597 if (nWalletUnlockTime)
1599 nWalletUnlockTime = 0;
1600 pwalletMain->Lock();
1605 if (nWalletUnlockTime < nMyWakeTime)
1606 nWalletUnlockTime = nMyWakeTime;
1609 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1611 delete (int64*)parg;
1614 Value walletpassphrase(const Array& params, bool fHelp)
1616 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 3))
1617 throw runtime_error(
1618 "walletpassphrase <passphrase> <timeout> [mintonly]\n"
1619 "Stores the wallet decryption key in memory for <timeout> seconds.\n"
1620 "mintonly is optional true/false allowing only block minting.");
1623 if (!pwalletMain->IsCrypted())
1624 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1626 if (!pwalletMain->IsLocked())
1627 throw JSONRPCError(-17, "Error: Wallet is already unlocked, use walletlock first if need to change unlock settings.");
1629 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1630 SecureString strWalletPass;
1631 strWalletPass.reserve(100);
1632 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1633 // Alternately, find a way to make params[0] mlock()'d to begin with.
1634 strWalletPass = params[0].get_str().c_str();
1636 if (strWalletPass.length() > 0)
1638 if (!pwalletMain->Unlock(strWalletPass))
1639 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1642 throw runtime_error(
1643 "walletpassphrase <passphrase> <timeout>\n"
1644 "Stores the wallet decryption key in memory for <timeout> seconds.");
1646 CreateThread(ThreadTopUpKeyPool, NULL);
1647 int64* pnSleepTime = new int64(params[1].get_int64());
1648 CreateThread(ThreadCleanWalletPassphrase, pnSleepTime);
1650 // ppcoin: if user OS account compromised prevent trivial sendmoney commands
1651 if (params.size() > 2)
1652 fWalletUnlockMintOnly = params[2].get_bool();
1654 fWalletUnlockMintOnly = false;
1660 Value walletpassphrasechange(const Array& params, bool fHelp)
1662 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1663 throw runtime_error(
1664 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1665 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1668 if (!pwalletMain->IsCrypted())
1669 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1671 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1672 // Alternately, find a way to make params[0] mlock()'d to begin with.
1673 SecureString strOldWalletPass;
1674 strOldWalletPass.reserve(100);
1675 strOldWalletPass = params[0].get_str().c_str();
1677 SecureString strNewWalletPass;
1678 strNewWalletPass.reserve(100);
1679 strNewWalletPass = params[1].get_str().c_str();
1681 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1682 throw runtime_error(
1683 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1684 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1686 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1687 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1693 Value walletlock(const Array& params, bool fHelp)
1695 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1696 throw runtime_error(
1698 "Removes the wallet encryption key from memory, locking the wallet.\n"
1699 "After calling this method, you will need to call walletpassphrase again\n"
1700 "before being able to call any methods which require the wallet to be unlocked.");
1703 if (!pwalletMain->IsCrypted())
1704 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called.");
1707 LOCK(cs_nWalletUnlockTime);
1708 pwalletMain->Lock();
1709 nWalletUnlockTime = 0;
1716 Value encryptwallet(const Array& params, bool fHelp)
1718 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1719 throw runtime_error(
1720 "encryptwallet <passphrase>\n"
1721 "Encrypts the wallet with <passphrase>.");
1724 if (pwalletMain->IsCrypted())
1725 throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
1727 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1728 // Alternately, find a way to make params[0] mlock()'d to begin with.
1729 SecureString strWalletPass;
1730 strWalletPass.reserve(100);
1731 strWalletPass = params[0].get_str().c_str();
1733 if (strWalletPass.length() < 1)
1734 throw runtime_error(
1735 "encryptwallet <passphrase>\n"
1736 "Encrypts the wallet with <passphrase>.");
1738 if (!pwalletMain->EncryptWallet(strWalletPass))
1739 throw JSONRPCError(-16, "Error: Failed to encrypt the wallet.");
1741 // BDB seems to have a bad habit of writing old data into
1742 // slack space in .dat files; that is bad if the old data is
1743 // unencrypted private keys. So:
1745 return "wallet encrypted; ppcoin server stopping, restart to run with encrypted wallet";
1749 Value validateaddress(const Array& params, bool fHelp)
1751 if (fHelp || params.size() != 1)
1752 throw runtime_error(
1753 "validateaddress <ppcoinaddress>\n"
1754 "Return information about <ppcoinaddress>.");
1756 CBitcoinAddress address(params[0].get_str());
1757 bool isValid = address.IsValid();
1760 ret.push_back(Pair("isvalid", isValid));
1763 // Call Hash160ToAddress() so we always return current ADDRESSVERSION
1764 // version of the address:
1765 string currentAddress = address.ToString();
1766 ret.push_back(Pair("address", currentAddress));
1767 if (pwalletMain->HaveKey(address))
1769 ret.push_back(Pair("ismine", true));
1770 std::vector<unsigned char> vchPubKey;
1771 pwalletMain->GetPubKey(address, vchPubKey);
1772 ret.push_back(Pair("pubkey", HexStr(vchPubKey)));
1774 key.SetPubKey(vchPubKey);
1775 ret.push_back(Pair("iscompressed", key.IsCompressed()));
1777 else if (pwalletMain->HaveCScript(address.GetHash160()))
1779 ret.push_back(Pair("isscript", true));
1781 pwalletMain->GetCScript(address.GetHash160(), subscript);
1782 ret.push_back(Pair("ismine", ::IsMine(*pwalletMain, subscript)));
1783 std::vector<CBitcoinAddress> addresses;
1784 txnouttype whichType;
1786 ExtractAddresses(subscript, whichType, addresses, nRequired);
1787 ret.push_back(Pair("script", GetTxnOutputType(whichType)));
1789 BOOST_FOREACH(const CBitcoinAddress& addr, addresses)
1790 a.push_back(addr.ToString());
1791 ret.push_back(Pair("addresses", a));
1792 if (whichType == TX_MULTISIG)
1793 ret.push_back(Pair("sigsrequired", nRequired));
1796 ret.push_back(Pair("ismine", false));
1797 if (pwalletMain->mapAddressBook.count(address))
1798 ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
1803 Value getwork(const Array& params, bool fHelp)
1805 if (fHelp || params.size() > 1)
1806 throw runtime_error(
1808 "If [data] is not specified, returns formatted hash data to work on:\n"
1809 " \"midstate\" : precomputed hash state after hashing the first half of the data (DEPRECATED)\n" // deprecated
1810 " \"data\" : block data\n"
1811 " \"hash1\" : formatted hash buffer for second hash (DEPRECATED)\n" // deprecated
1812 " \"target\" : little endian hash target\n"
1813 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1816 throw JSONRPCError(-9, "PPCoin is not connected!");
1818 if (IsInitialBlockDownload())
1819 throw JSONRPCError(-10, "PPCoin is downloading blocks...");
1821 typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
1822 static mapNewBlock_t mapNewBlock;
1823 static vector<CBlock*> vNewBlock;
1824 static CReserveKey reservekey(pwalletMain);
1826 if (params.size() == 0)
1829 static unsigned int nTransactionsUpdatedLast;
1830 static CBlockIndex* pindexPrev;
1831 static int64 nStart;
1832 static CBlock* pblock;
1833 if (pindexPrev != pindexBest ||
1834 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
1836 if (pindexPrev != pindexBest)
1838 // Deallocate old blocks since they're obsolete now
1839 mapNewBlock.clear();
1840 BOOST_FOREACH(CBlock* pblock, vNewBlock)
1844 nTransactionsUpdatedLast = nTransactionsUpdated;
1845 pindexPrev = pindexBest;
1849 pblock = CreateNewBlock(pwalletMain);
1851 throw JSONRPCError(-7, "Out of memory");
1852 vNewBlock.push_back(pblock);
1856 pblock->UpdateTime(pindexPrev);
1859 // Update nExtraNonce
1860 static unsigned int nExtraNonce = 0;
1861 IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
1864 mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
1866 // Prebuild hash buffers
1870 FormatHashBuffers(pblock, pmidstate, pdata, phash1);
1872 uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
1875 result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate)))); // deprecated
1876 result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata))));
1877 result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1)))); // deprecated
1878 result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
1884 vector<unsigned char> vchData = ParseHex(params[0].get_str());
1885 if (vchData.size() != 128)
1886 throw JSONRPCError(-8, "Invalid parameter");
1887 CBlock* pdata = (CBlock*)&vchData[0];
1890 for (int i = 0; i < 128/4; i++)
1891 ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]);
1894 if (!mapNewBlock.count(pdata->hashMerkleRoot))
1896 CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
1898 pblock->nTime = pdata->nTime;
1899 pblock->nNonce = pdata->nNonce;
1900 pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
1901 pblock->hashMerkleRoot = pblock->BuildMerkleTree();
1902 if (!pblock->SignBlock(*pwalletMain))
1903 throw JSONRPCError(-100, "Unable to sign block, wallet locked?");
1905 return CheckWork(pblock, *pwalletMain, reservekey);
1910 Value getmemorypool(const Array& params, bool fHelp)
1912 if (fHelp || params.size() > 1)
1913 throw runtime_error(
1914 "getmemorypool [data]\n"
1915 "If [data] is not specified, returns data needed to construct a block to work on:\n"
1916 " \"version\" : block version\n"
1917 " \"previousblockhash\" : hash of current highest block\n"
1918 " \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
1919 " \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
1920 " \"coinbaseflags\" : data that should be included in coinbase so support for new features can be judged\n"
1921 " \"time\" : timestamp appropriate for next block\n"
1922 " \"mintime\" : minimum timestamp appropriate for next block\n"
1923 " \"curtime\" : current timestamp\n"
1924 " \"bits\" : compressed target of next block\n"
1925 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1927 if (params.size() == 0)
1930 throw JSONRPCError(-9, "PPCoin is not connected!");
1932 if (IsInitialBlockDownload())
1933 throw JSONRPCError(-10, "PPCoin is downloading blocks...");
1935 static CReserveKey reservekey(pwalletMain);
1938 static unsigned int nTransactionsUpdatedLast;
1939 static CBlockIndex* pindexPrev;
1940 static int64 nStart;
1941 static CBlock* pblock;
1942 if (pindexPrev != pindexBest ||
1943 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5))
1945 nTransactionsUpdatedLast = nTransactionsUpdated;
1946 pindexPrev = pindexBest;
1952 pblock = CreateNewBlock(pwalletMain);
1954 throw JSONRPCError(-7, "Out of memory");
1958 pblock->UpdateTime(pindexPrev);
1962 BOOST_FOREACH(CTransaction tx, pblock->vtx) {
1963 if(tx.IsCoinBase() || tx.IsCoinStake())
1966 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
1969 transactions.push_back(HexStr(ssTx.begin(), ssTx.end()));
1973 result.push_back(Pair("version", pblock->nVersion));
1974 result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
1975 result.push_back(Pair("transactions", transactions));
1976 result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
1977 result.push_back(Pair("coinbaseflags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end())));
1978 result.push_back(Pair("time", (int64_t)pblock->nTime));
1979 result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1));
1980 result.push_back(Pair("curtime", (int64_t)GetAdjustedTime()));
1981 result.push_back(Pair("bits", HexBits(pblock->nBits)));
1988 CDataStream ssBlock(ParseHex(params[0].get_str()), SER_NETWORK, PROTOCOL_VERSION);
1992 return ProcessBlock(NULL, &pblock);
1996 Value getblockhash(const Array& params, bool fHelp)
1998 if (fHelp || params.size() != 1)
1999 throw runtime_error(
2000 "getblockhash <index>\n"
2001 "Returns hash of block in best-block-chain at <index>.");
2003 int nHeight = params[0].get_int();
2004 if (nHeight < 0 || nHeight > nBestHeight)
2005 throw runtime_error("Block number out of range.");
2008 CBlockIndex* pblockindex = mapBlockIndex[hashBestChain];
2009 while (pblockindex->nHeight > nHeight)
2010 pblockindex = pblockindex->pprev;
2011 return pblockindex->phashBlock->GetHex();
2014 Value getblock(const Array& params, bool fHelp)
2016 if (fHelp || params.size() < 1 || params.size() > 2)
2017 throw runtime_error(
2018 "getblock <hash> [txinfo]\n"
2019 "txinfo optional to print more detailed tx info\n"
2020 "Returns details of a block with given block-hash.");
2022 std::string strHash = params[0].get_str();
2023 uint256 hash(strHash);
2025 if (mapBlockIndex.count(hash) == 0)
2026 throw JSONRPCError(-5, "Block not found");
2029 CBlockIndex* pblockindex = mapBlockIndex[hash];
2030 block.ReadFromDisk(pblockindex, true);
2032 return blockToJSON(block, pblockindex, params.size() > 1 ? params[1].get_bool() : false);
2036 // ppcoin: get information of sync-checkpoint
2037 Value getcheckpoint(const Array& params, bool fHelp)
2039 if (fHelp || params.size() != 0)
2040 throw runtime_error(
2042 "Show info of synchronized checkpoint.\n");
2045 CBlockIndex* pindexCheckpoint;
2047 result.push_back(Pair("synccheckpoint", Checkpoints::hashSyncCheckpoint.ToString().c_str()));
2048 pindexCheckpoint = mapBlockIndex[Checkpoints::hashSyncCheckpoint];
2049 result.push_back(Pair("height", pindexCheckpoint->nHeight));
2050 result.push_back(Pair("timestamp", DateTimeStrFormat(pindexCheckpoint->GetBlockTime()).c_str()));
2051 if (mapArgs.count("-checkpointkey"))
2052 result.push_back(Pair("checkpointmaster", true));
2058 // ppcoin: reserve balance from being staked for network protection
2059 Value reservebalance(const Array& params, bool fHelp)
2061 if (fHelp || params.size() > 2)
2062 throw runtime_error(
2063 "reservebalance [<reserve> [amount]]\n"
2064 "<reserve> is true or false to turn balance reserve on or off.\n"
2065 "<amount> is a real and rounded to cent.\n"
2066 "Set reserve amount not participating in network protection.\n"
2067 "If no parameters provided current setting is printed.\n");
2069 if (params.size() > 0)
2071 bool fReserve = params[0].get_bool();
2074 if (params.size() == 1)
2075 throw runtime_error("must provide amount to reserve balance.\n");
2076 int64 nAmount = AmountFromValue(params[1]);
2077 nAmount = (nAmount / CENT) * CENT; // round to cent
2079 throw runtime_error("amount cannot be negative.\n");
2080 mapArgs["-reservebalance"] = FormatMoney(nAmount).c_str();
2084 if (params.size() > 1)
2085 throw runtime_error("cannot specify amount to turn off reserve.\n");
2086 mapArgs["-reservebalance"] = "0";
2091 int64 nReserveBalance = 0;
2092 if (mapArgs.count("-reservebalance") && !ParseMoney(mapArgs["-reservebalance"], nReserveBalance))
2093 throw runtime_error("invalid reserve balance amount\n");
2094 result.push_back(Pair("reserve", (nReserveBalance > 0)));
2095 result.push_back(Pair("amount", ValueFromAmount(nReserveBalance)));
2100 // ppcoin: check wallet integrity
2101 Value checkwallet(const Array& params, bool fHelp)
2103 if (fHelp || params.size() > 0)
2104 throw runtime_error(
2106 "Check wallet for integrity.\n");
2109 int64 nBalanceInQuestion;
2111 if (pwalletMain->CheckSpentCoins(nMismatchSpent, nBalanceInQuestion))
2112 result.push_back(Pair("wallet check passed", true));
2115 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
2116 result.push_back(Pair("amount in question", ValueFromAmount(nBalanceInQuestion)));
2122 // ppcoin: repair wallet
2123 Value repairwallet(const Array& params, bool fHelp)
2125 if (fHelp || params.size() > 0)
2126 throw runtime_error(
2128 "Repair wallet if checkwallet reports any problem.\n");
2131 int64 nBalanceInQuestion;
2132 pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion);
2134 if (nMismatchSpent == 0)
2135 result.push_back(Pair("wallet check passed", true));
2138 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
2139 result.push_back(Pair("amount affected by repair", ValueFromAmount(nBalanceInQuestion)));
2144 // ppcoin: make a public-private key pair
2145 Value makekeypair(const Array& params, bool fHelp)
2147 if (fHelp || params.size() > 1)
2148 throw runtime_error(
2149 "makekeypair [prefix]\n"
2150 "Make a public/private key pair.\n"
2151 "[prefix] is optional preferred prefix for the public key.\n");
2153 string strPrefix = "";
2154 if (params.size() > 0)
2155 strPrefix = params[0].get_str();
2161 key.MakeNewKey(false);
2163 } while (nCount < 10000 && strPrefix != HexStr(key.GetPubKey()).substr(0, strPrefix.size()));
2165 if (strPrefix != HexStr(key.GetPubKey()).substr(0, strPrefix.size()))
2168 CPrivKey vchPrivKey = key.GetPrivKey();
2170 result.push_back(Pair("PrivateKey", HexStr<CPrivKey::iterator>(vchPrivKey.begin(), vchPrivKey.end())));
2171 result.push_back(Pair("PublicKey", HexStr(key.GetPubKey())));
2175 extern CCriticalSection cs_mapAlerts;
2176 extern map<uint256, CAlert> mapAlerts;
2178 // ppcoin: send alert.
2179 // There is a known deadlock situation with ThreadMessageHandler
2180 // ThreadMessageHandler: holds cs_vSend and acquiring cs_main in SendMessages()
2181 // ThreadRPCServer: holds cs_main and acquiring cs_vSend in alert.RelayTo()/PushMessage()/BeginMessage()
2182 Value sendalert(const Array& params, bool fHelp)
2184 if (fHelp || params.size() < 6)
2185 throw runtime_error(
2186 "sendalert <message> <privatekey> <minver> <maxver> <priority> <id> [cancelupto]\n"
2187 "<message> is the alert text message\n"
2188 "<privatekey> is hex string of alert master private key\n"
2189 "<minver> is the minimum applicable internal client version\n"
2190 "<maxver> is the maximum applicable internal client version\n"
2191 "<priority> is integer priority number\n"
2192 "<id> is the alert id\n"
2193 "[cancelupto] cancels all alert id's up to this number\n"
2194 "Returns true or false.");
2199 alert.strStatusBar = params[0].get_str();
2200 alert.nMinVer = params[2].get_int();
2201 alert.nMaxVer = params[3].get_int();
2202 alert.nPriority = params[4].get_int();
2203 alert.nID = params[5].get_int();
2204 if (params.size() > 6)
2205 alert.nCancel = params[6].get_int();
2206 alert.nVersion = PROTOCOL_VERSION;
2207 alert.nRelayUntil = GetAdjustedTime() + 365*24*60*60;
2208 alert.nExpiration = GetAdjustedTime() + 365*24*60*60;
2210 CDataStream sMsg(SER_NETWORK, PROTOCOL_VERSION);
2211 sMsg << (CUnsignedAlert)alert;
2212 alert.vchMsg = vector<unsigned char>(sMsg.begin(), sMsg.end());
2214 vector<unsigned char> vchPrivKey = ParseHex(params[1].get_str());
2215 key.SetPrivKey(CPrivKey(vchPrivKey.begin(), vchPrivKey.end())); // if key is not correct openssl may crash
2216 if (!key.Sign(Hash(alert.vchMsg.begin(), alert.vchMsg.end()), alert.vchSig))
2217 throw runtime_error(
2218 "Unable to sign alert, check private key?\n");
2219 if(!alert.ProcessAlert())
2220 throw runtime_error(
2221 "Failed to process alert.\n");
2225 BOOST_FOREACH(CNode* pnode, vNodes)
2226 alert.RelayTo(pnode);
2230 result.push_back(Pair("strStatusBar", alert.strStatusBar));
2231 result.push_back(Pair("nVersion", alert.nVersion));
2232 result.push_back(Pair("nMinVer", alert.nMinVer));
2233 result.push_back(Pair("nMaxVer", alert.nMaxVer));
2234 result.push_back(Pair("nPriority", alert.nPriority));
2235 result.push_back(Pair("nID", alert.nID));
2236 if (alert.nCancel > 0)
2237 result.push_back(Pair("nCancel", alert.nCancel));
2248 static const CRPCCommand vRPCCommands[] =
2249 { // name function safe mode?
2250 // ------------------------ ----------------------- ----------
2251 { "help", &help, true },
2252 { "stop", &stop, true },
2253 { "getblockcount", &getblockcount, true },
2254 { "getblocknumber", &getblocknumber, true },
2255 { "getconnectioncount", &getconnectioncount, true },
2256 { "getdifficulty", &getdifficulty, true },
2257 { "getgenerate", &getgenerate, true },
2258 { "setgenerate", &setgenerate, true },
2259 { "gethashespersec", &gethashespersec, true },
2260 { "getinfo", &getinfo, true },
2261 { "getmininginfo", &getmininginfo, true },
2262 { "getnewaddress", &getnewaddress, true },
2263 { "getaccountaddress", &getaccountaddress, true },
2264 { "setaccount", &setaccount, true },
2265 { "getaccount", &getaccount, false },
2266 { "getaddressesbyaccount", &getaddressesbyaccount, true },
2267 { "sendtoaddress", &sendtoaddress, false },
2268 { "getreceivedbyaddress", &getreceivedbyaddress, false },
2269 { "getreceivedbyaccount", &getreceivedbyaccount, false },
2270 { "listreceivedbyaddress", &listreceivedbyaddress, false },
2271 { "listreceivedbyaccount", &listreceivedbyaccount, false },
2272 { "backupwallet", &backupwallet, true },
2273 { "keypoolrefill", &keypoolrefill, true },
2274 { "walletpassphrase", &walletpassphrase, true },
2275 { "walletpassphrasechange", &walletpassphrasechange, false },
2276 { "walletlock", &walletlock, true },
2277 { "encryptwallet", &encryptwallet, false },
2278 { "validateaddress", &validateaddress, true },
2279 { "getbalance", &getbalance, false },
2280 { "move", &movecmd, false },
2281 { "sendfrom", &sendfrom, false },
2282 { "sendmany", &sendmany, false },
2283 { "addmultisigaddress", &addmultisigaddress, false },
2284 { "getblock", &getblock, false },
2285 { "getblockhash", &getblockhash, false },
2286 { "gettransaction", &gettransaction, false },
2287 { "listtransactions", &listtransactions, false },
2288 { "signmessage", &signmessage, false },
2289 { "verifymessage", &verifymessage, false },
2290 { "getwork", &getwork, true },
2291 { "listaccounts", &listaccounts, false },
2292 { "settxfee", &settxfee, false },
2293 { "getmemorypool", &getmemorypool, true },
2294 { "listsinceblock", &listsinceblock, false },
2295 { "dumpprivkey", &dumpprivkey, false },
2296 { "importprivkey", &importprivkey, false },
2297 { "getcheckpoint", &getcheckpoint, true },
2298 { "reservebalance", &reservebalance, false},
2299 { "checkwallet", &checkwallet, false},
2300 { "repairwallet", &repairwallet, false},
2301 { "makekeypair", &makekeypair, false},
2302 { "sendalert", &sendalert, false},
2305 CRPCTable::CRPCTable()
2308 for (vcidx = 0; vcidx < (sizeof(vRPCCommands) / sizeof(vRPCCommands[0])); vcidx++)
2310 const CRPCCommand *pcmd;
2312 pcmd = &vRPCCommands[vcidx];
2313 mapCommands[pcmd->name] = pcmd;
2317 const CRPCCommand *CRPCTable::operator[](string name) const
2319 map<string, const CRPCCommand*>::const_iterator it = mapCommands.find(name);
2320 if (it == mapCommands.end())
2322 return (*it).second;
2328 // This ain't Apache. We're just using HTTP header for the length field
2329 // and to be compatible with other JSON-RPC implementations.
2332 string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
2335 s << "POST / HTTP/1.1\r\n"
2336 << "User-Agent: ppcoin-json-rpc/" << FormatFullVersion() << "\r\n"
2337 << "Host: 127.0.0.1\r\n"
2338 << "Content-Type: application/json\r\n"
2339 << "Content-Length: " << strMsg.size() << "\r\n"
2340 << "Connection: close\r\n"
2341 << "Accept: application/json\r\n";
2342 BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
2343 s << item.first << ": " << item.second << "\r\n";
2344 s << "\r\n" << strMsg;
2349 string rfc1123Time()
2354 struct tm* now_gmt = gmtime(&now);
2355 string locale(setlocale(LC_TIME, NULL));
2356 setlocale(LC_TIME, "C"); // we want posix (aka "C") weekday/month strings
2357 strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt);
2358 setlocale(LC_TIME, locale.c_str());
2359 return string(buffer);
2362 static string HTTPReply(int nStatus, const string& strMsg)
2365 return strprintf("HTTP/1.0 401 Authorization Required\r\n"
2367 "Server: ppcoin-json-rpc/%s\r\n"
2368 "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
2369 "Content-Type: text/html\r\n"
2370 "Content-Length: 296\r\n"
2372 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
2373 "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
2376 "<TITLE>Error</TITLE>\r\n"
2377 "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
2379 "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
2380 "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
2381 const char *cStatus;
2382 if (nStatus == 200) cStatus = "OK";
2383 else if (nStatus == 400) cStatus = "Bad Request";
2384 else if (nStatus == 403) cStatus = "Forbidden";
2385 else if (nStatus == 404) cStatus = "Not Found";
2386 else if (nStatus == 500) cStatus = "Internal Server Error";
2389 "HTTP/1.1 %d %s\r\n"
2391 "Connection: close\r\n"
2392 "Content-Length: %d\r\n"
2393 "Content-Type: application/json\r\n"
2394 "Server: ppcoin-json-rpc/%s\r\n"
2399 rfc1123Time().c_str(),
2401 FormatFullVersion().c_str(),
2405 int ReadHTTPStatus(std::basic_istream<char>& stream)
2408 getline(stream, str);
2409 vector<string> vWords;
2410 boost::split(vWords, str, boost::is_any_of(" "));
2411 if (vWords.size() < 2)
2413 return atoi(vWords[1].c_str());
2416 int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
2422 std::getline(stream, str);
2423 if (str.empty() || str == "\r")
2425 string::size_type nColon = str.find(":");
2426 if (nColon != string::npos)
2428 string strHeader = str.substr(0, nColon);
2429 boost::trim(strHeader);
2430 boost::to_lower(strHeader);
2431 string strValue = str.substr(nColon+1);
2432 boost::trim(strValue);
2433 mapHeadersRet[strHeader] = strValue;
2434 if (strHeader == "content-length")
2435 nLen = atoi(strValue.c_str());
2441 int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
2443 mapHeadersRet.clear();
2447 int nStatus = ReadHTTPStatus(stream);
2450 int nLen = ReadHTTPHeader(stream, mapHeadersRet);
2451 if (nLen < 0 || nLen > (int)MAX_SIZE)
2457 vector<char> vch(nLen);
2458 stream.read(&vch[0], nLen);
2459 strMessageRet = string(vch.begin(), vch.end());
2465 bool HTTPAuthorized(map<string, string>& mapHeaders)
2467 string strAuth = mapHeaders["authorization"];
2468 if (strAuth.substr(0,6) != "Basic ")
2470 string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
2471 string strUserPass = DecodeBase64(strUserPass64);
2472 return strUserPass == strRPCUserColonPass;
2476 // JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
2477 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
2478 // unspecified (HTTP errors and contents of 'error').
2480 // 1.0 spec: http://json-rpc.org/wiki/specification
2481 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
2482 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
2485 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
2488 request.push_back(Pair("method", strMethod));
2489 request.push_back(Pair("params", params));
2490 request.push_back(Pair("id", id));
2491 return write_string(Value(request), false) + "\n";
2494 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
2497 if (error.type() != null_type)
2498 reply.push_back(Pair("result", Value::null));
2500 reply.push_back(Pair("result", result));
2501 reply.push_back(Pair("error", error));
2502 reply.push_back(Pair("id", id));
2503 return write_string(Value(reply), false) + "\n";
2506 void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
2508 // Send error reply from json-rpc error object
2510 int code = find_value(objError, "code").get_int();
2511 if (code == -32600) nStatus = 400;
2512 else if (code == -32601) nStatus = 404;
2513 string strReply = JSONRPCReply(Value::null, objError, id);
2514 stream << HTTPReply(nStatus, strReply) << std::flush;
2517 bool ClientAllowed(const string& strAddress)
2519 if (strAddress == asio::ip::address_v4::loopback().to_string())
2521 const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
2522 BOOST_FOREACH(string strAllow, vAllow)
2523 if (WildcardMatch(strAddress, strAllow))
2529 // IOStream device that speaks SSL but can also speak non-SSL
2531 class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
2533 SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
2535 fUseSSL = fUseSSLIn;
2536 fNeedHandshake = fUseSSLIn;
2539 void handshake(ssl::stream_base::handshake_type role)
2541 if (!fNeedHandshake) return;
2542 fNeedHandshake = false;
2543 stream.handshake(role);
2545 std::streamsize read(char* s, std::streamsize n)
2547 handshake(ssl::stream_base::server); // HTTPS servers read first
2548 if (fUseSSL) return stream.read_some(asio::buffer(s, n));
2549 return stream.next_layer().read_some(asio::buffer(s, n));
2551 std::streamsize write(const char* s, std::streamsize n)
2553 handshake(ssl::stream_base::client); // HTTPS clients write first
2554 if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
2555 return asio::write(stream.next_layer(), asio::buffer(s, n));
2557 bool connect(const std::string& server, const std::string& port)
2559 ip::tcp::resolver resolver(stream.get_io_service());
2560 ip::tcp::resolver::query query(server.c_str(), port.c_str());
2561 ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
2562 ip::tcp::resolver::iterator end;
2563 boost::system::error_code error = asio::error::host_not_found;
2564 while (error && endpoint_iterator != end)
2566 stream.lowest_layer().close();
2567 stream.lowest_layer().connect(*endpoint_iterator++, error);
2575 bool fNeedHandshake;
2580 void ThreadRPCServer(void* parg)
2582 IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
2585 vnThreadsRunning[THREAD_RPCSERVER]++;
2586 ThreadRPCServer2(parg);
2587 vnThreadsRunning[THREAD_RPCSERVER]--;
2589 catch (std::exception& e) {
2590 vnThreadsRunning[THREAD_RPCSERVER]--;
2591 PrintException(&e, "ThreadRPCServer()");
2593 vnThreadsRunning[THREAD_RPCSERVER]--;
2594 PrintException(NULL, "ThreadRPCServer()");
2596 printf("ThreadRPCServer exiting\n");
2599 void ThreadRPCServer2(void* parg)
2601 printf("ThreadRPCServer started\n");
2603 strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
2604 if (mapArgs["-rpcpassword"] == "")
2606 unsigned char rand_pwd[32];
2607 RAND_bytes(rand_pwd, 32);
2608 string strWhatAmI = "To use ppcoind";
2609 if (mapArgs.count("-server"))
2610 strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
2611 else if (mapArgs.count("-daemon"))
2612 strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
2613 ThreadSafeMessageBox(strprintf(
2614 _("%s, you must set a rpcpassword in the configuration file:\n %s\n"
2615 "It is recommended you use the following random password:\n"
2616 "rpcuser=bitcoinrpc\n"
2618 "(you do not need to remember this password)\n"
2619 "If the file does not exist, create it with owner-readable-only file permissions.\n"),
2621 GetConfigFile().string().c_str(),
2622 EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str()),
2623 _("Error"), wxOK | wxMODAL);
2628 bool fUseSSL = GetBoolArg("-rpcssl");
2629 asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
2631 asio::io_service io_service;
2632 ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", RPC_PORT));
2633 ip::tcp::acceptor acceptor(io_service);
2636 acceptor.open(endpoint.protocol());
2637 acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
2638 acceptor.bind(endpoint);
2639 acceptor.listen(socket_base::max_connections);
2641 catch(boost::system::system_error &e)
2643 ThreadSafeMessageBox(strprintf(_("An error occured while setting up the RPC port %i for listening: %s"), endpoint.port(), e.what()),
2644 _("Error"), wxOK | wxMODAL);
2649 ssl::context context(io_service, ssl::context::sslv23);
2652 context.set_options(ssl::context::no_sslv2);
2654 filesystem::path pathCertFile(GetArg("-rpcsslcertificatechainfile", "server.cert"));
2655 if (!pathCertFile.is_complete()) pathCertFile = filesystem::path(GetDataDir()) / pathCertFile;
2656 if (filesystem::exists(pathCertFile)) context.use_certificate_chain_file(pathCertFile.string());
2657 else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", pathCertFile.string().c_str());
2659 filesystem::path pathPKFile(GetArg("-rpcsslprivatekeyfile", "server.pem"));
2660 if (!pathPKFile.is_complete()) pathPKFile = filesystem::path(GetDataDir()) / pathPKFile;
2661 if (filesystem::exists(pathPKFile)) context.use_private_key_file(pathPKFile.string(), ssl::context::pem);
2662 else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pathPKFile.string().c_str());
2664 string strCiphers = GetArg("-rpcsslciphers", "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
2665 SSL_CTX_set_cipher_list(context.impl(), strCiphers.c_str());
2670 // Accept connection
2671 SSLStream sslStream(io_service, context);
2672 SSLIOStreamDevice d(sslStream, fUseSSL);
2673 iostreams::stream<SSLIOStreamDevice> stream(d);
2675 ip::tcp::endpoint peer;
2676 vnThreadsRunning[THREAD_RPCSERVER]--;
2677 acceptor.accept(sslStream.lowest_layer(), peer);
2678 vnThreadsRunning[4]++;
2682 // Restrict callers by IP
2683 if (!ClientAllowed(peer.address().to_string()))
2685 // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
2687 stream << HTTPReply(403, "") << std::flush;
2691 map<string, string> mapHeaders;
2694 boost::thread api_caller(ReadHTTP, boost::ref(stream), boost::ref(mapHeaders), boost::ref(strRequest));
2695 if (!api_caller.timed_join(boost::posix_time::seconds(GetArg("-rpctimeout", 30))))
2698 printf("ThreadRPCServer ReadHTTP timeout\n");
2702 // Check authorization
2703 if (mapHeaders.count("authorization") == 0)
2705 stream << HTTPReply(401, "") << std::flush;
2708 if (!HTTPAuthorized(mapHeaders))
2710 printf("ThreadRPCServer incorrect password attempt from %s\n",peer.address().to_string().c_str());
2711 /* Deter brute-forcing short passwords.
2712 If this results in a DOS the user really
2713 shouldn't have their RPC port exposed.*/
2714 if (mapArgs["-rpcpassword"].size() < 20)
2717 stream << HTTPReply(401, "") << std::flush;
2721 Value id = Value::null;
2726 if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
2727 throw JSONRPCError(-32700, "Parse error");
2728 const Object& request = valRequest.get_obj();
2730 // Parse id now so errors from here on will have the id
2731 id = find_value(request, "id");
2734 Value valMethod = find_value(request, "method");
2735 if (valMethod.type() == null_type)
2736 throw JSONRPCError(-32600, "Missing method");
2737 if (valMethod.type() != str_type)
2738 throw JSONRPCError(-32600, "Method must be a string");
2739 string strMethod = valMethod.get_str();
2740 if (strMethod != "getwork" && strMethod != "getmemorypool")
2741 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
2744 Value valParams = find_value(request, "params");
2746 if (valParams.type() == array_type)
2747 params = valParams.get_array();
2748 else if (valParams.type() == null_type)
2751 throw JSONRPCError(-32600, "Params must be an array");
2754 const CRPCCommand *pcmd = tableRPC[strMethod];
2756 throw JSONRPCError(-32601, "Method not found");
2758 // Observe safe mode
2759 string strWarning = GetWarnings("rpc");
2760 if (strWarning != "" && !GetBoolArg("-disablesafemode") &&
2762 throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
2769 LOCK2(cs_main, pwalletMain->cs_wallet);
2770 result = pcmd->actor(params, false);
2774 string strReply = JSONRPCReply(result, Value::null, id);
2775 stream << HTTPReply(200, strReply) << std::flush;
2777 catch (std::exception& e)
2779 ErrorReply(stream, JSONRPCError(-1, e.what()), id);
2782 catch (Object& objError)
2784 ErrorReply(stream, objError, id);
2786 catch (std::exception& e)
2788 ErrorReply(stream, JSONRPCError(-32700, e.what()), id);
2796 Object CallRPC(const string& strMethod, const Array& params)
2798 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2799 throw runtime_error(strprintf(
2800 _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
2801 "If the file does not exist, create it with owner-readable-only file permissions."),
2802 GetConfigFile().string().c_str()));
2804 // Connect to localhost
2805 bool fUseSSL = GetBoolArg("-rpcssl");
2806 asio::io_service io_service;
2807 ssl::context context(io_service, ssl::context::sslv23);
2808 context.set_options(ssl::context::no_sslv2);
2809 SSLStream sslStream(io_service, context);
2810 SSLIOStreamDevice d(sslStream, fUseSSL);
2811 iostreams::stream<SSLIOStreamDevice> stream(d);
2812 if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", CBigNum(RPC_PORT).ToString().c_str())))
2813 throw runtime_error("couldn't connect to server");
2815 // HTTP basic authentication
2816 string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
2817 map<string, string> mapRequestHeaders;
2818 mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
2821 string strRequest = JSONRPCRequest(strMethod, params, 1);
2822 string strPost = HTTPPost(strRequest, mapRequestHeaders);
2823 stream << strPost << std::flush;
2826 map<string, string> mapHeaders;
2828 int nStatus = ReadHTTP(stream, mapHeaders, strReply);
2830 throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
2831 else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
2832 throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
2833 else if (strReply.empty())
2834 throw runtime_error("no response from server");
2838 if (!read_string(strReply, valReply))
2839 throw runtime_error("couldn't parse reply from server");
2840 const Object& reply = valReply.get_obj();
2842 throw runtime_error("expected reply to have result, error and id properties");
2850 template<typename T>
2851 void ConvertTo(Value& value)
2853 if (value.type() == str_type)
2855 // reinterpret string as unquoted json value
2857 if (!read_string(value.get_str(), value2))
2858 throw runtime_error("type mismatch");
2859 value = value2.get_value<T>();
2863 value = value.get_value<T>();
2867 int CommandLineRPC(int argc, char *argv[])
2874 while (argc > 1 && IsSwitchChar(argv[1][0]))
2882 throw runtime_error("too few parameters");
2883 string strMethod = argv[1];
2885 // Parameters default to strings
2887 for (int i = 2; i < argc; i++)
2888 params.push_back(argv[i]);
2889 int n = params.size();
2892 // Special case non-string parameter types
2894 if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
2895 if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2896 if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
2897 if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]);
2898 if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2899 if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2900 if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2901 if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
2902 if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2903 if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
2904 if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2905 if (strMethod == "getblockhash" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2906 if (strMethod == "getblock" && n > 1) ConvertTo<bool>(params[1]);
2907 if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]);
2908 if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2909 if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]);
2910 if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2911 if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2912 if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2913 if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2914 if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2915 if (strMethod == "walletpassphrase" && n > 2) ConvertTo<bool>(params[2]);
2916 if (strMethod == "listsinceblock" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2917 if (strMethod == "sendalert" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2918 if (strMethod == "sendalert" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2919 if (strMethod == "sendalert" && n > 4) ConvertTo<boost::int64_t>(params[4]);
2920 if (strMethod == "sendalert" && n > 5) ConvertTo<boost::int64_t>(params[5]);
2921 if (strMethod == "sendalert" && n > 6) ConvertTo<boost::int64_t>(params[6]);
2922 if (strMethod == "sendmany" && n > 1)
2924 string s = params[1].get_str();
2926 if (!read_string(s, v) || v.type() != obj_type)
2927 throw runtime_error("type mismatch");
2928 params[1] = v.get_obj();
2930 if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2931 if (strMethod == "reservebalance" && n > 0) ConvertTo<bool>(params[0]);
2932 if (strMethod == "reservebalance" && n > 1) ConvertTo<double>(params[1]);
2933 if (strMethod == "addmultisigaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2934 if (strMethod == "addmultisigaddress" && n > 1)
2936 string s = params[1].get_str();
2938 if (!read_string(s, v) || v.type() != array_type)
2939 throw runtime_error("type mismatch "+s);
2940 params[1] = v.get_array();
2944 Object reply = CallRPC(strMethod, params);
2947 const Value& result = find_value(reply, "result");
2948 const Value& error = find_value(reply, "error");
2950 if (error.type() != null_type)
2953 strPrint = "error: " + write_string(error, false);
2954 int code = find_value(error.get_obj(), "code").get_int();
2960 if (result.type() == null_type)
2962 else if (result.type() == str_type)
2963 strPrint = result.get_str();
2965 strPrint = write_string(result, true);
2968 catch (std::exception& e)
2970 strPrint = string("error: ") + e.what();
2975 PrintException(NULL, "CommandLineRPC()");
2980 fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
2989 int main(int argc, char *argv[])
2992 // Turn off microsoft heap dump noise
2993 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
2994 _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
2996 setbuf(stdin, NULL);
2997 setbuf(stdout, NULL);
2998 setbuf(stderr, NULL);
3002 if (argc >= 2 && string(argv[1]) == "-server")
3004 printf("server ready\n");
3005 ThreadRPCServer(NULL);
3009 return CommandLineRPC(argc, argv);
3012 catch (std::exception& e) {
3013 PrintException(&e, "main()");
3015 PrintException(NULL, "main()");
3021 const CRPCTable tableRPC;