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;
2110 pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion, true);
2112 if (nMismatchSpent == 0)
2113 result.push_back(Pair("wallet check passed", true));
2116 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
2117 result.push_back(Pair("amount in question", ValueFromAmount(nBalanceInQuestion)));
2123 // ppcoin: repair wallet
2124 Value repairwallet(const Array& params, bool fHelp)
2126 if (fHelp || params.size() > 0)
2127 throw runtime_error(
2129 "Repair wallet if checkwallet reports any problem.\n");
2132 int64 nBalanceInQuestion;
2133 pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion);
2135 if (nMismatchSpent == 0)
2136 result.push_back(Pair("wallet check passed", true));
2139 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
2140 result.push_back(Pair("amount affected by repair", ValueFromAmount(nBalanceInQuestion)));
2145 // ppcoin: make a public-private key pair
2146 Value makekeypair(const Array& params, bool fHelp)
2148 if (fHelp || params.size() > 1)
2149 throw runtime_error(
2150 "makekeypair [prefix]\n"
2151 "Make a public/private key pair.\n"
2152 "[prefix] is optional preferred prefix for the public key.\n");
2154 string strPrefix = "";
2155 if (params.size() > 0)
2156 strPrefix = params[0].get_str();
2162 key.MakeNewKey(false);
2164 } while (nCount < 10000 && strPrefix != HexStr(key.GetPubKey()).substr(0, strPrefix.size()));
2166 if (strPrefix != HexStr(key.GetPubKey()).substr(0, strPrefix.size()))
2169 CPrivKey vchPrivKey = key.GetPrivKey();
2171 result.push_back(Pair("PrivateKey", HexStr<CPrivKey::iterator>(vchPrivKey.begin(), vchPrivKey.end())));
2172 result.push_back(Pair("PublicKey", HexStr(key.GetPubKey())));
2176 extern CCriticalSection cs_mapAlerts;
2177 extern map<uint256, CAlert> mapAlerts;
2179 // ppcoin: send alert.
2180 // There is a known deadlock situation with ThreadMessageHandler
2181 // ThreadMessageHandler: holds cs_vSend and acquiring cs_main in SendMessages()
2182 // ThreadRPCServer: holds cs_main and acquiring cs_vSend in alert.RelayTo()/PushMessage()/BeginMessage()
2183 Value sendalert(const Array& params, bool fHelp)
2185 if (fHelp || params.size() < 6)
2186 throw runtime_error(
2187 "sendalert <message> <privatekey> <minver> <maxver> <priority> <id> [cancelupto]\n"
2188 "<message> is the alert text message\n"
2189 "<privatekey> is hex string of alert master private key\n"
2190 "<minver> is the minimum applicable internal client version\n"
2191 "<maxver> is the maximum applicable internal client version\n"
2192 "<priority> is integer priority number\n"
2193 "<id> is the alert id\n"
2194 "[cancelupto] cancels all alert id's up to this number\n"
2195 "Returns true or false.");
2200 alert.strStatusBar = params[0].get_str();
2201 alert.nMinVer = params[2].get_int();
2202 alert.nMaxVer = params[3].get_int();
2203 alert.nPriority = params[4].get_int();
2204 alert.nID = params[5].get_int();
2205 if (params.size() > 6)
2206 alert.nCancel = params[6].get_int();
2207 alert.nVersion = PROTOCOL_VERSION;
2208 alert.nRelayUntil = GetAdjustedTime() + 365*24*60*60;
2209 alert.nExpiration = GetAdjustedTime() + 365*24*60*60;
2211 CDataStream sMsg(SER_NETWORK, PROTOCOL_VERSION);
2212 sMsg << (CUnsignedAlert)alert;
2213 alert.vchMsg = vector<unsigned char>(sMsg.begin(), sMsg.end());
2215 vector<unsigned char> vchPrivKey = ParseHex(params[1].get_str());
2216 key.SetPrivKey(CPrivKey(vchPrivKey.begin(), vchPrivKey.end())); // if key is not correct openssl may crash
2217 if (!key.Sign(Hash(alert.vchMsg.begin(), alert.vchMsg.end()), alert.vchSig))
2218 throw runtime_error(
2219 "Unable to sign alert, check private key?\n");
2220 if(!alert.ProcessAlert())
2221 throw runtime_error(
2222 "Failed to process alert.\n");
2226 BOOST_FOREACH(CNode* pnode, vNodes)
2227 alert.RelayTo(pnode);
2231 result.push_back(Pair("strStatusBar", alert.strStatusBar));
2232 result.push_back(Pair("nVersion", alert.nVersion));
2233 result.push_back(Pair("nMinVer", alert.nMinVer));
2234 result.push_back(Pair("nMaxVer", alert.nMaxVer));
2235 result.push_back(Pair("nPriority", alert.nPriority));
2236 result.push_back(Pair("nID", alert.nID));
2237 if (alert.nCancel > 0)
2238 result.push_back(Pair("nCancel", alert.nCancel));
2249 static const CRPCCommand vRPCCommands[] =
2250 { // name function safe mode?
2251 // ------------------------ ----------------------- ----------
2252 { "help", &help, true },
2253 { "stop", &stop, true },
2254 { "getblockcount", &getblockcount, true },
2255 { "getblocknumber", &getblocknumber, true },
2256 { "getconnectioncount", &getconnectioncount, true },
2257 { "getdifficulty", &getdifficulty, true },
2258 { "getgenerate", &getgenerate, true },
2259 { "setgenerate", &setgenerate, true },
2260 { "gethashespersec", &gethashespersec, true },
2261 { "getinfo", &getinfo, true },
2262 { "getmininginfo", &getmininginfo, true },
2263 { "getnewaddress", &getnewaddress, true },
2264 { "getaccountaddress", &getaccountaddress, true },
2265 { "setaccount", &setaccount, true },
2266 { "getaccount", &getaccount, false },
2267 { "getaddressesbyaccount", &getaddressesbyaccount, true },
2268 { "sendtoaddress", &sendtoaddress, false },
2269 { "getreceivedbyaddress", &getreceivedbyaddress, false },
2270 { "getreceivedbyaccount", &getreceivedbyaccount, false },
2271 { "listreceivedbyaddress", &listreceivedbyaddress, false },
2272 { "listreceivedbyaccount", &listreceivedbyaccount, false },
2273 { "backupwallet", &backupwallet, true },
2274 { "keypoolrefill", &keypoolrefill, true },
2275 { "walletpassphrase", &walletpassphrase, true },
2276 { "walletpassphrasechange", &walletpassphrasechange, false },
2277 { "walletlock", &walletlock, true },
2278 { "encryptwallet", &encryptwallet, false },
2279 { "validateaddress", &validateaddress, true },
2280 { "getbalance", &getbalance, false },
2281 { "move", &movecmd, false },
2282 { "sendfrom", &sendfrom, false },
2283 { "sendmany", &sendmany, false },
2284 { "addmultisigaddress", &addmultisigaddress, false },
2285 { "getblock", &getblock, false },
2286 { "getblockhash", &getblockhash, false },
2287 { "gettransaction", &gettransaction, false },
2288 { "listtransactions", &listtransactions, false },
2289 { "signmessage", &signmessage, false },
2290 { "verifymessage", &verifymessage, false },
2291 { "getwork", &getwork, true },
2292 { "listaccounts", &listaccounts, false },
2293 { "settxfee", &settxfee, false },
2294 { "getmemorypool", &getmemorypool, true },
2295 { "listsinceblock", &listsinceblock, false },
2296 { "dumpprivkey", &dumpprivkey, false },
2297 { "importprivkey", &importprivkey, false },
2298 { "getcheckpoint", &getcheckpoint, true },
2299 { "reservebalance", &reservebalance, false},
2300 { "checkwallet", &checkwallet, false},
2301 { "repairwallet", &repairwallet, false},
2302 { "makekeypair", &makekeypair, false},
2303 { "sendalert", &sendalert, false},
2306 CRPCTable::CRPCTable()
2309 for (vcidx = 0; vcidx < (sizeof(vRPCCommands) / sizeof(vRPCCommands[0])); vcidx++)
2311 const CRPCCommand *pcmd;
2313 pcmd = &vRPCCommands[vcidx];
2314 mapCommands[pcmd->name] = pcmd;
2318 const CRPCCommand *CRPCTable::operator[](string name) const
2320 map<string, const CRPCCommand*>::const_iterator it = mapCommands.find(name);
2321 if (it == mapCommands.end())
2323 return (*it).second;
2329 // This ain't Apache. We're just using HTTP header for the length field
2330 // and to be compatible with other JSON-RPC implementations.
2333 string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
2336 s << "POST / HTTP/1.1\r\n"
2337 << "User-Agent: ppcoin-json-rpc/" << FormatFullVersion() << "\r\n"
2338 << "Host: 127.0.0.1\r\n"
2339 << "Content-Type: application/json\r\n"
2340 << "Content-Length: " << strMsg.size() << "\r\n"
2341 << "Connection: close\r\n"
2342 << "Accept: application/json\r\n";
2343 BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
2344 s << item.first << ": " << item.second << "\r\n";
2345 s << "\r\n" << strMsg;
2350 string rfc1123Time()
2355 struct tm* now_gmt = gmtime(&now);
2356 string locale(setlocale(LC_TIME, NULL));
2357 setlocale(LC_TIME, "C"); // we want posix (aka "C") weekday/month strings
2358 strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt);
2359 setlocale(LC_TIME, locale.c_str());
2360 return string(buffer);
2363 static string HTTPReply(int nStatus, const string& strMsg)
2366 return strprintf("HTTP/1.0 401 Authorization Required\r\n"
2368 "Server: ppcoin-json-rpc/%s\r\n"
2369 "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
2370 "Content-Type: text/html\r\n"
2371 "Content-Length: 296\r\n"
2373 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
2374 "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
2377 "<TITLE>Error</TITLE>\r\n"
2378 "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
2380 "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
2381 "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
2382 const char *cStatus;
2383 if (nStatus == 200) cStatus = "OK";
2384 else if (nStatus == 400) cStatus = "Bad Request";
2385 else if (nStatus == 403) cStatus = "Forbidden";
2386 else if (nStatus == 404) cStatus = "Not Found";
2387 else if (nStatus == 500) cStatus = "Internal Server Error";
2390 "HTTP/1.1 %d %s\r\n"
2392 "Connection: close\r\n"
2393 "Content-Length: %d\r\n"
2394 "Content-Type: application/json\r\n"
2395 "Server: ppcoin-json-rpc/%s\r\n"
2400 rfc1123Time().c_str(),
2402 FormatFullVersion().c_str(),
2406 int ReadHTTPStatus(std::basic_istream<char>& stream)
2409 getline(stream, str);
2410 vector<string> vWords;
2411 boost::split(vWords, str, boost::is_any_of(" "));
2412 if (vWords.size() < 2)
2414 return atoi(vWords[1].c_str());
2417 int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
2423 std::getline(stream, str);
2424 if (str.empty() || str == "\r")
2426 string::size_type nColon = str.find(":");
2427 if (nColon != string::npos)
2429 string strHeader = str.substr(0, nColon);
2430 boost::trim(strHeader);
2431 boost::to_lower(strHeader);
2432 string strValue = str.substr(nColon+1);
2433 boost::trim(strValue);
2434 mapHeadersRet[strHeader] = strValue;
2435 if (strHeader == "content-length")
2436 nLen = atoi(strValue.c_str());
2442 int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
2444 mapHeadersRet.clear();
2448 int nStatus = ReadHTTPStatus(stream);
2451 int nLen = ReadHTTPHeader(stream, mapHeadersRet);
2452 if (nLen < 0 || nLen > (int)MAX_SIZE)
2458 vector<char> vch(nLen);
2459 stream.read(&vch[0], nLen);
2460 strMessageRet = string(vch.begin(), vch.end());
2466 bool HTTPAuthorized(map<string, string>& mapHeaders)
2468 string strAuth = mapHeaders["authorization"];
2469 if (strAuth.substr(0,6) != "Basic ")
2471 string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
2472 string strUserPass = DecodeBase64(strUserPass64);
2473 return strUserPass == strRPCUserColonPass;
2477 // JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
2478 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
2479 // unspecified (HTTP errors and contents of 'error').
2481 // 1.0 spec: http://json-rpc.org/wiki/specification
2482 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
2483 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
2486 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
2489 request.push_back(Pair("method", strMethod));
2490 request.push_back(Pair("params", params));
2491 request.push_back(Pair("id", id));
2492 return write_string(Value(request), false) + "\n";
2495 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
2498 if (error.type() != null_type)
2499 reply.push_back(Pair("result", Value::null));
2501 reply.push_back(Pair("result", result));
2502 reply.push_back(Pair("error", error));
2503 reply.push_back(Pair("id", id));
2504 return write_string(Value(reply), false) + "\n";
2507 void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
2509 // Send error reply from json-rpc error object
2511 int code = find_value(objError, "code").get_int();
2512 if (code == -32600) nStatus = 400;
2513 else if (code == -32601) nStatus = 404;
2514 string strReply = JSONRPCReply(Value::null, objError, id);
2515 stream << HTTPReply(nStatus, strReply) << std::flush;
2518 bool ClientAllowed(const string& strAddress)
2520 if (strAddress == asio::ip::address_v4::loopback().to_string())
2522 const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
2523 BOOST_FOREACH(string strAllow, vAllow)
2524 if (WildcardMatch(strAddress, strAllow))
2530 // IOStream device that speaks SSL but can also speak non-SSL
2532 class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
2534 SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
2536 fUseSSL = fUseSSLIn;
2537 fNeedHandshake = fUseSSLIn;
2540 void handshake(ssl::stream_base::handshake_type role)
2542 if (!fNeedHandshake) return;
2543 fNeedHandshake = false;
2544 stream.handshake(role);
2546 std::streamsize read(char* s, std::streamsize n)
2548 handshake(ssl::stream_base::server); // HTTPS servers read first
2549 if (fUseSSL) return stream.read_some(asio::buffer(s, n));
2550 return stream.next_layer().read_some(asio::buffer(s, n));
2552 std::streamsize write(const char* s, std::streamsize n)
2554 handshake(ssl::stream_base::client); // HTTPS clients write first
2555 if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
2556 return asio::write(stream.next_layer(), asio::buffer(s, n));
2558 bool connect(const std::string& server, const std::string& port)
2560 ip::tcp::resolver resolver(stream.get_io_service());
2561 ip::tcp::resolver::query query(server.c_str(), port.c_str());
2562 ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
2563 ip::tcp::resolver::iterator end;
2564 boost::system::error_code error = asio::error::host_not_found;
2565 while (error && endpoint_iterator != end)
2567 stream.lowest_layer().close();
2568 stream.lowest_layer().connect(*endpoint_iterator++, error);
2576 bool fNeedHandshake;
2581 void ThreadRPCServer(void* parg)
2583 IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
2586 vnThreadsRunning[THREAD_RPCSERVER]++;
2587 ThreadRPCServer2(parg);
2588 vnThreadsRunning[THREAD_RPCSERVER]--;
2590 catch (std::exception& e) {
2591 vnThreadsRunning[THREAD_RPCSERVER]--;
2592 PrintException(&e, "ThreadRPCServer()");
2594 vnThreadsRunning[THREAD_RPCSERVER]--;
2595 PrintException(NULL, "ThreadRPCServer()");
2597 printf("ThreadRPCServer exiting\n");
2600 void ThreadRPCServer2(void* parg)
2602 printf("ThreadRPCServer started\n");
2604 strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
2605 if (mapArgs["-rpcpassword"] == "")
2607 unsigned char rand_pwd[32];
2608 RAND_bytes(rand_pwd, 32);
2609 string strWhatAmI = "To use ppcoind";
2610 if (mapArgs.count("-server"))
2611 strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
2612 else if (mapArgs.count("-daemon"))
2613 strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
2614 ThreadSafeMessageBox(strprintf(
2615 _("%s, you must set a rpcpassword in the configuration file:\n %s\n"
2616 "It is recommended you use the following random password:\n"
2617 "rpcuser=bitcoinrpc\n"
2619 "(you do not need to remember this password)\n"
2620 "If the file does not exist, create it with owner-readable-only file permissions.\n"),
2622 GetConfigFile().string().c_str(),
2623 EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str()),
2624 _("Error"), wxOK | wxMODAL);
2629 bool fUseSSL = GetBoolArg("-rpcssl");
2630 asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
2632 asio::io_service io_service;
2633 ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", RPC_PORT));
2634 ip::tcp::acceptor acceptor(io_service);
2637 acceptor.open(endpoint.protocol());
2638 acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
2639 acceptor.bind(endpoint);
2640 acceptor.listen(socket_base::max_connections);
2642 catch(boost::system::system_error &e)
2644 ThreadSafeMessageBox(strprintf(_("An error occured while setting up the RPC port %i for listening: %s"), endpoint.port(), e.what()),
2645 _("Error"), wxOK | wxMODAL);
2650 ssl::context context(io_service, ssl::context::sslv23);
2653 context.set_options(ssl::context::no_sslv2);
2655 filesystem::path pathCertFile(GetArg("-rpcsslcertificatechainfile", "server.cert"));
2656 if (!pathCertFile.is_complete()) pathCertFile = filesystem::path(GetDataDir()) / pathCertFile;
2657 if (filesystem::exists(pathCertFile)) context.use_certificate_chain_file(pathCertFile.string());
2658 else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", pathCertFile.string().c_str());
2660 filesystem::path pathPKFile(GetArg("-rpcsslprivatekeyfile", "server.pem"));
2661 if (!pathPKFile.is_complete()) pathPKFile = filesystem::path(GetDataDir()) / pathPKFile;
2662 if (filesystem::exists(pathPKFile)) context.use_private_key_file(pathPKFile.string(), ssl::context::pem);
2663 else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pathPKFile.string().c_str());
2665 string strCiphers = GetArg("-rpcsslciphers", "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
2666 SSL_CTX_set_cipher_list(context.impl(), strCiphers.c_str());
2671 // Accept connection
2672 SSLStream sslStream(io_service, context);
2673 SSLIOStreamDevice d(sslStream, fUseSSL);
2674 iostreams::stream<SSLIOStreamDevice> stream(d);
2676 ip::tcp::endpoint peer;
2677 vnThreadsRunning[THREAD_RPCSERVER]--;
2678 acceptor.accept(sslStream.lowest_layer(), peer);
2679 vnThreadsRunning[4]++;
2683 // Restrict callers by IP
2684 if (!ClientAllowed(peer.address().to_string()))
2686 // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
2688 stream << HTTPReply(403, "") << std::flush;
2692 map<string, string> mapHeaders;
2695 boost::thread api_caller(ReadHTTP, boost::ref(stream), boost::ref(mapHeaders), boost::ref(strRequest));
2696 if (!api_caller.timed_join(boost::posix_time::seconds(GetArg("-rpctimeout", 30))))
2699 printf("ThreadRPCServer ReadHTTP timeout\n");
2703 // Check authorization
2704 if (mapHeaders.count("authorization") == 0)
2706 stream << HTTPReply(401, "") << std::flush;
2709 if (!HTTPAuthorized(mapHeaders))
2711 printf("ThreadRPCServer incorrect password attempt from %s\n",peer.address().to_string().c_str());
2712 /* Deter brute-forcing short passwords.
2713 If this results in a DOS the user really
2714 shouldn't have their RPC port exposed.*/
2715 if (mapArgs["-rpcpassword"].size() < 20)
2718 stream << HTTPReply(401, "") << std::flush;
2722 Value id = Value::null;
2727 if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
2728 throw JSONRPCError(-32700, "Parse error");
2729 const Object& request = valRequest.get_obj();
2731 // Parse id now so errors from here on will have the id
2732 id = find_value(request, "id");
2735 Value valMethod = find_value(request, "method");
2736 if (valMethod.type() == null_type)
2737 throw JSONRPCError(-32600, "Missing method");
2738 if (valMethod.type() != str_type)
2739 throw JSONRPCError(-32600, "Method must be a string");
2740 string strMethod = valMethod.get_str();
2741 if (strMethod != "getwork" && strMethod != "getmemorypool")
2742 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
2745 Value valParams = find_value(request, "params");
2747 if (valParams.type() == array_type)
2748 params = valParams.get_array();
2749 else if (valParams.type() == null_type)
2752 throw JSONRPCError(-32600, "Params must be an array");
2755 const CRPCCommand *pcmd = tableRPC[strMethod];
2757 throw JSONRPCError(-32601, "Method not found");
2759 // Observe safe mode
2760 string strWarning = GetWarnings("rpc");
2761 if (strWarning != "" && !GetBoolArg("-disablesafemode") &&
2763 throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
2770 LOCK2(cs_main, pwalletMain->cs_wallet);
2771 result = pcmd->actor(params, false);
2775 string strReply = JSONRPCReply(result, Value::null, id);
2776 stream << HTTPReply(200, strReply) << std::flush;
2778 catch (std::exception& e)
2780 ErrorReply(stream, JSONRPCError(-1, e.what()), id);
2783 catch (Object& objError)
2785 ErrorReply(stream, objError, id);
2787 catch (std::exception& e)
2789 ErrorReply(stream, JSONRPCError(-32700, e.what()), id);
2797 Object CallRPC(const string& strMethod, const Array& params)
2799 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2800 throw runtime_error(strprintf(
2801 _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
2802 "If the file does not exist, create it with owner-readable-only file permissions."),
2803 GetConfigFile().string().c_str()));
2805 // Connect to localhost
2806 bool fUseSSL = GetBoolArg("-rpcssl");
2807 asio::io_service io_service;
2808 ssl::context context(io_service, ssl::context::sslv23);
2809 context.set_options(ssl::context::no_sslv2);
2810 SSLStream sslStream(io_service, context);
2811 SSLIOStreamDevice d(sslStream, fUseSSL);
2812 iostreams::stream<SSLIOStreamDevice> stream(d);
2813 if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", CBigNum(RPC_PORT).ToString().c_str())))
2814 throw runtime_error("couldn't connect to server");
2816 // HTTP basic authentication
2817 string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
2818 map<string, string> mapRequestHeaders;
2819 mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
2822 string strRequest = JSONRPCRequest(strMethod, params, 1);
2823 string strPost = HTTPPost(strRequest, mapRequestHeaders);
2824 stream << strPost << std::flush;
2827 map<string, string> mapHeaders;
2829 int nStatus = ReadHTTP(stream, mapHeaders, strReply);
2831 throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
2832 else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
2833 throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
2834 else if (strReply.empty())
2835 throw runtime_error("no response from server");
2839 if (!read_string(strReply, valReply))
2840 throw runtime_error("couldn't parse reply from server");
2841 const Object& reply = valReply.get_obj();
2843 throw runtime_error("expected reply to have result, error and id properties");
2851 template<typename T>
2852 void ConvertTo(Value& value)
2854 if (value.type() == str_type)
2856 // reinterpret string as unquoted json value
2858 if (!read_string(value.get_str(), value2))
2859 throw runtime_error("type mismatch");
2860 value = value2.get_value<T>();
2864 value = value.get_value<T>();
2868 int CommandLineRPC(int argc, char *argv[])
2875 while (argc > 1 && IsSwitchChar(argv[1][0]))
2883 throw runtime_error("too few parameters");
2884 string strMethod = argv[1];
2886 // Parameters default to strings
2888 for (int i = 2; i < argc; i++)
2889 params.push_back(argv[i]);
2890 int n = params.size();
2893 // Special case non-string parameter types
2895 if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
2896 if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2897 if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
2898 if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]);
2899 if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2900 if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2901 if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2902 if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
2903 if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2904 if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
2905 if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2906 if (strMethod == "getblockhash" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2907 if (strMethod == "getblock" && n > 1) ConvertTo<bool>(params[1]);
2908 if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]);
2909 if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2910 if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]);
2911 if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2912 if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2913 if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2914 if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2915 if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2916 if (strMethod == "walletpassphrase" && n > 2) ConvertTo<bool>(params[2]);
2917 if (strMethod == "listsinceblock" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2918 if (strMethod == "sendalert" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2919 if (strMethod == "sendalert" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2920 if (strMethod == "sendalert" && n > 4) ConvertTo<boost::int64_t>(params[4]);
2921 if (strMethod == "sendalert" && n > 5) ConvertTo<boost::int64_t>(params[5]);
2922 if (strMethod == "sendalert" && n > 6) ConvertTo<boost::int64_t>(params[6]);
2923 if (strMethod == "sendmany" && n > 1)
2925 string s = params[1].get_str();
2927 if (!read_string(s, v) || v.type() != obj_type)
2928 throw runtime_error("type mismatch");
2929 params[1] = v.get_obj();
2931 if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2932 if (strMethod == "reservebalance" && n > 0) ConvertTo<bool>(params[0]);
2933 if (strMethod == "reservebalance" && n > 1) ConvertTo<double>(params[1]);
2934 if (strMethod == "addmultisigaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2935 if (strMethod == "addmultisigaddress" && n > 1)
2937 string s = params[1].get_str();
2939 if (!read_string(s, v) || v.type() != array_type)
2940 throw runtime_error("type mismatch "+s);
2941 params[1] = v.get_array();
2945 Object reply = CallRPC(strMethod, params);
2948 const Value& result = find_value(reply, "result");
2949 const Value& error = find_value(reply, "error");
2951 if (error.type() != null_type)
2954 strPrint = "error: " + write_string(error, false);
2955 int code = find_value(error.get_obj(), "code").get_int();
2961 if (result.type() == null_type)
2963 else if (result.type() == str_type)
2964 strPrint = result.get_str();
2966 strPrint = write_string(result, true);
2969 catch (std::exception& e)
2971 strPrint = string("error: ") + e.what();
2976 PrintException(NULL, "CommandLineRPC()");
2981 fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
2990 int main(int argc, char *argv[])
2993 // Turn off microsoft heap dump noise
2994 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
2995 _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
2997 setbuf(stdin, NULL);
2998 setbuf(stdout, NULL);
2999 setbuf(stderr, NULL);
3003 if (argc >= 2 && string(argv[1]) == "-server")
3005 printf("server ready\n");
3006 ThreadRPCServer(NULL);
3010 return CommandLineRPC(argc, argv);
3013 catch (std::exception& e) {
3014 PrintException(&e, "main()");
3016 PrintException(NULL, "main()");
3022 const CRPCTable tableRPC;