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 BOOST_FOREACH(const CTxIn& txin, tx.vin)
163 txinfo.push_back(txin.ToStringShort());
164 BOOST_FOREACH(const CTxOut& txout, tx.vout)
165 txinfo.push_back(txout.ToStringShort());
168 txinfo.push_back(tx.GetHash().GetHex());
170 result.push_back(Pair("tx", txinfo));
177 /// Note: This interface may still be subject to change.
180 string CRPCTable::help(string strCommand) const
183 set<rpcfn_type> setDone;
184 for (map<string, const CRPCCommand*>::const_iterator mi = mapCommands.begin(); mi != mapCommands.end(); ++mi)
186 const CRPCCommand *pcmd = mi->second;
187 string strMethod = mi->first;
188 // We already filter duplicates, but these deprecated screw up the sort order
189 if (strMethod == "getamountreceived" ||
190 strMethod == "getallreceived" ||
191 strMethod == "getblocknumber" || // deprecated
192 (strMethod.find("label") != string::npos))
194 if (strCommand != "" && strMethod != strCommand)
199 rpcfn_type pfn = pcmd->actor;
200 if (setDone.insert(pfn).second)
201 (*pfn)(params, true);
203 catch (std::exception& e)
205 // Help text is returned in an exception
206 string strHelp = string(e.what());
207 if (strCommand == "")
208 if (strHelp.find('\n') != string::npos)
209 strHelp = strHelp.substr(0, strHelp.find('\n'));
210 strRet += strHelp + "\n";
214 strRet = strprintf("help: unknown command: %s\n", strCommand.c_str());
215 strRet = strRet.substr(0,strRet.size()-1);
219 Value help(const Array& params, bool fHelp)
221 if (fHelp || params.size() > 1)
224 "List commands, or get help for a command.");
227 if (params.size() > 0)
228 strCommand = params[0].get_str();
230 return tableRPC.help(strCommand);
234 Value stop(const Array& params, bool fHelp)
236 if (fHelp || params.size() != 0)
239 "Stop ppcoin server.");
240 // Shutdown will take long enough that the response should get back
242 return "ppcoin server stopping";
246 Value getblockcount(const Array& params, bool fHelp)
248 if (fHelp || params.size() != 0)
251 "Returns the number of blocks in the longest block chain.");
258 Value getblocknumber(const Array& params, bool fHelp)
260 if (fHelp || params.size() != 0)
263 "Deprecated. Use getblockcount.");
269 Value getconnectioncount(const Array& params, bool fHelp)
271 if (fHelp || params.size() != 0)
273 "getconnectioncount\n"
274 "Returns the number of connections to other nodes.");
276 return (int)vNodes.size();
280 Value getdifficulty(const Array& params, bool fHelp)
282 if (fHelp || params.size() != 0)
285 "Returns difficulty as a multiple of the minimum difficulty.");
288 obj.push_back(Pair("proof-of-work", GetDifficulty()));
289 obj.push_back(Pair("proof-of-stake", GetDifficulty(GetLastBlockIndex(pindexBest, true))));
294 Value getgenerate(const Array& params, bool fHelp)
296 if (fHelp || params.size() != 0)
299 "Returns true or false.");
301 return GetBoolArg("-gen");
305 Value setgenerate(const Array& params, bool fHelp)
307 if (fHelp || params.size() < 1 || params.size() > 2)
309 "setgenerate <generate> [genproclimit]\n"
310 "<generate> is true or false to turn generation on or off.\n"
311 "Generation is limited to [genproclimit] processors, -1 is unlimited.");
313 bool fGenerate = true;
314 if (params.size() > 0)
315 fGenerate = params[0].get_bool();
317 if (params.size() > 1)
319 int nGenProcLimit = params[1].get_int();
320 mapArgs["-genproclimit"] = itostr(nGenProcLimit);
321 if (nGenProcLimit == 0)
324 mapArgs["-gen"] = (fGenerate ? "1" : "0");
326 GenerateBitcoins(fGenerate, pwalletMain);
331 Value gethashespersec(const Array& params, bool fHelp)
333 if (fHelp || params.size() != 0)
336 "Returns a recent hashes per second performance measurement while generating.");
338 if (GetTimeMillis() - nHPSTimerStart > 8000)
339 return (boost::int64_t)0;
340 return (boost::int64_t)dHashesPerSec;
344 Value getinfo(const Array& params, bool fHelp)
346 if (fHelp || params.size() != 0)
349 "Returns an object containing various state info.");
352 obj.push_back(Pair("version", FormatFullVersion()));
353 obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION));
354 obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
355 obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
356 obj.push_back(Pair("newmint", ValueFromAmount(pwalletMain->GetNewMint())));
357 obj.push_back(Pair("stake", ValueFromAmount(pwalletMain->GetStake())));
358 obj.push_back(Pair("blocks", (int)nBestHeight));
359 obj.push_back(Pair("moneysupply", ValueFromAmount(pindexBest->nMoneySupply)));
360 obj.push_back(Pair("connections", (int)vNodes.size()));
361 obj.push_back(Pair("proxy", (fUseProxy ? addrProxy.ToStringIPPort() : string())));
362 obj.push_back(Pair("ip", addrSeenByPeer.ToStringIP()));
363 obj.push_back(Pair("difficulty", (double)GetDifficulty()));
364 obj.push_back(Pair("testnet", fTestNet));
365 obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));
366 obj.push_back(Pair("keypoolsize", pwalletMain->GetKeyPoolSize()));
367 obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee)));
368 if (pwalletMain->IsCrypted())
369 obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime / 1000));
370 obj.push_back(Pair("errors", GetWarnings("statusbar")));
375 Value getmininginfo(const Array& params, bool fHelp)
377 if (fHelp || params.size() != 0)
380 "Returns an object containing mining-related information.");
383 obj.push_back(Pair("blocks", (int)nBestHeight));
384 obj.push_back(Pair("currentblocksize",(uint64_t)nLastBlockSize));
385 obj.push_back(Pair("currentblocktx",(uint64_t)nLastBlockTx));
386 obj.push_back(Pair("difficulty", (double)GetDifficulty()));
387 obj.push_back(Pair("errors", GetWarnings("statusbar")));
388 obj.push_back(Pair("generate", GetBoolArg("-gen")));
389 obj.push_back(Pair("genproclimit", (int)GetArg("-genproclimit", -1)));
390 obj.push_back(Pair("hashespersec", gethashespersec(params, false)));
391 obj.push_back(Pair("pooledtx", (uint64_t)mempool.size()));
392 obj.push_back(Pair("testnet", fTestNet));
397 Value getnewaddress(const Array& params, bool fHelp)
399 if (fHelp || params.size() > 1)
401 "getnewaddress [account]\n"
402 "Returns a new ppcoin address for receiving payments. "
403 "If [account] is specified (recommended), it is added to the address book "
404 "so payments received with the address will be credited to [account].");
406 // Parse the account first so we don't generate a key if there's an error
408 if (params.size() > 0)
409 strAccount = AccountFromValue(params[0]);
411 if (!pwalletMain->IsLocked())
412 pwalletMain->TopUpKeyPool();
414 // Generate a new key that is added to wallet
415 std::vector<unsigned char> newKey;
416 if (!pwalletMain->GetKeyFromPool(newKey, false))
417 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
418 CBitcoinAddress address(newKey);
420 pwalletMain->SetAddressBookName(address, strAccount);
422 return address.ToString();
426 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
428 CWalletDB walletdb(pwalletMain->strWalletFile);
431 walletdb.ReadAccount(strAccount, account);
433 bool bKeyUsed = false;
435 // Check if the current key has been used
436 if (!account.vchPubKey.empty())
438 CScript scriptPubKey;
439 scriptPubKey.SetBitcoinAddress(account.vchPubKey);
440 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
441 it != pwalletMain->mapWallet.end() && !account.vchPubKey.empty();
444 const CWalletTx& wtx = (*it).second;
445 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
446 if (txout.scriptPubKey == scriptPubKey)
451 // Generate a new key
452 if (account.vchPubKey.empty() || bForceNew || bKeyUsed)
454 if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false))
455 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
457 pwalletMain->SetAddressBookName(CBitcoinAddress(account.vchPubKey), strAccount);
458 walletdb.WriteAccount(strAccount, account);
461 return CBitcoinAddress(account.vchPubKey);
464 Value getaccountaddress(const Array& params, bool fHelp)
466 if (fHelp || params.size() != 1)
468 "getaccountaddress <account>\n"
469 "Returns the current ppcoin address for receiving payments to this account.");
471 // Parse the account first so we don't generate a key if there's an error
472 string strAccount = AccountFromValue(params[0]);
476 ret = GetAccountAddress(strAccount).ToString();
483 Value setaccount(const Array& params, bool fHelp)
485 if (fHelp || params.size() < 1 || params.size() > 2)
487 "setaccount <ppcoinaddress> <account>\n"
488 "Sets the account associated with the given address.");
490 CBitcoinAddress address(params[0].get_str());
491 if (!address.IsValid())
492 throw JSONRPCError(-5, "Invalid ppcoin address");
496 if (params.size() > 1)
497 strAccount = AccountFromValue(params[1]);
499 // Detect when changing the account of an address that is the 'unused current key' of another account:
500 if (pwalletMain->mapAddressBook.count(address))
502 string strOldAccount = pwalletMain->mapAddressBook[address];
503 if (address == GetAccountAddress(strOldAccount))
504 GetAccountAddress(strOldAccount, true);
507 pwalletMain->SetAddressBookName(address, strAccount);
513 Value getaccount(const Array& params, bool fHelp)
515 if (fHelp || params.size() != 1)
517 "getaccount <ppcoinaddress>\n"
518 "Returns the account associated with the given address.");
520 CBitcoinAddress address(params[0].get_str());
521 if (!address.IsValid())
522 throw JSONRPCError(-5, "Invalid ppcoin address");
525 map<CBitcoinAddress, string>::iterator mi = pwalletMain->mapAddressBook.find(address);
526 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
527 strAccount = (*mi).second;
532 Value getaddressesbyaccount(const Array& params, bool fHelp)
534 if (fHelp || params.size() != 1)
536 "getaddressesbyaccount <account>\n"
537 "Returns the list of addresses for the given account.");
539 string strAccount = AccountFromValue(params[0]);
541 // Find all addresses that have the given account
543 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
545 const CBitcoinAddress& address = item.first;
546 const string& strName = item.second;
547 if (strName == strAccount)
548 ret.push_back(address.ToString());
553 Value settxfee(const Array& params, bool fHelp)
555 if (fHelp || params.size() < 1 || params.size() > 1 || AmountFromValue(params[0]) < MIN_TX_FEE)
557 "settxfee <amount>\n"
558 "<amount> is a real and is rounded to 0.01 (cent)\n"
559 "Minimum and default transaction fee per KB is 1 cent");
561 nTransactionFee = AmountFromValue(params[0]);
562 nTransactionFee = (nTransactionFee / CENT) * CENT; // round to cent
566 Value sendtoaddress(const Array& params, bool fHelp)
568 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
570 "sendtoaddress <ppcoinaddress> <amount> [comment] [comment-to]\n"
571 "<amount> is a real and is rounded to the nearest 0.000001\n"
572 "requires wallet passphrase to be set with walletpassphrase first");
573 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
575 "sendtoaddress <ppcoinaddress> <amount> [comment] [comment-to]\n"
576 "<amount> is a real and is rounded to the nearest 0.000001");
578 CBitcoinAddress address(params[0].get_str());
579 if (!address.IsValid())
580 throw JSONRPCError(-5, "Invalid ppcoin address");
583 int64 nAmount = AmountFromValue(params[1]);
584 if (nAmount < MIN_TXOUT_AMOUNT)
585 throw JSONRPCError(-101, "Send amount too small");
589 if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
590 wtx.mapValue["comment"] = params[2].get_str();
591 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
592 wtx.mapValue["to"] = params[3].get_str();
594 if (pwalletMain->IsLocked())
595 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
597 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
599 throw JSONRPCError(-4, strError);
601 return wtx.GetHash().GetHex();
604 Value signmessage(const Array& params, bool fHelp)
606 if (fHelp || params.size() != 2)
608 "signmessage <ppcoinaddress> <message>\n"
609 "Sign a message with the private key of an address");
611 if (pwalletMain->IsLocked())
612 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
614 string strAddress = params[0].get_str();
615 string strMessage = params[1].get_str();
617 CBitcoinAddress addr(strAddress);
619 throw JSONRPCError(-3, "Invalid address");
622 if (!pwalletMain->GetKey(addr, key))
623 throw JSONRPCError(-4, "Private key not available");
625 CDataStream ss(SER_GETHASH, 0);
626 ss << strMessageMagic;
629 vector<unsigned char> vchSig;
630 if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig))
631 throw JSONRPCError(-5, "Sign failed");
633 return EncodeBase64(&vchSig[0], vchSig.size());
636 Value verifymessage(const Array& params, bool fHelp)
638 if (fHelp || params.size() != 3)
640 "verifymessage <ppcoinaddress> <signature> <message>\n"
641 "Verify a signed message");
643 string strAddress = params[0].get_str();
644 string strSign = params[1].get_str();
645 string strMessage = params[2].get_str();
647 CBitcoinAddress addr(strAddress);
649 throw JSONRPCError(-3, "Invalid address");
651 bool fInvalid = false;
652 vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
655 throw JSONRPCError(-5, "Malformed base64 encoding");
657 CDataStream ss(SER_GETHASH, 0);
658 ss << strMessageMagic;
662 if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
665 return (CBitcoinAddress(key.GetPubKey()) == addr);
669 Value getreceivedbyaddress(const Array& params, bool fHelp)
671 if (fHelp || params.size() < 1 || params.size() > 2)
673 "getreceivedbyaddress <ppcoinaddress> [minconf=1]\n"
674 "Returns the total amount received by <ppcoinaddress> in transactions with at least [minconf] confirmations.");
677 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
678 CScript scriptPubKey;
679 if (!address.IsValid())
680 throw JSONRPCError(-5, "Invalid ppcoin address");
681 scriptPubKey.SetBitcoinAddress(address);
682 if (!IsMine(*pwalletMain,scriptPubKey))
685 // Minimum confirmations
687 if (params.size() > 1)
688 nMinDepth = params[1].get_int();
692 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
694 const CWalletTx& wtx = (*it).second;
695 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
698 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
699 if (txout.scriptPubKey == scriptPubKey)
700 if (wtx.GetDepthInMainChain() >= nMinDepth)
701 nAmount += txout.nValue;
704 return ValueFromAmount(nAmount);
708 void GetAccountAddresses(string strAccount, set<CBitcoinAddress>& setAddress)
710 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
712 const CBitcoinAddress& address = item.first;
713 const string& strName = item.second;
714 if (strName == strAccount)
715 setAddress.insert(address);
720 Value getreceivedbyaccount(const Array& params, bool fHelp)
722 if (fHelp || params.size() < 1 || params.size() > 2)
724 "getreceivedbyaccount <account> [minconf=1]\n"
725 "Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.");
727 // Minimum confirmations
729 if (params.size() > 1)
730 nMinDepth = params[1].get_int();
732 // Get the set of pub keys assigned to account
733 string strAccount = AccountFromValue(params[0]);
734 set<CBitcoinAddress> setAddress;
735 GetAccountAddresses(strAccount, setAddress);
739 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
741 const CWalletTx& wtx = (*it).second;
742 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
745 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
747 CBitcoinAddress address;
748 if (ExtractAddress(txout.scriptPubKey, address) && pwalletMain->HaveKey(address) && setAddress.count(address))
749 if (wtx.GetDepthInMainChain() >= nMinDepth)
750 nAmount += txout.nValue;
754 return (double)nAmount / (double)COIN;
758 int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth)
762 // Tally wallet transactions
763 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
765 const CWalletTx& wtx = (*it).second;
769 int64 nGenerated, nReceived, nSent, nFee;
770 wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee);
772 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
773 nBalance += nReceived;
774 nBalance += nGenerated - nSent - nFee;
777 // Tally internal accounting entries
778 nBalance += walletdb.GetAccountCreditDebit(strAccount);
783 int64 GetAccountBalance(const string& strAccount, int nMinDepth)
785 CWalletDB walletdb(pwalletMain->strWalletFile);
786 return GetAccountBalance(walletdb, strAccount, nMinDepth);
790 Value getbalance(const Array& params, bool fHelp)
792 if (fHelp || params.size() > 2)
794 "getbalance [account] [minconf=1]\n"
795 "If [account] is not specified, returns the server's total available balance.\n"
796 "If [account] is specified, returns the balance in the account.");
798 if (params.size() == 0)
799 return ValueFromAmount(pwalletMain->GetBalance());
802 if (params.size() > 1)
803 nMinDepth = params[1].get_int();
805 if (params[0].get_str() == "*") {
806 // Calculate total balance a different way from GetBalance()
807 // (GetBalance() sums up all unspent TxOuts)
808 // getbalance and getbalance '*' should always return the same number.
810 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
812 const CWalletTx& wtx = (*it).second;
816 int64 allGeneratedImmature, allGeneratedMature, allFee;
817 allGeneratedImmature = allGeneratedMature = allFee = 0;
818 string strSentAccount;
819 list<pair<CBitcoinAddress, int64> > listReceived;
820 list<pair<CBitcoinAddress, int64> > listSent;
821 wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
822 if (wtx.GetDepthInMainChain() >= nMinDepth)
824 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listReceived)
825 nBalance += r.second;
827 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listSent)
828 nBalance -= r.second;
830 nBalance += allGeneratedMature;
832 return ValueFromAmount(nBalance);
835 string strAccount = AccountFromValue(params[0]);
837 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
839 return ValueFromAmount(nBalance);
843 Value movecmd(const Array& params, bool fHelp)
845 if (fHelp || params.size() < 3 || params.size() > 5)
847 "move <fromaccount> <toaccount> <amount> [minconf=1] [comment]\n"
848 "Move from one account in your wallet to another.");
850 string strFrom = AccountFromValue(params[0]);
851 string strTo = AccountFromValue(params[1]);
852 int64 nAmount = AmountFromValue(params[2]);
853 if (params.size() > 3)
854 // unused parameter, used to be nMinDepth, keep type-checking it though
855 (void)params[3].get_int();
857 if (params.size() > 4)
858 strComment = params[4].get_str();
860 CWalletDB walletdb(pwalletMain->strWalletFile);
861 if (!walletdb.TxnBegin())
862 throw JSONRPCError(-20, "database error");
864 int64 nNow = GetAdjustedTime();
867 CAccountingEntry debit;
868 debit.strAccount = strFrom;
869 debit.nCreditDebit = -nAmount;
871 debit.strOtherAccount = strTo;
872 debit.strComment = strComment;
873 walletdb.WriteAccountingEntry(debit);
876 CAccountingEntry credit;
877 credit.strAccount = strTo;
878 credit.nCreditDebit = nAmount;
880 credit.strOtherAccount = strFrom;
881 credit.strComment = strComment;
882 walletdb.WriteAccountingEntry(credit);
884 if (!walletdb.TxnCommit())
885 throw JSONRPCError(-20, "database error");
891 Value sendfrom(const Array& params, bool fHelp)
893 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
895 "sendfrom <fromaccount> <toppcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
896 "<amount> is a real and is rounded to the nearest 0.000001\n"
897 "requires wallet passphrase to be set with walletpassphrase first");
898 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
900 "sendfrom <fromaccount> <toppcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
901 "<amount> is a real and is rounded to the nearest 0.000001");
903 string strAccount = AccountFromValue(params[0]);
904 CBitcoinAddress address(params[1].get_str());
905 if (!address.IsValid())
906 throw JSONRPCError(-5, "Invalid ppcoin address");
907 int64 nAmount = AmountFromValue(params[2]);
908 if (nAmount < MIN_TXOUT_AMOUNT)
909 throw JSONRPCError(-101, "Send amount too small");
911 if (params.size() > 3)
912 nMinDepth = params[3].get_int();
915 wtx.strFromAccount = strAccount;
916 if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
917 wtx.mapValue["comment"] = params[4].get_str();
918 if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
919 wtx.mapValue["to"] = params[5].get_str();
921 if (pwalletMain->IsLocked())
922 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
925 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
926 if (nAmount > nBalance)
927 throw JSONRPCError(-6, "Account has insufficient funds");
930 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
932 throw JSONRPCError(-4, strError);
934 return wtx.GetHash().GetHex();
938 Value sendmany(const Array& params, bool fHelp)
940 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
942 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
943 "amounts are double-precision floating point numbers\n"
944 "requires wallet passphrase to be set with walletpassphrase first");
945 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
947 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
948 "amounts are double-precision floating point numbers");
950 string strAccount = AccountFromValue(params[0]);
951 Object sendTo = params[1].get_obj();
953 if (params.size() > 2)
954 nMinDepth = params[2].get_int();
957 wtx.strFromAccount = strAccount;
958 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
959 wtx.mapValue["comment"] = params[3].get_str();
961 set<CBitcoinAddress> setAddress;
962 vector<pair<CScript, int64> > vecSend;
964 int64 totalAmount = 0;
965 BOOST_FOREACH(const Pair& s, sendTo)
967 CBitcoinAddress address(s.name_);
968 if (!address.IsValid())
969 throw JSONRPCError(-5, string("Invalid ppcoin address:")+s.name_);
971 if (setAddress.count(address))
972 throw JSONRPCError(-8, string("Invalid parameter, duplicated address: ")+s.name_);
973 setAddress.insert(address);
975 CScript scriptPubKey;
976 scriptPubKey.SetBitcoinAddress(address);
977 int64 nAmount = AmountFromValue(s.value_);
978 if (nAmount < MIN_TXOUT_AMOUNT)
979 throw JSONRPCError(-101, "Send amount too small");
980 totalAmount += nAmount;
982 vecSend.push_back(make_pair(scriptPubKey, nAmount));
985 if (pwalletMain->IsLocked())
986 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
987 if (fWalletUnlockMintOnly)
988 throw JSONRPCError(-13, "Error: Wallet unlocked for block minting only.");
991 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
992 if (totalAmount > nBalance)
993 throw JSONRPCError(-6, "Account has insufficient funds");
996 CReserveKey keyChange(pwalletMain);
997 int64 nFeeRequired = 0;
998 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
1001 if (totalAmount + nFeeRequired > pwalletMain->GetBalance())
1002 throw JSONRPCError(-6, "Insufficient funds");
1003 throw JSONRPCError(-4, "Transaction creation failed");
1005 if (!pwalletMain->CommitTransaction(wtx, keyChange))
1006 throw JSONRPCError(-4, "Transaction commit failed");
1008 return wtx.GetHash().GetHex();
1011 Value addmultisigaddress(const Array& params, bool fHelp)
1013 if (fHelp || params.size() < 2 || params.size() > 3)
1015 string msg = "addmultisigaddress <nrequired> <'[\"key\",\"key\"]'> [account]\n"
1016 "Add a nrequired-to-sign multisignature address to the wallet\"\n"
1017 "each key is a bitcoin address or hex-encoded public key\n"
1018 "If [account] is specified, assign address to [account].";
1019 throw runtime_error(msg);
1022 int nRequired = params[0].get_int();
1023 const Array& keys = params[1].get_array();
1025 if (params.size() > 2)
1026 strAccount = AccountFromValue(params[2]);
1028 // Gather public keys
1030 throw runtime_error("a multisignature address must require at least one key to redeem");
1031 if ((int)keys.size() < nRequired)
1032 throw runtime_error(
1033 strprintf("not enough keys supplied "
1034 "(got %d keys, but need at least %d to redeem)", keys.size(), nRequired));
1035 std::vector<CKey> pubkeys;
1036 pubkeys.resize(keys.size());
1037 for (unsigned int i = 0; i < keys.size(); i++)
1039 const std::string& ks = keys[i].get_str();
1041 // Case 1: bitcoin address and we have full public key:
1042 CBitcoinAddress address(ks);
1043 if (address.IsValid())
1045 if (address.IsScript())
1046 throw runtime_error(
1047 strprintf("%s is a pay-to-script address",ks.c_str()));
1048 std::vector<unsigned char> vchPubKey;
1049 if (!pwalletMain->GetPubKey(address, vchPubKey))
1050 throw runtime_error(
1051 strprintf("no full public key for address %s",ks.c_str()));
1052 if (vchPubKey.empty() || !pubkeys[i].SetPubKey(vchPubKey))
1053 throw runtime_error(" Invalid public key: "+ks);
1056 // Case 2: hex public key
1059 vector<unsigned char> vchPubKey = ParseHex(ks);
1060 if (vchPubKey.empty() || !pubkeys[i].SetPubKey(vchPubKey))
1061 throw runtime_error(" Invalid public key: "+ks);
1065 throw runtime_error(" Invalid public key: "+ks);
1069 // Construct using pay-to-script-hash:
1071 inner.SetMultisig(nRequired, pubkeys);
1073 uint160 scriptHash = Hash160(inner);
1074 CScript scriptPubKey;
1075 scriptPubKey.SetPayToScriptHash(inner);
1076 pwalletMain->AddCScript(inner);
1077 CBitcoinAddress address;
1078 address.SetScriptHash160(scriptHash);
1080 pwalletMain->SetAddressBookName(address, strAccount);
1081 return address.ToString();
1092 nConf = std::numeric_limits<int>::max();
1096 Value ListReceived(const Array& params, bool fByAccounts)
1098 // Minimum confirmations
1100 if (params.size() > 0)
1101 nMinDepth = params[0].get_int();
1103 // Whether to include empty accounts
1104 bool fIncludeEmpty = false;
1105 if (params.size() > 1)
1106 fIncludeEmpty = params[1].get_bool();
1109 map<CBitcoinAddress, tallyitem> mapTally;
1110 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1112 const CWalletTx& wtx = (*it).second;
1114 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
1117 int nDepth = wtx.GetDepthInMainChain();
1118 if (nDepth < nMinDepth)
1121 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
1123 CBitcoinAddress address;
1124 if (!ExtractAddress(txout.scriptPubKey, address) || !pwalletMain->HaveKey(address) || !address.IsValid())
1127 tallyitem& item = mapTally[address];
1128 item.nAmount += txout.nValue;
1129 item.nConf = min(item.nConf, nDepth);
1135 map<string, tallyitem> mapAccountTally;
1136 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
1138 const CBitcoinAddress& address = item.first;
1139 const string& strAccount = item.second;
1140 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
1141 if (it == mapTally.end() && !fIncludeEmpty)
1145 int nConf = std::numeric_limits<int>::max();
1146 if (it != mapTally.end())
1148 nAmount = (*it).second.nAmount;
1149 nConf = (*it).second.nConf;
1154 tallyitem& item = mapAccountTally[strAccount];
1155 item.nAmount += nAmount;
1156 item.nConf = min(item.nConf, nConf);
1161 obj.push_back(Pair("address", address.ToString()));
1162 obj.push_back(Pair("account", strAccount));
1163 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1164 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1171 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
1173 int64 nAmount = (*it).second.nAmount;
1174 int nConf = (*it).second.nConf;
1176 obj.push_back(Pair("account", (*it).first));
1177 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1178 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1186 Value listreceivedbyaddress(const Array& params, bool fHelp)
1188 if (fHelp || params.size() > 2)
1189 throw runtime_error(
1190 "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
1191 "[minconf] is the minimum number of confirmations before payments are included.\n"
1192 "[includeempty] whether to include addresses that haven't received any payments.\n"
1193 "Returns an array of objects containing:\n"
1194 " \"address\" : receiving address\n"
1195 " \"account\" : the account of the receiving address\n"
1196 " \"amount\" : total amount received by the address\n"
1197 " \"confirmations\" : number of confirmations of the most recent transaction included");
1199 return ListReceived(params, false);
1202 Value listreceivedbyaccount(const Array& params, bool fHelp)
1204 if (fHelp || params.size() > 2)
1205 throw runtime_error(
1206 "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
1207 "[minconf] is the minimum number of confirmations before payments are included.\n"
1208 "[includeempty] whether to include accounts that haven't received any payments.\n"
1209 "Returns an array of objects containing:\n"
1210 " \"account\" : the account of the receiving addresses\n"
1211 " \"amount\" : total amount received by addresses with this account\n"
1212 " \"confirmations\" : number of confirmations of the most recent transaction included");
1214 return ListReceived(params, true);
1217 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret)
1219 int64 nGeneratedImmature, nGeneratedMature, nFee;
1220 string strSentAccount;
1221 list<pair<CBitcoinAddress, int64> > listReceived;
1222 list<pair<CBitcoinAddress, int64> > listSent;
1224 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1226 bool fAllAccounts = (strAccount == string("*"));
1228 // Generated blocks assigned to account ""
1229 if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == ""))
1232 entry.push_back(Pair("account", string("")));
1233 if (nGeneratedImmature)
1235 entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
1236 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
1240 entry.push_back(Pair("category", "generate"));
1241 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
1244 WalletTxToJSON(wtx, entry);
1245 ret.push_back(entry);
1249 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1251 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1254 entry.push_back(Pair("account", strSentAccount));
1255 entry.push_back(Pair("address", s.first.ToString()));
1256 entry.push_back(Pair("category", "send"));
1257 entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1258 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1260 WalletTxToJSON(wtx, entry);
1261 ret.push_back(entry);
1266 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1268 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1271 if (pwalletMain->mapAddressBook.count(r.first))
1272 account = pwalletMain->mapAddressBook[r.first];
1273 if (fAllAccounts || (account == strAccount))
1276 entry.push_back(Pair("account", account));
1277 entry.push_back(Pair("address", r.first.ToString()));
1278 entry.push_back(Pair("category", "receive"));
1279 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1281 WalletTxToJSON(wtx, entry);
1282 ret.push_back(entry);
1288 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1290 bool fAllAccounts = (strAccount == string("*"));
1292 if (fAllAccounts || acentry.strAccount == strAccount)
1295 entry.push_back(Pair("account", acentry.strAccount));
1296 entry.push_back(Pair("category", "move"));
1297 entry.push_back(Pair("time", (boost::int64_t)acentry.nTime));
1298 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1299 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1300 entry.push_back(Pair("comment", acentry.strComment));
1301 ret.push_back(entry);
1305 Value listtransactions(const Array& params, bool fHelp)
1307 if (fHelp || params.size() > 3)
1308 throw runtime_error(
1309 "listtransactions [account] [count=10] [from=0]\n"
1310 "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1312 string strAccount = "*";
1313 if (params.size() > 0)
1314 strAccount = params[0].get_str();
1316 if (params.size() > 1)
1317 nCount = params[1].get_int();
1319 if (params.size() > 2)
1320 nFrom = params[2].get_int();
1323 throw JSONRPCError(-8, "Negative count");
1325 throw JSONRPCError(-8, "Negative from");
1328 CWalletDB walletdb(pwalletMain->strWalletFile);
1330 // First: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap.
1331 typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
1332 typedef multimap<int64, TxPair > TxItems;
1335 // Note: maintaining indices in the database of (account,time) --> txid and (account, time) --> acentry
1336 // would make this much faster for applications that do this a lot.
1337 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1339 CWalletTx* wtx = &((*it).second);
1340 txByTime.insert(make_pair(wtx->GetTxTime(), TxPair(wtx, (CAccountingEntry*)0)));
1342 list<CAccountingEntry> acentries;
1343 walletdb.ListAccountCreditDebit(strAccount, acentries);
1344 BOOST_FOREACH(CAccountingEntry& entry, acentries)
1346 txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
1349 // iterate backwards until we have nCount items to return:
1350 for (TxItems::reverse_iterator it = txByTime.rbegin(); it != txByTime.rend(); ++it)
1352 CWalletTx *const pwtx = (*it).second.first;
1354 ListTransactions(*pwtx, strAccount, 0, true, ret);
1355 CAccountingEntry *const pacentry = (*it).second.second;
1357 AcentryToJSON(*pacentry, strAccount, ret);
1359 if (ret.size() >= (nCount+nFrom)) break;
1361 // ret is newest to oldest
1363 if (nFrom > (int)ret.size())
1365 if ((nFrom + nCount) > (int)ret.size())
1366 nCount = ret.size() - nFrom;
1367 Array::iterator first = ret.begin();
1368 std::advance(first, nFrom);
1369 Array::iterator last = ret.begin();
1370 std::advance(last, nFrom+nCount);
1372 if (last != ret.end()) ret.erase(last, ret.end());
1373 if (first != ret.begin()) ret.erase(ret.begin(), first);
1375 std::reverse(ret.begin(), ret.end()); // Return oldest to newest
1380 Value listaccounts(const Array& params, bool fHelp)
1382 if (fHelp || params.size() > 1)
1383 throw runtime_error(
1384 "listaccounts [minconf=1]\n"
1385 "Returns Object that has account names as keys, account balances as values.");
1388 if (params.size() > 0)
1389 nMinDepth = params[0].get_int();
1391 map<string, int64> mapAccountBalances;
1392 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& entry, pwalletMain->mapAddressBook) {
1393 if (pwalletMain->HaveKey(entry.first)) // This address belongs to me
1394 mapAccountBalances[entry.second] = 0;
1397 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1399 const CWalletTx& wtx = (*it).second;
1400 int64 nGeneratedImmature, nGeneratedMature, nFee;
1401 string strSentAccount;
1402 list<pair<CBitcoinAddress, int64> > listReceived;
1403 list<pair<CBitcoinAddress, int64> > listSent;
1404 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1405 mapAccountBalances[strSentAccount] -= nFee;
1406 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1407 mapAccountBalances[strSentAccount] -= s.second;
1408 if (wtx.GetDepthInMainChain() >= nMinDepth)
1410 mapAccountBalances[""] += nGeneratedMature;
1411 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1412 if (pwalletMain->mapAddressBook.count(r.first))
1413 mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1415 mapAccountBalances[""] += r.second;
1419 list<CAccountingEntry> acentries;
1420 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1421 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1422 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1425 BOOST_FOREACH(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) {
1426 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1431 Value listsinceblock(const Array& params, bool fHelp)
1434 throw runtime_error(
1435 "listsinceblock [blockhash] [target-confirmations]\n"
1436 "Get all transactions in blocks since block [blockhash], or all transactions if omitted");
1438 CBlockIndex *pindex = NULL;
1439 int target_confirms = 1;
1441 if (params.size() > 0)
1443 uint256 blockId = 0;
1445 blockId.SetHex(params[0].get_str());
1446 pindex = CBlockLocator(blockId).GetBlockIndex();
1449 if (params.size() > 1)
1451 target_confirms = params[1].get_int();
1453 if (target_confirms < 1)
1454 throw JSONRPCError(-8, "Invalid parameter");
1457 int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1;
1461 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1463 CWalletTx tx = (*it).second;
1465 if (depth == -1 || tx.GetDepthInMainChain() < depth)
1466 ListTransactions(tx, "*", 0, true, transactions);
1471 if (target_confirms == 1)
1473 lastblock = hashBestChain;
1477 int target_height = pindexBest->nHeight + 1 - target_confirms;
1480 for (block = pindexBest;
1481 block && block->nHeight > target_height;
1482 block = block->pprev) { }
1484 lastblock = block ? block->GetBlockHash() : 0;
1488 ret.push_back(Pair("transactions", transactions));
1489 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1494 Value gettransaction(const Array& params, bool fHelp)
1496 if (fHelp || params.size() != 1)
1497 throw runtime_error(
1498 "gettransaction <txid>\n"
1499 "Get detailed information about <txid>");
1502 hash.SetHex(params[0].get_str());
1506 if (!pwalletMain->mapWallet.count(hash))
1507 throw JSONRPCError(-5, "Invalid or non-wallet transaction id");
1508 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1510 int64 nCredit = wtx.GetCredit();
1511 int64 nDebit = wtx.GetDebit();
1512 int64 nNet = nCredit - nDebit;
1513 int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
1515 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1517 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1519 WalletTxToJSON(pwalletMain->mapWallet[hash], entry);
1522 ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
1523 entry.push_back(Pair("details", details));
1529 Value backupwallet(const Array& params, bool fHelp)
1531 if (fHelp || params.size() != 1)
1532 throw runtime_error(
1533 "backupwallet <destination>\n"
1534 "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1536 string strDest = params[0].get_str();
1537 BackupWallet(*pwalletMain, strDest);
1543 Value keypoolrefill(const Array& params, bool fHelp)
1545 if (pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1546 throw runtime_error(
1548 "Fills the keypool, requires wallet passphrase to be set.");
1549 if (!pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1550 throw runtime_error(
1552 "Fills the keypool.");
1554 if (pwalletMain->IsLocked())
1555 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
1557 pwalletMain->TopUpKeyPool();
1559 if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100))
1560 throw JSONRPCError(-4, "Error refreshing keypool.");
1566 void ThreadTopUpKeyPool(void* parg)
1568 pwalletMain->TopUpKeyPool();
1571 void ThreadCleanWalletPassphrase(void* parg)
1573 int64 nMyWakeTime = GetTimeMillis() + *((int64*)parg) * 1000;
1575 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1577 if (nWalletUnlockTime == 0)
1579 nWalletUnlockTime = nMyWakeTime;
1583 if (nWalletUnlockTime==0)
1585 int64 nToSleep = nWalletUnlockTime - GetTimeMillis();
1589 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1591 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1595 if (nWalletUnlockTime)
1597 nWalletUnlockTime = 0;
1598 pwalletMain->Lock();
1603 if (nWalletUnlockTime < nMyWakeTime)
1604 nWalletUnlockTime = nMyWakeTime;
1607 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1609 delete (int64*)parg;
1612 Value walletpassphrase(const Array& params, bool fHelp)
1614 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 3))
1615 throw runtime_error(
1616 "walletpassphrase <passphrase> <timeout> [mintonly]\n"
1617 "Stores the wallet decryption key in memory for <timeout> seconds.\n"
1618 "mintonly is optional true/false allowing only block minting.");
1621 if (!pwalletMain->IsCrypted())
1622 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1624 if (!pwalletMain->IsLocked())
1625 throw JSONRPCError(-17, "Error: Wallet is already unlocked, use walletlock first if need to change unlock settings.");
1627 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1628 SecureString strWalletPass;
1629 strWalletPass.reserve(100);
1630 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1631 // Alternately, find a way to make params[0] mlock()'d to begin with.
1632 strWalletPass = params[0].get_str().c_str();
1634 if (strWalletPass.length() > 0)
1636 if (!pwalletMain->Unlock(strWalletPass))
1637 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1640 throw runtime_error(
1641 "walletpassphrase <passphrase> <timeout>\n"
1642 "Stores the wallet decryption key in memory for <timeout> seconds.");
1644 CreateThread(ThreadTopUpKeyPool, NULL);
1645 int64* pnSleepTime = new int64(params[1].get_int64());
1646 CreateThread(ThreadCleanWalletPassphrase, pnSleepTime);
1648 // ppcoin: if user OS account compromised prevent trivial sendmoney commands
1649 if (params.size() > 2)
1650 fWalletUnlockMintOnly = params[2].get_bool();
1652 fWalletUnlockMintOnly = false;
1658 Value walletpassphrasechange(const Array& params, bool fHelp)
1660 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1661 throw runtime_error(
1662 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1663 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1666 if (!pwalletMain->IsCrypted())
1667 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1669 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1670 // Alternately, find a way to make params[0] mlock()'d to begin with.
1671 SecureString strOldWalletPass;
1672 strOldWalletPass.reserve(100);
1673 strOldWalletPass = params[0].get_str().c_str();
1675 SecureString strNewWalletPass;
1676 strNewWalletPass.reserve(100);
1677 strNewWalletPass = params[1].get_str().c_str();
1679 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1680 throw runtime_error(
1681 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1682 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1684 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1685 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1691 Value walletlock(const Array& params, bool fHelp)
1693 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1694 throw runtime_error(
1696 "Removes the wallet encryption key from memory, locking the wallet.\n"
1697 "After calling this method, you will need to call walletpassphrase again\n"
1698 "before being able to call any methods which require the wallet to be unlocked.");
1701 if (!pwalletMain->IsCrypted())
1702 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called.");
1705 LOCK(cs_nWalletUnlockTime);
1706 pwalletMain->Lock();
1707 nWalletUnlockTime = 0;
1714 Value encryptwallet(const Array& params, bool fHelp)
1716 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1717 throw runtime_error(
1718 "encryptwallet <passphrase>\n"
1719 "Encrypts the wallet with <passphrase>.");
1722 if (pwalletMain->IsCrypted())
1723 throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
1725 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1726 // Alternately, find a way to make params[0] mlock()'d to begin with.
1727 SecureString strWalletPass;
1728 strWalletPass.reserve(100);
1729 strWalletPass = params[0].get_str().c_str();
1731 if (strWalletPass.length() < 1)
1732 throw runtime_error(
1733 "encryptwallet <passphrase>\n"
1734 "Encrypts the wallet with <passphrase>.");
1736 if (!pwalletMain->EncryptWallet(strWalletPass))
1737 throw JSONRPCError(-16, "Error: Failed to encrypt the wallet.");
1739 // BDB seems to have a bad habit of writing old data into
1740 // slack space in .dat files; that is bad if the old data is
1741 // unencrypted private keys. So:
1743 return "wallet encrypted; ppcoin server stopping, restart to run with encrypted wallet";
1747 Value validateaddress(const Array& params, bool fHelp)
1749 if (fHelp || params.size() != 1)
1750 throw runtime_error(
1751 "validateaddress <ppcoinaddress>\n"
1752 "Return information about <ppcoinaddress>.");
1754 CBitcoinAddress address(params[0].get_str());
1755 bool isValid = address.IsValid();
1758 ret.push_back(Pair("isvalid", isValid));
1761 // Call Hash160ToAddress() so we always return current ADDRESSVERSION
1762 // version of the address:
1763 string currentAddress = address.ToString();
1764 ret.push_back(Pair("address", currentAddress));
1765 if (pwalletMain->HaveKey(address))
1767 ret.push_back(Pair("ismine", true));
1768 std::vector<unsigned char> vchPubKey;
1769 pwalletMain->GetPubKey(address, vchPubKey);
1770 ret.push_back(Pair("pubkey", HexStr(vchPubKey)));
1772 key.SetPubKey(vchPubKey);
1773 ret.push_back(Pair("iscompressed", key.IsCompressed()));
1775 else if (pwalletMain->HaveCScript(address.GetHash160()))
1777 ret.push_back(Pair("isscript", true));
1779 pwalletMain->GetCScript(address.GetHash160(), subscript);
1780 ret.push_back(Pair("ismine", ::IsMine(*pwalletMain, subscript)));
1781 std::vector<CBitcoinAddress> addresses;
1782 txnouttype whichType;
1784 ExtractAddresses(subscript, whichType, addresses, nRequired);
1785 ret.push_back(Pair("script", GetTxnOutputType(whichType)));
1787 BOOST_FOREACH(const CBitcoinAddress& addr, addresses)
1788 a.push_back(addr.ToString());
1789 ret.push_back(Pair("addresses", a));
1790 if (whichType == TX_MULTISIG)
1791 ret.push_back(Pair("sigsrequired", nRequired));
1794 ret.push_back(Pair("ismine", false));
1795 if (pwalletMain->mapAddressBook.count(address))
1796 ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
1801 Value getwork(const Array& params, bool fHelp)
1803 if (fHelp || params.size() > 1)
1804 throw runtime_error(
1806 "If [data] is not specified, returns formatted hash data to work on:\n"
1807 " \"midstate\" : precomputed hash state after hashing the first half of the data (DEPRECATED)\n" // deprecated
1808 " \"data\" : block data\n"
1809 " \"hash1\" : formatted hash buffer for second hash (DEPRECATED)\n" // deprecated
1810 " \"target\" : little endian hash target\n"
1811 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1814 throw JSONRPCError(-9, "PPCoin is not connected!");
1816 if (IsInitialBlockDownload())
1817 throw JSONRPCError(-10, "PPCoin is downloading blocks...");
1819 typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
1820 static mapNewBlock_t mapNewBlock;
1821 static vector<CBlock*> vNewBlock;
1822 static CReserveKey reservekey(pwalletMain);
1824 if (params.size() == 0)
1827 static unsigned int nTransactionsUpdatedLast;
1828 static CBlockIndex* pindexPrev;
1829 static int64 nStart;
1830 static CBlock* pblock;
1831 if (pindexPrev != pindexBest ||
1832 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
1834 if (pindexPrev != pindexBest)
1836 // Deallocate old blocks since they're obsolete now
1837 mapNewBlock.clear();
1838 BOOST_FOREACH(CBlock* pblock, vNewBlock)
1842 nTransactionsUpdatedLast = nTransactionsUpdated;
1843 pindexPrev = pindexBest;
1847 pblock = CreateNewBlock(pwalletMain);
1849 throw JSONRPCError(-7, "Out of memory");
1850 vNewBlock.push_back(pblock);
1854 pblock->UpdateTime(pindexPrev);
1857 // Update nExtraNonce
1858 static unsigned int nExtraNonce = 0;
1859 IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
1862 mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
1864 // Prebuild hash buffers
1868 FormatHashBuffers(pblock, pmidstate, pdata, phash1);
1870 uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
1873 result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate)))); // deprecated
1874 result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata))));
1875 result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1)))); // deprecated
1876 result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
1882 vector<unsigned char> vchData = ParseHex(params[0].get_str());
1883 if (vchData.size() != 128)
1884 throw JSONRPCError(-8, "Invalid parameter");
1885 CBlock* pdata = (CBlock*)&vchData[0];
1888 for (int i = 0; i < 128/4; i++)
1889 ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]);
1892 if (!mapNewBlock.count(pdata->hashMerkleRoot))
1894 CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
1896 pblock->nTime = pdata->nTime;
1897 pblock->nNonce = pdata->nNonce;
1898 pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
1899 pblock->hashMerkleRoot = pblock->BuildMerkleTree();
1900 if (!pblock->SignBlock(*pwalletMain))
1901 throw JSONRPCError(-100, "Unable to sign block, wallet locked?");
1903 return CheckWork(pblock, *pwalletMain, reservekey);
1908 Value getmemorypool(const Array& params, bool fHelp)
1910 if (fHelp || params.size() > 1)
1911 throw runtime_error(
1912 "getmemorypool [data]\n"
1913 "If [data] is not specified, returns data needed to construct a block to work on:\n"
1914 " \"version\" : block version\n"
1915 " \"previousblockhash\" : hash of current highest block\n"
1916 " \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
1917 " \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
1918 " \"coinbaseflags\" : data that should be included in coinbase so support for new features can be judged\n"
1919 " \"time\" : timestamp appropriate for next block\n"
1920 " \"mintime\" : minimum timestamp appropriate for next block\n"
1921 " \"curtime\" : current timestamp\n"
1922 " \"bits\" : compressed target of next block\n"
1923 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1925 if (params.size() == 0)
1928 throw JSONRPCError(-9, "PPCoin is not connected!");
1930 if (IsInitialBlockDownload())
1931 throw JSONRPCError(-10, "PPCoin is downloading blocks...");
1933 static CReserveKey reservekey(pwalletMain);
1936 static unsigned int nTransactionsUpdatedLast;
1937 static CBlockIndex* pindexPrev;
1938 static int64 nStart;
1939 static CBlock* pblock;
1940 if (pindexPrev != pindexBest ||
1941 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5))
1943 nTransactionsUpdatedLast = nTransactionsUpdated;
1944 pindexPrev = pindexBest;
1950 pblock = CreateNewBlock(pwalletMain);
1952 throw JSONRPCError(-7, "Out of memory");
1956 pblock->UpdateTime(pindexPrev);
1960 BOOST_FOREACH(CTransaction tx, pblock->vtx) {
1961 if(tx.IsCoinBase() || tx.IsCoinStake())
1964 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
1967 transactions.push_back(HexStr(ssTx.begin(), ssTx.end()));
1971 result.push_back(Pair("version", pblock->nVersion));
1972 result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
1973 result.push_back(Pair("transactions", transactions));
1974 result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
1975 result.push_back(Pair("coinbaseflags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end())));
1976 result.push_back(Pair("time", (int64_t)pblock->nTime));
1977 result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1));
1978 result.push_back(Pair("curtime", (int64_t)GetAdjustedTime()));
1979 result.push_back(Pair("bits", HexBits(pblock->nBits)));
1986 CDataStream ssBlock(ParseHex(params[0].get_str()), SER_NETWORK, PROTOCOL_VERSION);
1990 return ProcessBlock(NULL, &pblock);
1994 Value getblockhash(const Array& params, bool fHelp)
1996 if (fHelp || params.size() != 1)
1997 throw runtime_error(
1998 "getblockhash <index>\n"
1999 "Returns hash of block in best-block-chain at <index>.");
2001 int nHeight = params[0].get_int();
2002 if (nHeight < 0 || nHeight > nBestHeight)
2003 throw runtime_error("Block number out of range.");
2006 CBlockIndex* pblockindex = mapBlockIndex[hashBestChain];
2007 while (pblockindex->nHeight > nHeight)
2008 pblockindex = pblockindex->pprev;
2009 return pblockindex->phashBlock->GetHex();
2012 Value getblock(const Array& params, bool fHelp)
2014 if (fHelp || params.size() < 1 || params.size() > 2)
2015 throw runtime_error(
2016 "getblock <hash> [txinfo]\n"
2017 "txinfo optional to print more detailed tx info\n"
2018 "Returns details of a block with given block-hash.");
2020 std::string strHash = params[0].get_str();
2021 uint256 hash(strHash);
2023 if (mapBlockIndex.count(hash) == 0)
2024 throw JSONRPCError(-5, "Block not found");
2027 CBlockIndex* pblockindex = mapBlockIndex[hash];
2028 block.ReadFromDisk(pblockindex, true);
2030 return blockToJSON(block, pblockindex, params.size() > 1 ? params[1].get_bool() : false);
2034 // ppcoin: get information of sync-checkpoint
2035 Value getcheckpoint(const Array& params, bool fHelp)
2037 if (fHelp || params.size() != 0)
2038 throw runtime_error(
2040 "Show info of synchronized checkpoint.\n");
2043 CBlockIndex* pindexCheckpoint;
2045 result.push_back(Pair("synccheckpoint", Checkpoints::hashSyncCheckpoint.ToString().c_str()));
2046 pindexCheckpoint = mapBlockIndex[Checkpoints::hashSyncCheckpoint];
2047 result.push_back(Pair("height", pindexCheckpoint->nHeight));
2048 result.push_back(Pair("timestamp", DateTimeStrFormat(pindexCheckpoint->GetBlockTime()).c_str()));
2049 if (mapArgs.count("-checkpointkey"))
2050 result.push_back(Pair("checkpointmaster", true));
2056 // ppcoin: reserve balance from being staked for network protection
2057 Value reservebalance(const Array& params, bool fHelp)
2059 if (fHelp || params.size() > 2)
2060 throw runtime_error(
2061 "reservebalance [<reserve> [amount]]\n"
2062 "<reserve> is true or false to turn balance reserve on or off.\n"
2063 "<amount> is a real and rounded to cent.\n"
2064 "Set reserve amount not participating in network protection.\n"
2065 "If no parameters provided current setting is printed.\n");
2067 if (params.size() > 0)
2069 bool fReserve = params[0].get_bool();
2072 if (params.size() == 1)
2073 throw runtime_error("must provide amount to reserve balance.\n");
2074 int64 nAmount = AmountFromValue(params[1]);
2075 nAmount = (nAmount / CENT) * CENT; // round to cent
2077 throw runtime_error("amount cannot be negative.\n");
2078 mapArgs["-reservebalance"] = FormatMoney(nAmount).c_str();
2082 if (params.size() > 1)
2083 throw runtime_error("cannot specify amount to turn off reserve.\n");
2084 mapArgs["-reservebalance"] = "0";
2089 int64 nReserveBalance = 0;
2090 if (mapArgs.count("-reservebalance") && !ParseMoney(mapArgs["-reservebalance"], nReserveBalance))
2091 throw runtime_error("invalid reserve balance amount\n");
2092 result.push_back(Pair("reserve", (nReserveBalance > 0)));
2093 result.push_back(Pair("amount", ValueFromAmount(nReserveBalance)));
2098 // ppcoin: check wallet integrity
2099 Value checkwallet(const Array& params, bool fHelp)
2101 if (fHelp || params.size() > 0)
2102 throw runtime_error(
2104 "Check wallet for integrity.\n");
2107 int64 nBalanceInQuestion;
2109 if (pwalletMain->CheckSpentCoins(nMismatchSpent, nBalanceInQuestion))
2110 result.push_back(Pair("wallet check passed", true));
2113 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
2114 result.push_back(Pair("amount in question", ValueFromAmount(nBalanceInQuestion)));
2120 // ppcoin: repair wallet
2121 Value repairwallet(const Array& params, bool fHelp)
2123 if (fHelp || params.size() > 0)
2124 throw runtime_error(
2126 "Repair wallet if checkwallet reports any problem.\n");
2129 int64 nBalanceInQuestion;
2130 pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion);
2132 if (nMismatchSpent == 0)
2133 result.push_back(Pair("wallet check passed", true));
2136 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
2137 result.push_back(Pair("amount affected by repair", ValueFromAmount(nBalanceInQuestion)));
2142 // ppcoin: make a public-private key pair
2143 Value makekeypair(const Array& params, bool fHelp)
2145 if (fHelp || params.size() > 1)
2146 throw runtime_error(
2147 "makekeypair [prefix]\n"
2148 "Make a public/private key pair.\n"
2149 "[prefix] is optional preferred prefix for the public key.\n");
2151 string strPrefix = "";
2152 if (params.size() > 0)
2153 strPrefix = params[0].get_str();
2159 key.MakeNewKey(false);
2161 } while (nCount < 10000 && strPrefix != HexStr(key.GetPubKey()).substr(0, strPrefix.size()));
2163 if (strPrefix != HexStr(key.GetPubKey()).substr(0, strPrefix.size()))
2166 CPrivKey vchPrivKey = key.GetPrivKey();
2168 result.push_back(Pair("PrivateKey", HexStr<CPrivKey::iterator>(vchPrivKey.begin(), vchPrivKey.end())));
2169 result.push_back(Pair("PublicKey", HexStr(key.GetPubKey())));
2173 extern CCriticalSection cs_mapAlerts;
2174 extern map<uint256, CAlert> mapAlerts;
2176 // ppcoin: send alert.
2177 // There is a known deadlock situation with ThreadMessageHandler
2178 // ThreadMessageHandler: holds cs_vSend and acquiring cs_main in SendMessages()
2179 // ThreadRPCServer: holds cs_main and acquiring cs_vSend in alert.RelayTo()/PushMessage()/BeginMessage()
2180 Value sendalert(const Array& params, bool fHelp)
2182 if (fHelp || params.size() < 6)
2183 throw runtime_error(
2184 "sendalert <message> <privatekey> <minver> <maxver> <priority> <id> [cancelupto]\n"
2185 "<message> is the alert text message\n"
2186 "<privatekey> is hex string of alert master private key\n"
2187 "<minver> is the minimum applicable internal client version\n"
2188 "<maxver> is the maximum applicable internal client version\n"
2189 "<priority> is integer priority number\n"
2190 "<id> is the alert id\n"
2191 "[cancelupto] cancels all alert id's up to this number\n"
2192 "Returns true or false.");
2197 alert.strStatusBar = params[0].get_str();
2198 alert.nMinVer = params[2].get_int();
2199 alert.nMaxVer = params[3].get_int();
2200 alert.nPriority = params[4].get_int();
2201 alert.nID = params[5].get_int();
2202 if (params.size() > 6)
2203 alert.nCancel = params[6].get_int();
2204 alert.nVersion = PROTOCOL_VERSION;
2205 alert.nRelayUntil = GetAdjustedTime() + 365*24*60*60;
2206 alert.nExpiration = GetAdjustedTime() + 365*24*60*60;
2208 CDataStream sMsg(SER_NETWORK, PROTOCOL_VERSION);
2209 sMsg << (CUnsignedAlert)alert;
2210 alert.vchMsg = vector<unsigned char>(sMsg.begin(), sMsg.end());
2212 vector<unsigned char> vchPrivKey = ParseHex(params[1].get_str());
2213 key.SetPrivKey(CPrivKey(vchPrivKey.begin(), vchPrivKey.end())); // if key is not correct openssl may crash
2214 if (!key.Sign(Hash(alert.vchMsg.begin(), alert.vchMsg.end()), alert.vchSig))
2215 throw runtime_error(
2216 "Unable to sign alert, check private key?\n");
2217 if(!alert.ProcessAlert())
2218 throw runtime_error(
2219 "Failed to process alert.\n");
2223 BOOST_FOREACH(CNode* pnode, vNodes)
2224 alert.RelayTo(pnode);
2228 result.push_back(Pair("strStatusBar", alert.strStatusBar));
2229 result.push_back(Pair("nVersion", alert.nVersion));
2230 result.push_back(Pair("nMinVer", alert.nMinVer));
2231 result.push_back(Pair("nMaxVer", alert.nMaxVer));
2232 result.push_back(Pair("nPriority", alert.nPriority));
2233 result.push_back(Pair("nID", alert.nID));
2234 if (alert.nCancel > 0)
2235 result.push_back(Pair("nCancel", alert.nCancel));
2246 static const CRPCCommand vRPCCommands[] =
2247 { // name function safe mode?
2248 // ------------------------ ----------------------- ----------
2249 { "help", &help, true },
2250 { "stop", &stop, true },
2251 { "getblockcount", &getblockcount, true },
2252 { "getblocknumber", &getblocknumber, true },
2253 { "getconnectioncount", &getconnectioncount, true },
2254 { "getdifficulty", &getdifficulty, true },
2255 { "getgenerate", &getgenerate, true },
2256 { "setgenerate", &setgenerate, true },
2257 { "gethashespersec", &gethashespersec, true },
2258 { "getinfo", &getinfo, true },
2259 { "getmininginfo", &getmininginfo, true },
2260 { "getnewaddress", &getnewaddress, true },
2261 { "getaccountaddress", &getaccountaddress, true },
2262 { "setaccount", &setaccount, true },
2263 { "getaccount", &getaccount, false },
2264 { "getaddressesbyaccount", &getaddressesbyaccount, true },
2265 { "sendtoaddress", &sendtoaddress, false },
2266 { "getreceivedbyaddress", &getreceivedbyaddress, false },
2267 { "getreceivedbyaccount", &getreceivedbyaccount, false },
2268 { "listreceivedbyaddress", &listreceivedbyaddress, false },
2269 { "listreceivedbyaccount", &listreceivedbyaccount, false },
2270 { "backupwallet", &backupwallet, true },
2271 { "keypoolrefill", &keypoolrefill, true },
2272 { "walletpassphrase", &walletpassphrase, true },
2273 { "walletpassphrasechange", &walletpassphrasechange, false },
2274 { "walletlock", &walletlock, true },
2275 { "encryptwallet", &encryptwallet, false },
2276 { "validateaddress", &validateaddress, true },
2277 { "getbalance", &getbalance, false },
2278 { "move", &movecmd, false },
2279 { "sendfrom", &sendfrom, false },
2280 { "sendmany", &sendmany, false },
2281 { "addmultisigaddress", &addmultisigaddress, false },
2282 { "getblock", &getblock, false },
2283 { "getblockhash", &getblockhash, false },
2284 { "gettransaction", &gettransaction, false },
2285 { "listtransactions", &listtransactions, false },
2286 { "signmessage", &signmessage, false },
2287 { "verifymessage", &verifymessage, false },
2288 { "getwork", &getwork, true },
2289 { "listaccounts", &listaccounts, false },
2290 { "settxfee", &settxfee, false },
2291 { "getmemorypool", &getmemorypool, true },
2292 { "listsinceblock", &listsinceblock, false },
2293 { "dumpprivkey", &dumpprivkey, false },
2294 { "importprivkey", &importprivkey, false },
2295 { "getcheckpoint", &getcheckpoint, true },
2296 { "reservebalance", &reservebalance, false},
2297 { "checkwallet", &checkwallet, false},
2298 { "repairwallet", &repairwallet, false},
2299 { "makekeypair", &makekeypair, false},
2300 { "sendalert", &sendalert, false},
2303 CRPCTable::CRPCTable()
2306 for (vcidx = 0; vcidx < (sizeof(vRPCCommands) / sizeof(vRPCCommands[0])); vcidx++)
2308 const CRPCCommand *pcmd;
2310 pcmd = &vRPCCommands[vcidx];
2311 mapCommands[pcmd->name] = pcmd;
2315 const CRPCCommand *CRPCTable::operator[](string name) const
2317 map<string, const CRPCCommand*>::const_iterator it = mapCommands.find(name);
2318 if (it == mapCommands.end())
2320 return (*it).second;
2326 // This ain't Apache. We're just using HTTP header for the length field
2327 // and to be compatible with other JSON-RPC implementations.
2330 string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
2333 s << "POST / HTTP/1.1\r\n"
2334 << "User-Agent: ppcoin-json-rpc/" << FormatFullVersion() << "\r\n"
2335 << "Host: 127.0.0.1\r\n"
2336 << "Content-Type: application/json\r\n"
2337 << "Content-Length: " << strMsg.size() << "\r\n"
2338 << "Connection: close\r\n"
2339 << "Accept: application/json\r\n";
2340 BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
2341 s << item.first << ": " << item.second << "\r\n";
2342 s << "\r\n" << strMsg;
2347 string rfc1123Time()
2352 struct tm* now_gmt = gmtime(&now);
2353 string locale(setlocale(LC_TIME, NULL));
2354 setlocale(LC_TIME, "C"); // we want posix (aka "C") weekday/month strings
2355 strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt);
2356 setlocale(LC_TIME, locale.c_str());
2357 return string(buffer);
2360 static string HTTPReply(int nStatus, const string& strMsg)
2363 return strprintf("HTTP/1.0 401 Authorization Required\r\n"
2365 "Server: ppcoin-json-rpc/%s\r\n"
2366 "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
2367 "Content-Type: text/html\r\n"
2368 "Content-Length: 296\r\n"
2370 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
2371 "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
2374 "<TITLE>Error</TITLE>\r\n"
2375 "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
2377 "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
2378 "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
2379 const char *cStatus;
2380 if (nStatus == 200) cStatus = "OK";
2381 else if (nStatus == 400) cStatus = "Bad Request";
2382 else if (nStatus == 403) cStatus = "Forbidden";
2383 else if (nStatus == 404) cStatus = "Not Found";
2384 else if (nStatus == 500) cStatus = "Internal Server Error";
2387 "HTTP/1.1 %d %s\r\n"
2389 "Connection: close\r\n"
2390 "Content-Length: %d\r\n"
2391 "Content-Type: application/json\r\n"
2392 "Server: ppcoin-json-rpc/%s\r\n"
2397 rfc1123Time().c_str(),
2399 FormatFullVersion().c_str(),
2403 int ReadHTTPStatus(std::basic_istream<char>& stream)
2406 getline(stream, str);
2407 vector<string> vWords;
2408 boost::split(vWords, str, boost::is_any_of(" "));
2409 if (vWords.size() < 2)
2411 return atoi(vWords[1].c_str());
2414 int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
2420 std::getline(stream, str);
2421 if (str.empty() || str == "\r")
2423 string::size_type nColon = str.find(":");
2424 if (nColon != string::npos)
2426 string strHeader = str.substr(0, nColon);
2427 boost::trim(strHeader);
2428 boost::to_lower(strHeader);
2429 string strValue = str.substr(nColon+1);
2430 boost::trim(strValue);
2431 mapHeadersRet[strHeader] = strValue;
2432 if (strHeader == "content-length")
2433 nLen = atoi(strValue.c_str());
2439 int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
2441 mapHeadersRet.clear();
2445 int nStatus = ReadHTTPStatus(stream);
2448 int nLen = ReadHTTPHeader(stream, mapHeadersRet);
2449 if (nLen < 0 || nLen > (int)MAX_SIZE)
2455 vector<char> vch(nLen);
2456 stream.read(&vch[0], nLen);
2457 strMessageRet = string(vch.begin(), vch.end());
2463 bool HTTPAuthorized(map<string, string>& mapHeaders)
2465 string strAuth = mapHeaders["authorization"];
2466 if (strAuth.substr(0,6) != "Basic ")
2468 string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
2469 string strUserPass = DecodeBase64(strUserPass64);
2470 return strUserPass == strRPCUserColonPass;
2474 // JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
2475 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
2476 // unspecified (HTTP errors and contents of 'error').
2478 // 1.0 spec: http://json-rpc.org/wiki/specification
2479 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
2480 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
2483 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
2486 request.push_back(Pair("method", strMethod));
2487 request.push_back(Pair("params", params));
2488 request.push_back(Pair("id", id));
2489 return write_string(Value(request), false) + "\n";
2492 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
2495 if (error.type() != null_type)
2496 reply.push_back(Pair("result", Value::null));
2498 reply.push_back(Pair("result", result));
2499 reply.push_back(Pair("error", error));
2500 reply.push_back(Pair("id", id));
2501 return write_string(Value(reply), false) + "\n";
2504 void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
2506 // Send error reply from json-rpc error object
2508 int code = find_value(objError, "code").get_int();
2509 if (code == -32600) nStatus = 400;
2510 else if (code == -32601) nStatus = 404;
2511 string strReply = JSONRPCReply(Value::null, objError, id);
2512 stream << HTTPReply(nStatus, strReply) << std::flush;
2515 bool ClientAllowed(const string& strAddress)
2517 if (strAddress == asio::ip::address_v4::loopback().to_string())
2519 const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
2520 BOOST_FOREACH(string strAllow, vAllow)
2521 if (WildcardMatch(strAddress, strAllow))
2527 // IOStream device that speaks SSL but can also speak non-SSL
2529 class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
2531 SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
2533 fUseSSL = fUseSSLIn;
2534 fNeedHandshake = fUseSSLIn;
2537 void handshake(ssl::stream_base::handshake_type role)
2539 if (!fNeedHandshake) return;
2540 fNeedHandshake = false;
2541 stream.handshake(role);
2543 std::streamsize read(char* s, std::streamsize n)
2545 handshake(ssl::stream_base::server); // HTTPS servers read first
2546 if (fUseSSL) return stream.read_some(asio::buffer(s, n));
2547 return stream.next_layer().read_some(asio::buffer(s, n));
2549 std::streamsize write(const char* s, std::streamsize n)
2551 handshake(ssl::stream_base::client); // HTTPS clients write first
2552 if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
2553 return asio::write(stream.next_layer(), asio::buffer(s, n));
2555 bool connect(const std::string& server, const std::string& port)
2557 ip::tcp::resolver resolver(stream.get_io_service());
2558 ip::tcp::resolver::query query(server.c_str(), port.c_str());
2559 ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
2560 ip::tcp::resolver::iterator end;
2561 boost::system::error_code error = asio::error::host_not_found;
2562 while (error && endpoint_iterator != end)
2564 stream.lowest_layer().close();
2565 stream.lowest_layer().connect(*endpoint_iterator++, error);
2573 bool fNeedHandshake;
2578 void ThreadRPCServer(void* parg)
2580 IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
2583 vnThreadsRunning[THREAD_RPCSERVER]++;
2584 ThreadRPCServer2(parg);
2585 vnThreadsRunning[THREAD_RPCSERVER]--;
2587 catch (std::exception& e) {
2588 vnThreadsRunning[THREAD_RPCSERVER]--;
2589 PrintException(&e, "ThreadRPCServer()");
2591 vnThreadsRunning[THREAD_RPCSERVER]--;
2592 PrintException(NULL, "ThreadRPCServer()");
2594 printf("ThreadRPCServer exiting\n");
2597 void ThreadRPCServer2(void* parg)
2599 printf("ThreadRPCServer started\n");
2601 strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
2602 if (mapArgs["-rpcpassword"] == "")
2604 unsigned char rand_pwd[32];
2605 RAND_bytes(rand_pwd, 32);
2606 string strWhatAmI = "To use ppcoind";
2607 if (mapArgs.count("-server"))
2608 strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
2609 else if (mapArgs.count("-daemon"))
2610 strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
2611 ThreadSafeMessageBox(strprintf(
2612 _("%s, you must set a rpcpassword in the configuration file:\n %s\n"
2613 "It is recommended you use the following random password:\n"
2614 "rpcuser=bitcoinrpc\n"
2616 "(you do not need to remember this password)\n"
2617 "If the file does not exist, create it with owner-readable-only file permissions.\n"),
2619 GetConfigFile().string().c_str(),
2620 EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str()),
2621 _("Error"), wxOK | wxMODAL);
2626 bool fUseSSL = GetBoolArg("-rpcssl");
2627 asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
2629 asio::io_service io_service;
2630 ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", RPC_PORT));
2631 ip::tcp::acceptor acceptor(io_service);
2634 acceptor.open(endpoint.protocol());
2635 acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
2636 acceptor.bind(endpoint);
2637 acceptor.listen(socket_base::max_connections);
2639 catch(boost::system::system_error &e)
2641 ThreadSafeMessageBox(strprintf(_("An error occured while setting up the RPC port %i for listening: %s"), endpoint.port(), e.what()),
2642 _("Error"), wxOK | wxMODAL);
2647 ssl::context context(io_service, ssl::context::sslv23);
2650 context.set_options(ssl::context::no_sslv2);
2652 filesystem::path pathCertFile(GetArg("-rpcsslcertificatechainfile", "server.cert"));
2653 if (!pathCertFile.is_complete()) pathCertFile = filesystem::path(GetDataDir()) / pathCertFile;
2654 if (filesystem::exists(pathCertFile)) context.use_certificate_chain_file(pathCertFile.string());
2655 else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", pathCertFile.string().c_str());
2657 filesystem::path pathPKFile(GetArg("-rpcsslprivatekeyfile", "server.pem"));
2658 if (!pathPKFile.is_complete()) pathPKFile = filesystem::path(GetDataDir()) / pathPKFile;
2659 if (filesystem::exists(pathPKFile)) context.use_private_key_file(pathPKFile.string(), ssl::context::pem);
2660 else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pathPKFile.string().c_str());
2662 string strCiphers = GetArg("-rpcsslciphers", "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
2663 SSL_CTX_set_cipher_list(context.impl(), strCiphers.c_str());
2668 // Accept connection
2669 SSLStream sslStream(io_service, context);
2670 SSLIOStreamDevice d(sslStream, fUseSSL);
2671 iostreams::stream<SSLIOStreamDevice> stream(d);
2673 ip::tcp::endpoint peer;
2674 vnThreadsRunning[THREAD_RPCSERVER]--;
2675 acceptor.accept(sslStream.lowest_layer(), peer);
2676 vnThreadsRunning[4]++;
2680 // Restrict callers by IP
2681 if (!ClientAllowed(peer.address().to_string()))
2683 // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
2685 stream << HTTPReply(403, "") << std::flush;
2689 map<string, string> mapHeaders;
2692 boost::thread api_caller(ReadHTTP, boost::ref(stream), boost::ref(mapHeaders), boost::ref(strRequest));
2693 if (!api_caller.timed_join(boost::posix_time::seconds(GetArg("-rpctimeout", 30))))
2696 printf("ThreadRPCServer ReadHTTP timeout\n");
2700 // Check authorization
2701 if (mapHeaders.count("authorization") == 0)
2703 stream << HTTPReply(401, "") << std::flush;
2706 if (!HTTPAuthorized(mapHeaders))
2708 printf("ThreadRPCServer incorrect password attempt from %s\n",peer.address().to_string().c_str());
2709 /* Deter brute-forcing short passwords.
2710 If this results in a DOS the user really
2711 shouldn't have their RPC port exposed.*/
2712 if (mapArgs["-rpcpassword"].size() < 20)
2715 stream << HTTPReply(401, "") << std::flush;
2719 Value id = Value::null;
2724 if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
2725 throw JSONRPCError(-32700, "Parse error");
2726 const Object& request = valRequest.get_obj();
2728 // Parse id now so errors from here on will have the id
2729 id = find_value(request, "id");
2732 Value valMethod = find_value(request, "method");
2733 if (valMethod.type() == null_type)
2734 throw JSONRPCError(-32600, "Missing method");
2735 if (valMethod.type() != str_type)
2736 throw JSONRPCError(-32600, "Method must be a string");
2737 string strMethod = valMethod.get_str();
2738 if (strMethod != "getwork" && strMethod != "getmemorypool")
2739 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
2742 Value valParams = find_value(request, "params");
2744 if (valParams.type() == array_type)
2745 params = valParams.get_array();
2746 else if (valParams.type() == null_type)
2749 throw JSONRPCError(-32600, "Params must be an array");
2752 const CRPCCommand *pcmd = tableRPC[strMethod];
2754 throw JSONRPCError(-32601, "Method not found");
2756 // Observe safe mode
2757 string strWarning = GetWarnings("rpc");
2758 if (strWarning != "" && !GetBoolArg("-disablesafemode") &&
2760 throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
2767 LOCK2(cs_main, pwalletMain->cs_wallet);
2768 result = pcmd->actor(params, false);
2772 string strReply = JSONRPCReply(result, Value::null, id);
2773 stream << HTTPReply(200, strReply) << std::flush;
2775 catch (std::exception& e)
2777 ErrorReply(stream, JSONRPCError(-1, e.what()), id);
2780 catch (Object& objError)
2782 ErrorReply(stream, objError, id);
2784 catch (std::exception& e)
2786 ErrorReply(stream, JSONRPCError(-32700, e.what()), id);
2794 Object CallRPC(const string& strMethod, const Array& params)
2796 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2797 throw runtime_error(strprintf(
2798 _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
2799 "If the file does not exist, create it with owner-readable-only file permissions."),
2800 GetConfigFile().string().c_str()));
2802 // Connect to localhost
2803 bool fUseSSL = GetBoolArg("-rpcssl");
2804 asio::io_service io_service;
2805 ssl::context context(io_service, ssl::context::sslv23);
2806 context.set_options(ssl::context::no_sslv2);
2807 SSLStream sslStream(io_service, context);
2808 SSLIOStreamDevice d(sslStream, fUseSSL);
2809 iostreams::stream<SSLIOStreamDevice> stream(d);
2810 if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", CBigNum(RPC_PORT).ToString().c_str())))
2811 throw runtime_error("couldn't connect to server");
2813 // HTTP basic authentication
2814 string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
2815 map<string, string> mapRequestHeaders;
2816 mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
2819 string strRequest = JSONRPCRequest(strMethod, params, 1);
2820 string strPost = HTTPPost(strRequest, mapRequestHeaders);
2821 stream << strPost << std::flush;
2824 map<string, string> mapHeaders;
2826 int nStatus = ReadHTTP(stream, mapHeaders, strReply);
2828 throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
2829 else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
2830 throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
2831 else if (strReply.empty())
2832 throw runtime_error("no response from server");
2836 if (!read_string(strReply, valReply))
2837 throw runtime_error("couldn't parse reply from server");
2838 const Object& reply = valReply.get_obj();
2840 throw runtime_error("expected reply to have result, error and id properties");
2848 template<typename T>
2849 void ConvertTo(Value& value)
2851 if (value.type() == str_type)
2853 // reinterpret string as unquoted json value
2855 if (!read_string(value.get_str(), value2))
2856 throw runtime_error("type mismatch");
2857 value = value2.get_value<T>();
2861 value = value.get_value<T>();
2865 int CommandLineRPC(int argc, char *argv[])
2872 while (argc > 1 && IsSwitchChar(argv[1][0]))
2880 throw runtime_error("too few parameters");
2881 string strMethod = argv[1];
2883 // Parameters default to strings
2885 for (int i = 2; i < argc; i++)
2886 params.push_back(argv[i]);
2887 int n = params.size();
2890 // Special case non-string parameter types
2892 if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
2893 if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2894 if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
2895 if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]);
2896 if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2897 if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2898 if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2899 if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
2900 if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2901 if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
2902 if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2903 if (strMethod == "getblockhash" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2904 if (strMethod == "getblock" && n > 1) ConvertTo<bool>(params[1]);
2905 if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]);
2906 if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2907 if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]);
2908 if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2909 if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2910 if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2911 if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2912 if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2913 if (strMethod == "walletpassphrase" && n > 2) ConvertTo<bool>(params[2]);
2914 if (strMethod == "listsinceblock" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2915 if (strMethod == "sendalert" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2916 if (strMethod == "sendalert" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2917 if (strMethod == "sendalert" && n > 4) ConvertTo<boost::int64_t>(params[4]);
2918 if (strMethod == "sendalert" && n > 5) ConvertTo<boost::int64_t>(params[5]);
2919 if (strMethod == "sendalert" && n > 6) ConvertTo<boost::int64_t>(params[6]);
2920 if (strMethod == "sendmany" && n > 1)
2922 string s = params[1].get_str();
2924 if (!read_string(s, v) || v.type() != obj_type)
2925 throw runtime_error("type mismatch");
2926 params[1] = v.get_obj();
2928 if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2929 if (strMethod == "reservebalance" && n > 0) ConvertTo<bool>(params[0]);
2930 if (strMethod == "reservebalance" && n > 1) ConvertTo<double>(params[1]);
2931 if (strMethod == "addmultisigaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2932 if (strMethod == "addmultisigaddress" && n > 1)
2934 string s = params[1].get_str();
2936 if (!read_string(s, v) || v.type() != array_type)
2937 throw runtime_error("type mismatch "+s);
2938 params[1] = v.get_array();
2942 Object reply = CallRPC(strMethod, params);
2945 const Value& result = find_value(reply, "result");
2946 const Value& error = find_value(reply, "error");
2948 if (error.type() != null_type)
2951 strPrint = "error: " + write_string(error, false);
2952 int code = find_value(error.get_obj(), "code").get_int();
2958 if (result.type() == null_type)
2960 else if (result.type() == str_type)
2961 strPrint = result.get_str();
2963 strPrint = write_string(result, true);
2966 catch (std::exception& e)
2968 strPrint = string("error: ") + e.what();
2973 PrintException(NULL, "CommandLineRPC()");
2978 fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
2987 int main(int argc, char *argv[])
2990 // Turn off microsoft heap dump noise
2991 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
2992 _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
2994 setbuf(stdin, NULL);
2995 setbuf(stdout, NULL);
2996 setbuf(stderr, NULL);
3000 if (argc >= 2 && string(argv[1]) == "-server")
3002 printf("server ready\n");
3003 ThreadRPCServer(NULL);
3007 return CommandLineRPC(argc, argv);
3010 catch (std::exception& e) {
3011 PrintException(&e, "main()");
3013 PrintException(NULL, "main()");
3019 const CRPCTable tableRPC;