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)
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", (boost::int64_t)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)));
152 BOOST_FOREACH (const CTransaction&tx, block.vtx)
153 txhashes.push_back(tx.GetHash().GetHex());
154 result.push_back(Pair("tx", txhashes));
156 if (blockindex->pprev)
157 result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex()));
158 if (blockindex->pnext)
159 result.push_back(Pair("nextblockhash", blockindex->pnext->GetBlockHash().GetHex()));
166 /// Note: This interface may still be subject to change.
169 string CRPCTable::help(string strCommand) const
172 set<rpcfn_type> setDone;
173 for (map<string, const CRPCCommand*>::const_iterator mi = mapCommands.begin(); mi != mapCommands.end(); ++mi)
175 const CRPCCommand *pcmd = mi->second;
176 string strMethod = mi->first;
177 // We already filter duplicates, but these deprecated screw up the sort order
178 if (strMethod == "getamountreceived" ||
179 strMethod == "getallreceived" ||
180 strMethod == "getblocknumber" || // deprecated
181 (strMethod.find("label") != string::npos))
183 if (strCommand != "" && strMethod != strCommand)
188 rpcfn_type pfn = pcmd->actor;
189 if (setDone.insert(pfn).second)
190 (*pfn)(params, true);
192 catch (std::exception& e)
194 // Help text is returned in an exception
195 string strHelp = string(e.what());
196 if (strCommand == "")
197 if (strHelp.find('\n') != string::npos)
198 strHelp = strHelp.substr(0, strHelp.find('\n'));
199 strRet += strHelp + "\n";
203 strRet = strprintf("help: unknown command: %s\n", strCommand.c_str());
204 strRet = strRet.substr(0,strRet.size()-1);
208 Value help(const Array& params, bool fHelp)
210 if (fHelp || params.size() > 1)
213 "List commands, or get help for a command.");
216 if (params.size() > 0)
217 strCommand = params[0].get_str();
219 return tableRPC.help(strCommand);
223 Value stop(const Array& params, bool fHelp)
225 if (fHelp || params.size() != 0)
228 "Stop ppcoin server.");
229 // Shutdown will take long enough that the response should get back
231 return "ppcoin server stopping";
235 Value getblockcount(const Array& params, bool fHelp)
237 if (fHelp || params.size() != 0)
240 "Returns the number of blocks in the longest block chain.");
247 Value getblocknumber(const Array& params, bool fHelp)
249 if (fHelp || params.size() != 0)
252 "Deprecated. Use getblockcount.");
258 Value getconnectioncount(const Array& params, bool fHelp)
260 if (fHelp || params.size() != 0)
262 "getconnectioncount\n"
263 "Returns the number of connections to other nodes.");
265 return (int)vNodes.size();
269 Value getdifficulty(const Array& params, bool fHelp)
271 if (fHelp || params.size() != 0)
274 "Returns difficulty as a multiple of the minimum difficulty.");
277 obj.push_back(Pair("proof-of-work", GetDifficulty()));
278 obj.push_back(Pair("proof-of-stake", GetDifficulty(GetLastBlockIndex(pindexBest, true))));
283 Value getgenerate(const Array& params, bool fHelp)
285 if (fHelp || params.size() != 0)
288 "Returns true or false.");
290 return GetBoolArg("-gen");
294 Value setgenerate(const Array& params, bool fHelp)
296 if (fHelp || params.size() < 1 || params.size() > 2)
298 "setgenerate <generate> [genproclimit]\n"
299 "<generate> is true or false to turn generation on or off.\n"
300 "Generation is limited to [genproclimit] processors, -1 is unlimited.");
302 bool fGenerate = true;
303 if (params.size() > 0)
304 fGenerate = params[0].get_bool();
306 if (params.size() > 1)
308 int nGenProcLimit = params[1].get_int();
309 mapArgs["-genproclimit"] = itostr(nGenProcLimit);
310 if (nGenProcLimit == 0)
313 mapArgs["-gen"] = (fGenerate ? "1" : "0");
315 GenerateBitcoins(fGenerate, pwalletMain);
320 Value gethashespersec(const Array& params, bool fHelp)
322 if (fHelp || params.size() != 0)
325 "Returns a recent hashes per second performance measurement while generating.");
327 if (GetTimeMillis() - nHPSTimerStart > 8000)
328 return (boost::int64_t)0;
329 return (boost::int64_t)dHashesPerSec;
333 Value getinfo(const Array& params, bool fHelp)
335 if (fHelp || params.size() != 0)
338 "Returns an object containing various state info.");
341 obj.push_back(Pair("version", FormatFullVersion()));
342 obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION));
343 obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
344 obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
345 obj.push_back(Pair("newmint", ValueFromAmount(pwalletMain->GetNewMint())));
346 obj.push_back(Pair("stake", ValueFromAmount(pwalletMain->GetStake())));
347 obj.push_back(Pair("blocks", (int)nBestHeight));
348 obj.push_back(Pair("connections", (int)vNodes.size()));
349 obj.push_back(Pair("proxy", (fUseProxy ? addrProxy.ToStringIPPort() : string())));
350 obj.push_back(Pair("ip", addrSeenByPeer.ToStringIP()));
351 obj.push_back(Pair("difficulty", (double)GetDifficulty()));
352 obj.push_back(Pair("testnet", fTestNet));
353 obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));
354 obj.push_back(Pair("keypoolsize", pwalletMain->GetKeyPoolSize()));
355 obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee)));
356 if (pwalletMain->IsCrypted())
357 obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime / 1000));
358 obj.push_back(Pair("errors", GetWarnings("statusbar")));
363 Value getmininginfo(const Array& params, bool fHelp)
365 if (fHelp || params.size() != 0)
368 "Returns an object containing mining-related information.");
371 obj.push_back(Pair("blocks", (int)nBestHeight));
372 obj.push_back(Pair("currentblocksize",(uint64_t)nLastBlockSize));
373 obj.push_back(Pair("currentblocktx",(uint64_t)nLastBlockTx));
374 obj.push_back(Pair("difficulty", (double)GetDifficulty()));
375 obj.push_back(Pair("errors", GetWarnings("statusbar")));
376 obj.push_back(Pair("generate", GetBoolArg("-gen")));
377 obj.push_back(Pair("genproclimit", (int)GetArg("-genproclimit", -1)));
378 obj.push_back(Pair("hashespersec", gethashespersec(params, false)));
379 obj.push_back(Pair("pooledtx", (uint64_t)mempool.size()));
380 obj.push_back(Pair("testnet", fTestNet));
385 Value getnewaddress(const Array& params, bool fHelp)
387 if (fHelp || params.size() > 1)
389 "getnewaddress [account]\n"
390 "Returns a new ppcoin address for receiving payments. "
391 "If [account] is specified (recommended), it is added to the address book "
392 "so payments received with the address will be credited to [account].");
394 // Parse the account first so we don't generate a key if there's an error
396 if (params.size() > 0)
397 strAccount = AccountFromValue(params[0]);
399 if (!pwalletMain->IsLocked())
400 pwalletMain->TopUpKeyPool();
402 // Generate a new key that is added to wallet
403 std::vector<unsigned char> newKey;
404 if (!pwalletMain->GetKeyFromPool(newKey, false))
405 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
406 CBitcoinAddress address(newKey);
408 pwalletMain->SetAddressBookName(address, strAccount);
410 return address.ToString();
414 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
416 CWalletDB walletdb(pwalletMain->strWalletFile);
419 walletdb.ReadAccount(strAccount, account);
421 bool bKeyUsed = false;
423 // Check if the current key has been used
424 if (!account.vchPubKey.empty())
426 CScript scriptPubKey;
427 scriptPubKey.SetBitcoinAddress(account.vchPubKey);
428 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
429 it != pwalletMain->mapWallet.end() && !account.vchPubKey.empty();
432 const CWalletTx& wtx = (*it).second;
433 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
434 if (txout.scriptPubKey == scriptPubKey)
439 // Generate a new key
440 if (account.vchPubKey.empty() || bForceNew || bKeyUsed)
442 if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false))
443 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
445 pwalletMain->SetAddressBookName(CBitcoinAddress(account.vchPubKey), strAccount);
446 walletdb.WriteAccount(strAccount, account);
449 return CBitcoinAddress(account.vchPubKey);
452 Value getaccountaddress(const Array& params, bool fHelp)
454 if (fHelp || params.size() != 1)
456 "getaccountaddress <account>\n"
457 "Returns the current ppcoin address for receiving payments to this account.");
459 // Parse the account first so we don't generate a key if there's an error
460 string strAccount = AccountFromValue(params[0]);
464 ret = GetAccountAddress(strAccount).ToString();
471 Value setaccount(const Array& params, bool fHelp)
473 if (fHelp || params.size() < 1 || params.size() > 2)
475 "setaccount <ppcoinaddress> <account>\n"
476 "Sets the account associated with the given address.");
478 CBitcoinAddress address(params[0].get_str());
479 if (!address.IsValid())
480 throw JSONRPCError(-5, "Invalid ppcoin address");
484 if (params.size() > 1)
485 strAccount = AccountFromValue(params[1]);
487 // Detect when changing the account of an address that is the 'unused current key' of another account:
488 if (pwalletMain->mapAddressBook.count(address))
490 string strOldAccount = pwalletMain->mapAddressBook[address];
491 if (address == GetAccountAddress(strOldAccount))
492 GetAccountAddress(strOldAccount, true);
495 pwalletMain->SetAddressBookName(address, strAccount);
501 Value getaccount(const Array& params, bool fHelp)
503 if (fHelp || params.size() != 1)
505 "getaccount <ppcoinaddress>\n"
506 "Returns the account associated with the given address.");
508 CBitcoinAddress address(params[0].get_str());
509 if (!address.IsValid())
510 throw JSONRPCError(-5, "Invalid ppcoin address");
513 map<CBitcoinAddress, string>::iterator mi = pwalletMain->mapAddressBook.find(address);
514 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
515 strAccount = (*mi).second;
520 Value getaddressesbyaccount(const Array& params, bool fHelp)
522 if (fHelp || params.size() != 1)
524 "getaddressesbyaccount <account>\n"
525 "Returns the list of addresses for the given account.");
527 string strAccount = AccountFromValue(params[0]);
529 // Find all addresses that have the given account
531 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
533 const CBitcoinAddress& address = item.first;
534 const string& strName = item.second;
535 if (strName == strAccount)
536 ret.push_back(address.ToString());
541 Value settxfee(const Array& params, bool fHelp)
543 if (fHelp || params.size() < 1 || params.size() > 1 || AmountFromValue(params[0]) < MIN_TX_FEE)
545 "settxfee <amount>\n"
546 "<amount> is a real and is rounded to 0.01 (cent)\n"
547 "Minimum and default transaction fee per KB is 1 cent");
549 nTransactionFee = AmountFromValue(params[0]);
550 nTransactionFee = (nTransactionFee / CENT) * CENT; // round to cent
554 Value sendtoaddress(const Array& params, bool fHelp)
556 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
558 "sendtoaddress <ppcoinaddress> <amount> [comment] [comment-to]\n"
559 "<amount> is a real and is rounded to the nearest 0.000001\n"
560 "requires wallet passphrase to be set with walletpassphrase first");
561 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
563 "sendtoaddress <ppcoinaddress> <amount> [comment] [comment-to]\n"
564 "<amount> is a real and is rounded to the nearest 0.000001");
566 CBitcoinAddress address(params[0].get_str());
567 if (!address.IsValid())
568 throw JSONRPCError(-5, "Invalid ppcoin address");
571 int64 nAmount = AmountFromValue(params[1]);
572 if (nAmount < MIN_TXOUT_AMOUNT)
573 throw JSONRPCError(-101, "Send amount too small");
577 if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
578 wtx.mapValue["comment"] = params[2].get_str();
579 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
580 wtx.mapValue["to"] = params[3].get_str();
582 if (pwalletMain->IsLocked())
583 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
585 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
587 throw JSONRPCError(-4, strError);
589 return wtx.GetHash().GetHex();
592 Value signmessage(const Array& params, bool fHelp)
594 if (fHelp || params.size() != 2)
596 "signmessage <ppcoinaddress> <message>\n"
597 "Sign a message with the private key of an address");
599 if (pwalletMain->IsLocked())
600 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
602 string strAddress = params[0].get_str();
603 string strMessage = params[1].get_str();
605 CBitcoinAddress addr(strAddress);
607 throw JSONRPCError(-3, "Invalid address");
610 if (!pwalletMain->GetKey(addr, key))
611 throw JSONRPCError(-4, "Private key not available");
613 CDataStream ss(SER_GETHASH, 0);
614 ss << strMessageMagic;
617 vector<unsigned char> vchSig;
618 if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig))
619 throw JSONRPCError(-5, "Sign failed");
621 return EncodeBase64(&vchSig[0], vchSig.size());
624 Value verifymessage(const Array& params, bool fHelp)
626 if (fHelp || params.size() != 3)
628 "verifymessage <ppcoinaddress> <signature> <message>\n"
629 "Verify a signed message");
631 string strAddress = params[0].get_str();
632 string strSign = params[1].get_str();
633 string strMessage = params[2].get_str();
635 CBitcoinAddress addr(strAddress);
637 throw JSONRPCError(-3, "Invalid address");
639 bool fInvalid = false;
640 vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
643 throw JSONRPCError(-5, "Malformed base64 encoding");
645 CDataStream ss(SER_GETHASH, 0);
646 ss << strMessageMagic;
650 if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
653 return (CBitcoinAddress(key.GetPubKey()) == addr);
657 Value getreceivedbyaddress(const Array& params, bool fHelp)
659 if (fHelp || params.size() < 1 || params.size() > 2)
661 "getreceivedbyaddress <ppcoinaddress> [minconf=1]\n"
662 "Returns the total amount received by <ppcoinaddress> in transactions with at least [minconf] confirmations.");
665 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
666 CScript scriptPubKey;
667 if (!address.IsValid())
668 throw JSONRPCError(-5, "Invalid ppcoin address");
669 scriptPubKey.SetBitcoinAddress(address);
670 if (!IsMine(*pwalletMain,scriptPubKey))
673 // Minimum confirmations
675 if (params.size() > 1)
676 nMinDepth = params[1].get_int();
680 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
682 const CWalletTx& wtx = (*it).second;
683 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
686 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
687 if (txout.scriptPubKey == scriptPubKey)
688 if (wtx.GetDepthInMainChain() >= nMinDepth)
689 nAmount += txout.nValue;
692 return ValueFromAmount(nAmount);
696 void GetAccountAddresses(string strAccount, set<CBitcoinAddress>& setAddress)
698 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
700 const CBitcoinAddress& address = item.first;
701 const string& strName = item.second;
702 if (strName == strAccount)
703 setAddress.insert(address);
708 Value getreceivedbyaccount(const Array& params, bool fHelp)
710 if (fHelp || params.size() < 1 || params.size() > 2)
712 "getreceivedbyaccount <account> [minconf=1]\n"
713 "Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.");
715 // Minimum confirmations
717 if (params.size() > 1)
718 nMinDepth = params[1].get_int();
720 // Get the set of pub keys assigned to account
721 string strAccount = AccountFromValue(params[0]);
722 set<CBitcoinAddress> setAddress;
723 GetAccountAddresses(strAccount, setAddress);
727 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
729 const CWalletTx& wtx = (*it).second;
730 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
733 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
735 CBitcoinAddress address;
736 if (ExtractAddress(txout.scriptPubKey, address) && pwalletMain->HaveKey(address) && setAddress.count(address))
737 if (wtx.GetDepthInMainChain() >= nMinDepth)
738 nAmount += txout.nValue;
742 return (double)nAmount / (double)COIN;
746 int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth)
750 // Tally wallet transactions
751 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
753 const CWalletTx& wtx = (*it).second;
757 int64 nGenerated, nReceived, nSent, nFee;
758 wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee);
760 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
761 nBalance += nReceived;
762 nBalance += nGenerated - nSent - nFee;
765 // Tally internal accounting entries
766 nBalance += walletdb.GetAccountCreditDebit(strAccount);
771 int64 GetAccountBalance(const string& strAccount, int nMinDepth)
773 CWalletDB walletdb(pwalletMain->strWalletFile);
774 return GetAccountBalance(walletdb, strAccount, nMinDepth);
778 Value getbalance(const Array& params, bool fHelp)
780 if (fHelp || params.size() > 2)
782 "getbalance [account] [minconf=1]\n"
783 "If [account] is not specified, returns the server's total available balance.\n"
784 "If [account] is specified, returns the balance in the account.");
786 if (params.size() == 0)
787 return ValueFromAmount(pwalletMain->GetBalance());
790 if (params.size() > 1)
791 nMinDepth = params[1].get_int();
793 if (params[0].get_str() == "*") {
794 // Calculate total balance a different way from GetBalance()
795 // (GetBalance() sums up all unspent TxOuts)
796 // getbalance and getbalance '*' should always return the same number.
798 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
800 const CWalletTx& wtx = (*it).second;
804 int64 allGeneratedImmature, allGeneratedMature, allFee;
805 allGeneratedImmature = allGeneratedMature = allFee = 0;
806 string strSentAccount;
807 list<pair<CBitcoinAddress, int64> > listReceived;
808 list<pair<CBitcoinAddress, int64> > listSent;
809 wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
810 if (wtx.GetDepthInMainChain() >= nMinDepth)
812 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listReceived)
813 nBalance += r.second;
815 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listSent)
816 nBalance -= r.second;
818 nBalance += allGeneratedMature;
820 return ValueFromAmount(nBalance);
823 string strAccount = AccountFromValue(params[0]);
825 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
827 return ValueFromAmount(nBalance);
831 Value movecmd(const Array& params, bool fHelp)
833 if (fHelp || params.size() < 3 || params.size() > 5)
835 "move <fromaccount> <toaccount> <amount> [minconf=1] [comment]\n"
836 "Move from one account in your wallet to another.");
838 string strFrom = AccountFromValue(params[0]);
839 string strTo = AccountFromValue(params[1]);
840 int64 nAmount = AmountFromValue(params[2]);
841 if (params.size() > 3)
842 // unused parameter, used to be nMinDepth, keep type-checking it though
843 (void)params[3].get_int();
845 if (params.size() > 4)
846 strComment = params[4].get_str();
848 CWalletDB walletdb(pwalletMain->strWalletFile);
849 if (!walletdb.TxnBegin())
850 throw JSONRPCError(-20, "database error");
852 int64 nNow = GetAdjustedTime();
855 CAccountingEntry debit;
856 debit.strAccount = strFrom;
857 debit.nCreditDebit = -nAmount;
859 debit.strOtherAccount = strTo;
860 debit.strComment = strComment;
861 walletdb.WriteAccountingEntry(debit);
864 CAccountingEntry credit;
865 credit.strAccount = strTo;
866 credit.nCreditDebit = nAmount;
868 credit.strOtherAccount = strFrom;
869 credit.strComment = strComment;
870 walletdb.WriteAccountingEntry(credit);
872 if (!walletdb.TxnCommit())
873 throw JSONRPCError(-20, "database error");
879 Value sendfrom(const Array& params, bool fHelp)
881 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
883 "sendfrom <fromaccount> <toppcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
884 "<amount> is a real and is rounded to the nearest 0.000001\n"
885 "requires wallet passphrase to be set with walletpassphrase first");
886 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
888 "sendfrom <fromaccount> <toppcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
889 "<amount> is a real and is rounded to the nearest 0.000001");
891 string strAccount = AccountFromValue(params[0]);
892 CBitcoinAddress address(params[1].get_str());
893 if (!address.IsValid())
894 throw JSONRPCError(-5, "Invalid ppcoin address");
895 int64 nAmount = AmountFromValue(params[2]);
896 if (nAmount < MIN_TXOUT_AMOUNT)
897 throw JSONRPCError(-101, "Send amount too small");
899 if (params.size() > 3)
900 nMinDepth = params[3].get_int();
903 wtx.strFromAccount = strAccount;
904 if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
905 wtx.mapValue["comment"] = params[4].get_str();
906 if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
907 wtx.mapValue["to"] = params[5].get_str();
909 if (pwalletMain->IsLocked())
910 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
913 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
914 if (nAmount > nBalance)
915 throw JSONRPCError(-6, "Account has insufficient funds");
918 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
920 throw JSONRPCError(-4, strError);
922 return wtx.GetHash().GetHex();
926 Value sendmany(const Array& params, bool fHelp)
928 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
930 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
931 "amounts are double-precision floating point numbers\n"
932 "requires wallet passphrase to be set with walletpassphrase first");
933 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
935 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
936 "amounts are double-precision floating point numbers");
938 string strAccount = AccountFromValue(params[0]);
939 Object sendTo = params[1].get_obj();
941 if (params.size() > 2)
942 nMinDepth = params[2].get_int();
945 wtx.strFromAccount = strAccount;
946 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
947 wtx.mapValue["comment"] = params[3].get_str();
949 set<CBitcoinAddress> setAddress;
950 vector<pair<CScript, int64> > vecSend;
952 int64 totalAmount = 0;
953 BOOST_FOREACH(const Pair& s, sendTo)
955 CBitcoinAddress address(s.name_);
956 if (!address.IsValid())
957 throw JSONRPCError(-5, string("Invalid ppcoin address:")+s.name_);
959 if (setAddress.count(address))
960 throw JSONRPCError(-8, string("Invalid parameter, duplicated address: ")+s.name_);
961 setAddress.insert(address);
963 CScript scriptPubKey;
964 scriptPubKey.SetBitcoinAddress(address);
965 int64 nAmount = AmountFromValue(s.value_);
966 if (nAmount < MIN_TXOUT_AMOUNT)
967 throw JSONRPCError(-101, "Send amount too small");
968 totalAmount += nAmount;
970 vecSend.push_back(make_pair(scriptPubKey, nAmount));
973 if (pwalletMain->IsLocked())
974 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
975 if (fWalletUnlockStakeOnly)
976 throw JSONRPCError(-13, "Error: Wallet unlocked for coinstake only.");
979 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
980 if (totalAmount > nBalance)
981 throw JSONRPCError(-6, "Account has insufficient funds");
984 CReserveKey keyChange(pwalletMain);
985 int64 nFeeRequired = 0;
986 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
989 if (totalAmount + nFeeRequired > pwalletMain->GetBalance())
990 throw JSONRPCError(-6, "Insufficient funds");
991 throw JSONRPCError(-4, "Transaction creation failed");
993 if (!pwalletMain->CommitTransaction(wtx, keyChange))
994 throw JSONRPCError(-4, "Transaction commit failed");
996 return wtx.GetHash().GetHex();
999 Value addmultisigaddress(const Array& params, bool fHelp)
1001 if (fHelp || params.size() < 2 || params.size() > 3)
1003 string msg = "addmultisigaddress <nrequired> <'[\"key\",\"key\"]'> [account]\n"
1004 "Add a nrequired-to-sign multisignature address to the wallet\"\n"
1005 "each key is a bitcoin address or hex-encoded public key\n"
1006 "If [account] is specified, assign address to [account].";
1007 throw runtime_error(msg);
1010 int nRequired = params[0].get_int();
1011 const Array& keys = params[1].get_array();
1013 if (params.size() > 2)
1014 strAccount = AccountFromValue(params[2]);
1016 // Gather public keys
1018 throw runtime_error("a multisignature address must require at least one key to redeem");
1019 if ((int)keys.size() < nRequired)
1020 throw runtime_error(
1021 strprintf("not enough keys supplied "
1022 "(got %d keys, but need at least %d to redeem)", keys.size(), nRequired));
1023 std::vector<CKey> pubkeys;
1024 pubkeys.resize(keys.size());
1025 for (unsigned int i = 0; i < keys.size(); i++)
1027 const std::string& ks = keys[i].get_str();
1029 // Case 1: bitcoin address and we have full public key:
1030 CBitcoinAddress address(ks);
1031 if (address.IsValid())
1033 if (address.IsScript())
1034 throw runtime_error(
1035 strprintf("%s is a pay-to-script address",ks.c_str()));
1036 std::vector<unsigned char> vchPubKey;
1037 if (!pwalletMain->GetPubKey(address, vchPubKey))
1038 throw runtime_error(
1039 strprintf("no full public key for address %s",ks.c_str()));
1040 if (vchPubKey.empty() || !pubkeys[i].SetPubKey(vchPubKey))
1041 throw runtime_error(" Invalid public key: "+ks);
1044 // Case 2: hex public key
1047 vector<unsigned char> vchPubKey = ParseHex(ks);
1048 if (vchPubKey.empty() || !pubkeys[i].SetPubKey(vchPubKey))
1049 throw runtime_error(" Invalid public key: "+ks);
1053 throw runtime_error(" Invalid public key: "+ks);
1057 // Construct using pay-to-script-hash:
1059 inner.SetMultisig(nRequired, pubkeys);
1061 uint160 scriptHash = Hash160(inner);
1062 CScript scriptPubKey;
1063 scriptPubKey.SetPayToScriptHash(inner);
1064 pwalletMain->AddCScript(inner);
1065 CBitcoinAddress address;
1066 address.SetScriptHash160(scriptHash);
1068 pwalletMain->SetAddressBookName(address, strAccount);
1069 return address.ToString();
1080 nConf = std::numeric_limits<int>::max();
1084 Value ListReceived(const Array& params, bool fByAccounts)
1086 // Minimum confirmations
1088 if (params.size() > 0)
1089 nMinDepth = params[0].get_int();
1091 // Whether to include empty accounts
1092 bool fIncludeEmpty = false;
1093 if (params.size() > 1)
1094 fIncludeEmpty = params[1].get_bool();
1097 map<CBitcoinAddress, tallyitem> mapTally;
1098 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1100 const CWalletTx& wtx = (*it).second;
1102 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
1105 int nDepth = wtx.GetDepthInMainChain();
1106 if (nDepth < nMinDepth)
1109 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
1111 CBitcoinAddress address;
1112 if (!ExtractAddress(txout.scriptPubKey, address) || !pwalletMain->HaveKey(address) || !address.IsValid())
1115 tallyitem& item = mapTally[address];
1116 item.nAmount += txout.nValue;
1117 item.nConf = min(item.nConf, nDepth);
1123 map<string, tallyitem> mapAccountTally;
1124 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
1126 const CBitcoinAddress& address = item.first;
1127 const string& strAccount = item.second;
1128 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
1129 if (it == mapTally.end() && !fIncludeEmpty)
1133 int nConf = std::numeric_limits<int>::max();
1134 if (it != mapTally.end())
1136 nAmount = (*it).second.nAmount;
1137 nConf = (*it).second.nConf;
1142 tallyitem& item = mapAccountTally[strAccount];
1143 item.nAmount += nAmount;
1144 item.nConf = min(item.nConf, nConf);
1149 obj.push_back(Pair("address", address.ToString()));
1150 obj.push_back(Pair("account", strAccount));
1151 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1152 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1159 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
1161 int64 nAmount = (*it).second.nAmount;
1162 int nConf = (*it).second.nConf;
1164 obj.push_back(Pair("account", (*it).first));
1165 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1166 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1174 Value listreceivedbyaddress(const Array& params, bool fHelp)
1176 if (fHelp || params.size() > 2)
1177 throw runtime_error(
1178 "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
1179 "[minconf] is the minimum number of confirmations before payments are included.\n"
1180 "[includeempty] whether to include addresses that haven't received any payments.\n"
1181 "Returns an array of objects containing:\n"
1182 " \"address\" : receiving address\n"
1183 " \"account\" : the account of the receiving address\n"
1184 " \"amount\" : total amount received by the address\n"
1185 " \"confirmations\" : number of confirmations of the most recent transaction included");
1187 return ListReceived(params, false);
1190 Value listreceivedbyaccount(const Array& params, bool fHelp)
1192 if (fHelp || params.size() > 2)
1193 throw runtime_error(
1194 "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
1195 "[minconf] is the minimum number of confirmations before payments are included.\n"
1196 "[includeempty] whether to include accounts that haven't received any payments.\n"
1197 "Returns an array of objects containing:\n"
1198 " \"account\" : the account of the receiving addresses\n"
1199 " \"amount\" : total amount received by addresses with this account\n"
1200 " \"confirmations\" : number of confirmations of the most recent transaction included");
1202 return ListReceived(params, true);
1205 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret)
1207 int64 nGeneratedImmature, nGeneratedMature, nFee;
1208 string strSentAccount;
1209 list<pair<CBitcoinAddress, int64> > listReceived;
1210 list<pair<CBitcoinAddress, int64> > listSent;
1212 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1214 bool fAllAccounts = (strAccount == string("*"));
1216 // Generated blocks assigned to account ""
1217 if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == ""))
1220 entry.push_back(Pair("account", string("")));
1221 if (nGeneratedImmature)
1223 entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
1224 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
1228 entry.push_back(Pair("category", "generate"));
1229 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
1232 WalletTxToJSON(wtx, entry);
1233 ret.push_back(entry);
1237 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1239 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1242 entry.push_back(Pair("account", strSentAccount));
1243 entry.push_back(Pair("address", s.first.ToString()));
1244 entry.push_back(Pair("category", "send"));
1245 entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1246 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1248 WalletTxToJSON(wtx, entry);
1249 ret.push_back(entry);
1254 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1256 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1259 if (pwalletMain->mapAddressBook.count(r.first))
1260 account = pwalletMain->mapAddressBook[r.first];
1261 if (fAllAccounts || (account == strAccount))
1264 entry.push_back(Pair("account", account));
1265 entry.push_back(Pair("address", r.first.ToString()));
1266 entry.push_back(Pair("category", "receive"));
1267 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1269 WalletTxToJSON(wtx, entry);
1270 ret.push_back(entry);
1276 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1278 bool fAllAccounts = (strAccount == string("*"));
1280 if (fAllAccounts || acentry.strAccount == strAccount)
1283 entry.push_back(Pair("account", acentry.strAccount));
1284 entry.push_back(Pair("category", "move"));
1285 entry.push_back(Pair("time", (boost::int64_t)acentry.nTime));
1286 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1287 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1288 entry.push_back(Pair("comment", acentry.strComment));
1289 ret.push_back(entry);
1293 Value listtransactions(const Array& params, bool fHelp)
1295 if (fHelp || params.size() > 3)
1296 throw runtime_error(
1297 "listtransactions [account] [count=10] [from=0]\n"
1298 "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1300 string strAccount = "*";
1301 if (params.size() > 0)
1302 strAccount = params[0].get_str();
1304 if (params.size() > 1)
1305 nCount = params[1].get_int();
1307 if (params.size() > 2)
1308 nFrom = params[2].get_int();
1311 throw JSONRPCError(-8, "Negative count");
1313 throw JSONRPCError(-8, "Negative from");
1316 CWalletDB walletdb(pwalletMain->strWalletFile);
1318 // First: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap.
1319 typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
1320 typedef multimap<int64, TxPair > TxItems;
1323 // Note: maintaining indices in the database of (account,time) --> txid and (account, time) --> acentry
1324 // would make this much faster for applications that do this a lot.
1325 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1327 CWalletTx* wtx = &((*it).second);
1328 txByTime.insert(make_pair(wtx->GetTxTime(), TxPair(wtx, (CAccountingEntry*)0)));
1330 list<CAccountingEntry> acentries;
1331 walletdb.ListAccountCreditDebit(strAccount, acentries);
1332 BOOST_FOREACH(CAccountingEntry& entry, acentries)
1334 txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
1337 // iterate backwards until we have nCount items to return:
1338 for (TxItems::reverse_iterator it = txByTime.rbegin(); it != txByTime.rend(); ++it)
1340 CWalletTx *const pwtx = (*it).second.first;
1342 ListTransactions(*pwtx, strAccount, 0, true, ret);
1343 CAccountingEntry *const pacentry = (*it).second.second;
1345 AcentryToJSON(*pacentry, strAccount, ret);
1347 if (ret.size() >= (nCount+nFrom)) break;
1349 // ret is newest to oldest
1351 if (nFrom > (int)ret.size())
1353 if ((nFrom + nCount) > (int)ret.size())
1354 nCount = ret.size() - nFrom;
1355 Array::iterator first = ret.begin();
1356 std::advance(first, nFrom);
1357 Array::iterator last = ret.begin();
1358 std::advance(last, nFrom+nCount);
1360 if (last != ret.end()) ret.erase(last, ret.end());
1361 if (first != ret.begin()) ret.erase(ret.begin(), first);
1363 std::reverse(ret.begin(), ret.end()); // Return oldest to newest
1368 Value listaccounts(const Array& params, bool fHelp)
1370 if (fHelp || params.size() > 1)
1371 throw runtime_error(
1372 "listaccounts [minconf=1]\n"
1373 "Returns Object that has account names as keys, account balances as values.");
1376 if (params.size() > 0)
1377 nMinDepth = params[0].get_int();
1379 map<string, int64> mapAccountBalances;
1380 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& entry, pwalletMain->mapAddressBook) {
1381 if (pwalletMain->HaveKey(entry.first)) // This address belongs to me
1382 mapAccountBalances[entry.second] = 0;
1385 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1387 const CWalletTx& wtx = (*it).second;
1388 int64 nGeneratedImmature, nGeneratedMature, nFee;
1389 string strSentAccount;
1390 list<pair<CBitcoinAddress, int64> > listReceived;
1391 list<pair<CBitcoinAddress, int64> > listSent;
1392 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1393 mapAccountBalances[strSentAccount] -= nFee;
1394 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1395 mapAccountBalances[strSentAccount] -= s.second;
1396 if (wtx.GetDepthInMainChain() >= nMinDepth)
1398 mapAccountBalances[""] += nGeneratedMature;
1399 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1400 if (pwalletMain->mapAddressBook.count(r.first))
1401 mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1403 mapAccountBalances[""] += r.second;
1407 list<CAccountingEntry> acentries;
1408 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1409 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1410 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1413 BOOST_FOREACH(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) {
1414 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1419 Value listsinceblock(const Array& params, bool fHelp)
1422 throw runtime_error(
1423 "listsinceblock [blockhash] [target-confirmations]\n"
1424 "Get all transactions in blocks since block [blockhash], or all transactions if omitted");
1426 CBlockIndex *pindex = NULL;
1427 int target_confirms = 1;
1429 if (params.size() > 0)
1431 uint256 blockId = 0;
1433 blockId.SetHex(params[0].get_str());
1434 pindex = CBlockLocator(blockId).GetBlockIndex();
1437 if (params.size() > 1)
1439 target_confirms = params[1].get_int();
1441 if (target_confirms < 1)
1442 throw JSONRPCError(-8, "Invalid parameter");
1445 int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1;
1449 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1451 CWalletTx tx = (*it).second;
1453 if (depth == -1 || tx.GetDepthInMainChain() < depth)
1454 ListTransactions(tx, "*", 0, true, transactions);
1459 if (target_confirms == 1)
1461 lastblock = hashBestChain;
1465 int target_height = pindexBest->nHeight + 1 - target_confirms;
1468 for (block = pindexBest;
1469 block && block->nHeight > target_height;
1470 block = block->pprev) { }
1472 lastblock = block ? block->GetBlockHash() : 0;
1476 ret.push_back(Pair("transactions", transactions));
1477 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1482 Value gettransaction(const Array& params, bool fHelp)
1484 if (fHelp || params.size() != 1)
1485 throw runtime_error(
1486 "gettransaction <txid>\n"
1487 "Get detailed information about <txid>");
1490 hash.SetHex(params[0].get_str());
1494 if (!pwalletMain->mapWallet.count(hash))
1495 throw JSONRPCError(-5, "Invalid or non-wallet transaction id");
1496 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1498 int64 nCredit = wtx.GetCredit();
1499 int64 nDebit = wtx.GetDebit();
1500 int64 nNet = nCredit - nDebit;
1501 int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
1503 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1505 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1507 WalletTxToJSON(pwalletMain->mapWallet[hash], entry);
1510 ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
1511 entry.push_back(Pair("details", details));
1517 Value backupwallet(const Array& params, bool fHelp)
1519 if (fHelp || params.size() != 1)
1520 throw runtime_error(
1521 "backupwallet <destination>\n"
1522 "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1524 string strDest = params[0].get_str();
1525 BackupWallet(*pwalletMain, strDest);
1531 Value keypoolrefill(const Array& params, bool fHelp)
1533 if (pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1534 throw runtime_error(
1536 "Fills the keypool, requires wallet passphrase to be set.");
1537 if (!pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1538 throw runtime_error(
1540 "Fills the keypool.");
1542 if (pwalletMain->IsLocked())
1543 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
1545 pwalletMain->TopUpKeyPool();
1547 if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100))
1548 throw JSONRPCError(-4, "Error refreshing keypool.");
1554 void ThreadTopUpKeyPool(void* parg)
1556 pwalletMain->TopUpKeyPool();
1559 void ThreadCleanWalletPassphrase(void* parg)
1561 int64 nMyWakeTime = GetTimeMillis() + *((int64*)parg) * 1000;
1563 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1565 if (nWalletUnlockTime == 0)
1567 nWalletUnlockTime = nMyWakeTime;
1571 if (nWalletUnlockTime==0)
1573 int64 nToSleep = nWalletUnlockTime - GetTimeMillis();
1577 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1579 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1583 if (nWalletUnlockTime)
1585 nWalletUnlockTime = 0;
1586 pwalletMain->Lock();
1591 if (nWalletUnlockTime < nMyWakeTime)
1592 nWalletUnlockTime = nMyWakeTime;
1595 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1597 delete (int64*)parg;
1600 Value walletpassphrase(const Array& params, bool fHelp)
1602 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 3))
1603 throw runtime_error(
1604 "walletpassphrase <passphrase> <timeout> [stakeonly]\n"
1605 "Stores the wallet decryption key in memory for <timeout> seconds.\n"
1606 "stakeonly is optional true/false allowing only stake creation.");
1609 if (!pwalletMain->IsCrypted())
1610 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1612 if (!pwalletMain->IsLocked())
1613 throw JSONRPCError(-17, "Error: Wallet is already unlocked, use walletlock first if need to change unlock settings.");
1615 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1616 SecureString strWalletPass;
1617 strWalletPass.reserve(100);
1618 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1619 // Alternately, find a way to make params[0] mlock()'d to begin with.
1620 strWalletPass = params[0].get_str().c_str();
1622 if (strWalletPass.length() > 0)
1624 if (!pwalletMain->Unlock(strWalletPass))
1625 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1628 throw runtime_error(
1629 "walletpassphrase <passphrase> <timeout>\n"
1630 "Stores the wallet decryption key in memory for <timeout> seconds.");
1632 CreateThread(ThreadTopUpKeyPool, NULL);
1633 int64* pnSleepTime = new int64(params[1].get_int64());
1634 CreateThread(ThreadCleanWalletPassphrase, pnSleepTime);
1636 // ppcoin: if user OS account compromised prevent trivial sendmoney commands
1637 if (params.size() > 2)
1638 fWalletUnlockStakeOnly = params[2].get_bool();
1640 fWalletUnlockStakeOnly = false;
1646 Value walletpassphrasechange(const Array& params, bool fHelp)
1648 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1649 throw runtime_error(
1650 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1651 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1654 if (!pwalletMain->IsCrypted())
1655 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1657 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1658 // Alternately, find a way to make params[0] mlock()'d to begin with.
1659 SecureString strOldWalletPass;
1660 strOldWalletPass.reserve(100);
1661 strOldWalletPass = params[0].get_str().c_str();
1663 SecureString strNewWalletPass;
1664 strNewWalletPass.reserve(100);
1665 strNewWalletPass = params[1].get_str().c_str();
1667 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1668 throw runtime_error(
1669 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1670 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1672 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1673 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1679 Value walletlock(const Array& params, bool fHelp)
1681 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1682 throw runtime_error(
1684 "Removes the wallet encryption key from memory, locking the wallet.\n"
1685 "After calling this method, you will need to call walletpassphrase again\n"
1686 "before being able to call any methods which require the wallet to be unlocked.");
1689 if (!pwalletMain->IsCrypted())
1690 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called.");
1693 LOCK(cs_nWalletUnlockTime);
1694 pwalletMain->Lock();
1695 nWalletUnlockTime = 0;
1702 Value encryptwallet(const Array& params, bool fHelp)
1704 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1705 throw runtime_error(
1706 "encryptwallet <passphrase>\n"
1707 "Encrypts the wallet with <passphrase>.");
1710 if (pwalletMain->IsCrypted())
1711 throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
1713 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1714 // Alternately, find a way to make params[0] mlock()'d to begin with.
1715 SecureString strWalletPass;
1716 strWalletPass.reserve(100);
1717 strWalletPass = params[0].get_str().c_str();
1719 if (strWalletPass.length() < 1)
1720 throw runtime_error(
1721 "encryptwallet <passphrase>\n"
1722 "Encrypts the wallet with <passphrase>.");
1724 if (!pwalletMain->EncryptWallet(strWalletPass))
1725 throw JSONRPCError(-16, "Error: Failed to encrypt the wallet.");
1727 // BDB seems to have a bad habit of writing old data into
1728 // slack space in .dat files; that is bad if the old data is
1729 // unencrypted private keys. So:
1731 return "wallet encrypted; ppcoin server stopping, restart to run with encrypted wallet";
1735 Value validateaddress(const Array& params, bool fHelp)
1737 if (fHelp || params.size() != 1)
1738 throw runtime_error(
1739 "validateaddress <ppcoinaddress>\n"
1740 "Return information about <ppcoinaddress>.");
1742 CBitcoinAddress address(params[0].get_str());
1743 bool isValid = address.IsValid();
1746 ret.push_back(Pair("isvalid", isValid));
1749 // Call Hash160ToAddress() so we always return current ADDRESSVERSION
1750 // version of the address:
1751 string currentAddress = address.ToString();
1752 ret.push_back(Pair("address", currentAddress));
1753 if (pwalletMain->HaveKey(address))
1755 ret.push_back(Pair("ismine", true));
1756 std::vector<unsigned char> vchPubKey;
1757 pwalletMain->GetPubKey(address, vchPubKey);
1758 ret.push_back(Pair("pubkey", HexStr(vchPubKey)));
1760 key.SetPubKey(vchPubKey);
1761 ret.push_back(Pair("iscompressed", key.IsCompressed()));
1763 else if (pwalletMain->HaveCScript(address.GetHash160()))
1765 ret.push_back(Pair("isscript", true));
1767 pwalletMain->GetCScript(address.GetHash160(), subscript);
1768 ret.push_back(Pair("ismine", ::IsMine(*pwalletMain, subscript)));
1769 std::vector<CBitcoinAddress> addresses;
1770 txnouttype whichType;
1772 ExtractAddresses(subscript, whichType, addresses, nRequired);
1773 ret.push_back(Pair("script", GetTxnOutputType(whichType)));
1775 BOOST_FOREACH(const CBitcoinAddress& addr, addresses)
1776 a.push_back(addr.ToString());
1777 ret.push_back(Pair("addresses", a));
1778 if (whichType == TX_MULTISIG)
1779 ret.push_back(Pair("sigsrequired", nRequired));
1782 ret.push_back(Pair("ismine", false));
1783 if (pwalletMain->mapAddressBook.count(address))
1784 ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
1789 Value getwork(const Array& params, bool fHelp)
1791 if (fHelp || params.size() > 1)
1792 throw runtime_error(
1794 "If [data] is not specified, returns formatted hash data to work on:\n"
1795 " \"midstate\" : precomputed hash state after hashing the first half of the data (DEPRECATED)\n" // deprecated
1796 " \"data\" : block data\n"
1797 " \"hash1\" : formatted hash buffer for second hash (DEPRECATED)\n" // deprecated
1798 " \"target\" : little endian hash target\n"
1799 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1802 throw JSONRPCError(-9, "PPCoin is not connected!");
1804 if (IsInitialBlockDownload())
1805 throw JSONRPCError(-10, "PPCoin is downloading blocks...");
1807 typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
1808 static mapNewBlock_t mapNewBlock;
1809 static vector<CBlock*> vNewBlock;
1810 static CReserveKey reservekey(pwalletMain);
1812 if (params.size() == 0)
1815 static unsigned int nTransactionsUpdatedLast;
1816 static CBlockIndex* pindexPrev;
1817 static int64 nStart;
1818 static CBlock* pblock;
1819 if (pindexPrev != pindexBest ||
1820 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
1822 if (pindexPrev != pindexBest)
1824 // Deallocate old blocks since they're obsolete now
1825 mapNewBlock.clear();
1826 BOOST_FOREACH(CBlock* pblock, vNewBlock)
1830 nTransactionsUpdatedLast = nTransactionsUpdated;
1831 pindexPrev = pindexBest;
1835 pblock = CreateNewBlock(pwalletMain);
1837 throw JSONRPCError(-7, "Out of memory");
1838 vNewBlock.push_back(pblock);
1842 pblock->UpdateTime(pindexPrev);
1845 // Update nExtraNonce
1846 static unsigned int nExtraNonce = 0;
1847 IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
1850 mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
1852 // Prebuild hash buffers
1856 FormatHashBuffers(pblock, pmidstate, pdata, phash1);
1858 uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
1861 result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate)))); // deprecated
1862 result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata))));
1863 result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1)))); // deprecated
1864 result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
1870 vector<unsigned char> vchData = ParseHex(params[0].get_str());
1871 if (vchData.size() != 128)
1872 throw JSONRPCError(-8, "Invalid parameter");
1873 CBlock* pdata = (CBlock*)&vchData[0];
1876 for (int i = 0; i < 128/4; i++)
1877 ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]);
1880 if (!mapNewBlock.count(pdata->hashMerkleRoot))
1882 CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
1884 pblock->nTime = pdata->nTime;
1885 pblock->nNonce = pdata->nNonce;
1886 pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
1887 pblock->hashMerkleRoot = pblock->BuildMerkleTree();
1888 if (!pblock->SignBlock(*pwalletMain))
1889 throw JSONRPCError(-100, "Unable to sign block");
1891 return CheckWork(pblock, *pwalletMain, reservekey);
1896 Value getmemorypool(const Array& params, bool fHelp)
1898 if (fHelp || params.size() > 1)
1899 throw runtime_error(
1900 "getmemorypool [data]\n"
1901 "If [data] is not specified, returns data needed to construct a block to work on:\n"
1902 " \"version\" : block version\n"
1903 " \"previousblockhash\" : hash of current highest block\n"
1904 " \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
1905 " \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
1906 " \"coinbaseflags\" : data that should be included in coinbase so support for new features can be judged\n"
1907 " \"time\" : timestamp appropriate for next block\n"
1908 " \"mintime\" : minimum timestamp appropriate for next block\n"
1909 " \"curtime\" : current timestamp\n"
1910 " \"bits\" : compressed target of next block\n"
1911 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1913 if (params.size() == 0)
1916 throw JSONRPCError(-9, "PPCoin is not connected!");
1918 if (IsInitialBlockDownload())
1919 throw JSONRPCError(-10, "PPCoin is downloading blocks...");
1921 static CReserveKey reservekey(pwalletMain);
1924 static unsigned int nTransactionsUpdatedLast;
1925 static CBlockIndex* pindexPrev;
1926 static int64 nStart;
1927 static CBlock* pblock;
1928 if (pindexPrev != pindexBest ||
1929 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5))
1931 nTransactionsUpdatedLast = nTransactionsUpdated;
1932 pindexPrev = pindexBest;
1938 pblock = CreateNewBlock(pwalletMain);
1940 throw JSONRPCError(-7, "Out of memory");
1944 pblock->UpdateTime(pindexPrev);
1948 BOOST_FOREACH(CTransaction tx, pblock->vtx) {
1949 if(tx.IsCoinBase() || tx.IsCoinStake())
1952 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
1955 transactions.push_back(HexStr(ssTx.begin(), ssTx.end()));
1959 result.push_back(Pair("version", pblock->nVersion));
1960 result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
1961 result.push_back(Pair("transactions", transactions));
1962 result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
1963 result.push_back(Pair("coinbaseflags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end())));
1964 result.push_back(Pair("time", (int64_t)pblock->nTime));
1965 result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1));
1966 result.push_back(Pair("curtime", (int64_t)GetAdjustedTime()));
1967 result.push_back(Pair("bits", HexBits(pblock->nBits)));
1974 CDataStream ssBlock(ParseHex(params[0].get_str()), SER_NETWORK, PROTOCOL_VERSION);
1978 return ProcessBlock(NULL, &pblock);
1982 Value getblockhash(const Array& params, bool fHelp)
1984 if (fHelp || params.size() != 1)
1985 throw runtime_error(
1986 "getblockhash <index>\n"
1987 "Returns hash of block in best-block-chain at <index>.");
1989 int nHeight = params[0].get_int();
1990 if (nHeight < 0 || nHeight > nBestHeight)
1991 throw runtime_error("Block number out of range.");
1994 CBlockIndex* pblockindex = mapBlockIndex[hashBestChain];
1995 while (pblockindex->nHeight > nHeight)
1996 pblockindex = pblockindex->pprev;
1997 return pblockindex->phashBlock->GetHex();
2000 Value getblock(const Array& params, bool fHelp)
2002 if (fHelp || params.size() != 1)
2003 throw runtime_error(
2005 "Returns details of a block with given block-hash.");
2007 std::string strHash = params[0].get_str();
2008 uint256 hash(strHash);
2010 if (mapBlockIndex.count(hash) == 0)
2011 throw JSONRPCError(-5, "Block not found");
2014 CBlockIndex* pblockindex = mapBlockIndex[hash];
2015 block.ReadFromDisk(pblockindex, true);
2017 return blockToJSON(block, pblockindex);
2021 // ppcoin: get information of sync-checkpoint
2022 Value getcheckpoint(const Array& params, bool fHelp)
2024 if (fHelp || params.size() != 0)
2025 throw runtime_error(
2027 "Show info of synchronized checkpoint.\n");
2030 CBlockIndex* pindexCheckpoint;
2032 result.push_back(Pair("synccheckpoint", Checkpoints::hashSyncCheckpoint.ToString().c_str()));
2033 pindexCheckpoint = mapBlockIndex[Checkpoints::hashSyncCheckpoint];
2034 result.push_back(Pair("height", pindexCheckpoint->nHeight));
2035 result.push_back(Pair("timestamp", DateTimeStrFormat(pindexCheckpoint->GetBlockTime()).c_str()));
2036 if (mapArgs.count("-checkpointkey"))
2037 result.push_back(Pair("checkpointmaster", true));
2043 // ppcoin: reserve balance from being staked for network protection
2044 Value reservebalance(const Array& params, bool fHelp)
2046 if (fHelp || params.size() > 2)
2047 throw runtime_error(
2048 "reservebalance [<reserve> [amount]]\n"
2049 "<reserve> is true or false to turn balance reserve on or off.\n"
2050 "<amount> is a real and rounded to cent.\n"
2051 "Set reserve amount not participating in network protection.\n"
2052 "If no parameters provided current setting is printed.\n");
2054 if (params.size() > 0)
2056 bool fReserve = params[0].get_bool();
2059 if (params.size() == 1)
2060 throw runtime_error("must provide amount to reserve balance.\n");
2061 int64 nAmount = AmountFromValue(params[1]);
2062 nAmount = (nAmount / CENT) * CENT; // round to cent
2064 throw runtime_error("amount cannot be negative.\n");
2065 mapArgs["-reservebalance"] = FormatMoney(nAmount).c_str();
2069 if (params.size() > 1)
2070 throw runtime_error("cannot specify amount to turn off reserve.\n");
2071 mapArgs["-reservebalance"] = "0";
2076 int64 nReserveBalance = 0;
2077 if (mapArgs.count("-reservebalance") && !ParseMoney(mapArgs["-reservebalance"], nReserveBalance))
2078 throw runtime_error("invalid reserve balance amount\n");
2079 result.push_back(Pair("reserve", (nReserveBalance > 0)));
2080 result.push_back(Pair("amount", ValueFromAmount(nReserveBalance)));
2085 // ppcoin: check wallet integrity
2086 Value checkwallet(const Array& params, bool fHelp)
2088 if (fHelp || params.size() > 0)
2089 throw runtime_error(
2091 "Check wallet for integrity.\n");
2094 int64 nBalanceInQuestion;
2095 if (!pwalletMain->CheckSpentCoins(nMismatchSpent, nBalanceInQuestion))
2098 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
2099 result.push_back(Pair("amount in question", ValueFromAmount(nBalanceInQuestion)));
2106 // ppcoin: repair wallet
2107 Value repairwallet(const Array& params, bool fHelp)
2109 if (fHelp || params.size() > 0)
2110 throw runtime_error(
2112 "Repair wallet if checkwallet reports any problem.\n");
2115 int64 nBalanceInQuestion;
2116 pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion);
2118 if (nMismatchSpent == 0)
2120 result.push_back(Pair("wallet check passed", true));
2124 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
2125 result.push_back(Pair("amount affected by repair", ValueFromAmount(nBalanceInQuestion)));
2130 // ppcoin: make a public-private key pair
2131 Value makekeypair(const Array& params, bool fHelp)
2133 if (fHelp || params.size() > 1)
2134 throw runtime_error(
2135 "makekeypair [prefix]\n"
2136 "Make a public/private key pair.\n"
2137 "[prefix] is optional preferred prefix for the public key.\n");
2139 string strPrefix = "";
2140 if (params.size() > 0)
2141 strPrefix = params[0].get_str();
2147 key.MakeNewKey(false);
2149 } while (nCount < 10000 && strPrefix != HexStr(key.GetPubKey()).substr(0, strPrefix.size()));
2151 if (strPrefix != HexStr(key.GetPubKey()).substr(0, strPrefix.size()))
2154 CPrivKey vchPrivKey = key.GetPrivKey();
2156 result.push_back(Pair("PrivateKey", HexStr<CPrivKey::iterator>(vchPrivKey.begin(), vchPrivKey.end())));
2157 result.push_back(Pair("PublicKey", HexStr(key.GetPubKey())));
2161 extern CCriticalSection cs_mapAlerts;
2162 extern map<uint256, CAlert> mapAlerts;
2164 // ppcoin: send alert.
2165 // There is a known deadlock situation with ThreadMessageHandler
2166 // ThreadMessageHandler: holds cs_vSend and acquiring cs_main in SendMessages()
2167 // ThreadRPCServer: holds cs_main and acquiring cs_vSend in alert.RelayTo()/PushMessage()/BeginMessage()
2168 Value sendalert(const Array& params, bool fHelp)
2170 if (fHelp || params.size() < 6)
2171 throw runtime_error(
2172 "sendalert <message> <privatekey> <minver> <maxver> <priority> <id> [cancelupto]\n"
2173 "<message> is the alert text message\n"
2174 "<privatekey> is hex string of alert master private key\n"
2175 "<minver> is the minimum applicable internal client version\n"
2176 "<maxver> is the maximum applicable internal client version\n"
2177 "<priority> is integer priority number\n"
2178 "<id> is the alert id\n"
2179 "[cancelupto] cancels all alert id's up to this number\n"
2180 "Returns true or false.");
2185 alert.strStatusBar = params[0].get_str();
2186 alert.nMinVer = params[2].get_int();
2187 alert.nMaxVer = params[3].get_int();
2188 alert.nPriority = params[4].get_int();
2189 alert.nID = params[5].get_int();
2190 if (params.size() > 6)
2191 alert.nCancel = params[6].get_int();
2192 alert.nVersion = PROTOCOL_VERSION;
2193 alert.nRelayUntil = GetAdjustedTime() + 365*24*60*60;
2194 alert.nExpiration = GetAdjustedTime() + 365*24*60*60;
2196 CDataStream sMsg(SER_NETWORK, PROTOCOL_VERSION);
2197 sMsg << (CUnsignedAlert)alert;
2198 alert.vchMsg = vector<unsigned char>(sMsg.begin(), sMsg.end());
2200 vector<unsigned char> vchPrivKey = ParseHex(params[1].get_str());
2201 key.SetPrivKey(CPrivKey(vchPrivKey.begin(), vchPrivKey.end())); // if key is not correct openssl may crash
2202 if (!key.Sign(Hash(alert.vchMsg.begin(), alert.vchMsg.end()), alert.vchSig))
2203 throw runtime_error(
2204 "Unable to sign alert, check private key?\n");
2205 if(!alert.ProcessAlert())
2206 throw runtime_error(
2207 "Failed to process alert.\n");
2211 BOOST_FOREACH(CNode* pnode, vNodes)
2212 alert.RelayTo(pnode);
2216 result.push_back(Pair("strStatusBar", alert.strStatusBar));
2217 result.push_back(Pair("nVersion", alert.nVersion));
2218 result.push_back(Pair("nMinVer", alert.nMinVer));
2219 result.push_back(Pair("nMaxVer", alert.nMaxVer));
2220 result.push_back(Pair("nPriority", alert.nPriority));
2221 result.push_back(Pair("nID", alert.nID));
2222 if (alert.nCancel > 0)
2223 result.push_back(Pair("nCancel", alert.nCancel));
2234 static const CRPCCommand vRPCCommands[] =
2235 { // name function safe mode?
2236 // ------------------------ ----------------------- ----------
2237 { "help", &help, true },
2238 { "stop", &stop, true },
2239 { "getblockcount", &getblockcount, true },
2240 { "getblocknumber", &getblocknumber, true },
2241 { "getconnectioncount", &getconnectioncount, true },
2242 { "getdifficulty", &getdifficulty, true },
2243 { "getgenerate", &getgenerate, true },
2244 { "setgenerate", &setgenerate, true },
2245 { "gethashespersec", &gethashespersec, true },
2246 { "getinfo", &getinfo, true },
2247 { "getmininginfo", &getmininginfo, true },
2248 { "getnewaddress", &getnewaddress, true },
2249 { "getaccountaddress", &getaccountaddress, true },
2250 { "setaccount", &setaccount, true },
2251 { "getaccount", &getaccount, false },
2252 { "getaddressesbyaccount", &getaddressesbyaccount, true },
2253 { "sendtoaddress", &sendtoaddress, false },
2254 { "getreceivedbyaddress", &getreceivedbyaddress, false },
2255 { "getreceivedbyaccount", &getreceivedbyaccount, false },
2256 { "listreceivedbyaddress", &listreceivedbyaddress, false },
2257 { "listreceivedbyaccount", &listreceivedbyaccount, false },
2258 { "backupwallet", &backupwallet, true },
2259 { "keypoolrefill", &keypoolrefill, true },
2260 { "walletpassphrase", &walletpassphrase, true },
2261 { "walletpassphrasechange", &walletpassphrasechange, false },
2262 { "walletlock", &walletlock, true },
2263 { "encryptwallet", &encryptwallet, false },
2264 { "validateaddress", &validateaddress, true },
2265 { "getbalance", &getbalance, false },
2266 { "move", &movecmd, false },
2267 { "sendfrom", &sendfrom, false },
2268 { "sendmany", &sendmany, false },
2269 { "addmultisigaddress", &addmultisigaddress, false },
2270 { "getblock", &getblock, false },
2271 { "getblockhash", &getblockhash, false },
2272 { "gettransaction", &gettransaction, false },
2273 { "listtransactions", &listtransactions, false },
2274 { "signmessage", &signmessage, false },
2275 { "verifymessage", &verifymessage, false },
2276 { "getwork", &getwork, true },
2277 { "listaccounts", &listaccounts, false },
2278 { "settxfee", &settxfee, false },
2279 { "getmemorypool", &getmemorypool, true },
2280 { "listsinceblock", &listsinceblock, false },
2281 { "dumpprivkey", &dumpprivkey, false },
2282 { "importprivkey", &importprivkey, false },
2283 { "getcheckpoint", &getcheckpoint, true },
2284 { "reservebalance", &reservebalance, false},
2285 { "checkwallet", &checkwallet, false},
2286 { "repairwallet", &repairwallet, false},
2287 { "makekeypair", &makekeypair, false},
2288 { "sendalert", &sendalert, false},
2291 CRPCTable::CRPCTable()
2294 for (vcidx = 0; vcidx < (sizeof(vRPCCommands) / sizeof(vRPCCommands[0])); vcidx++)
2296 const CRPCCommand *pcmd;
2298 pcmd = &vRPCCommands[vcidx];
2299 mapCommands[pcmd->name] = pcmd;
2303 const CRPCCommand *CRPCTable::operator[](string name) const
2305 map<string, const CRPCCommand*>::const_iterator it = mapCommands.find(name);
2306 if (it == mapCommands.end())
2308 return (*it).second;
2314 // This ain't Apache. We're just using HTTP header for the length field
2315 // and to be compatible with other JSON-RPC implementations.
2318 string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
2321 s << "POST / HTTP/1.1\r\n"
2322 << "User-Agent: ppcoin-json-rpc/" << FormatFullVersion() << "\r\n"
2323 << "Host: 127.0.0.1\r\n"
2324 << "Content-Type: application/json\r\n"
2325 << "Content-Length: " << strMsg.size() << "\r\n"
2326 << "Connection: close\r\n"
2327 << "Accept: application/json\r\n";
2328 BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
2329 s << item.first << ": " << item.second << "\r\n";
2330 s << "\r\n" << strMsg;
2335 string rfc1123Time()
2340 struct tm* now_gmt = gmtime(&now);
2341 string locale(setlocale(LC_TIME, NULL));
2342 setlocale(LC_TIME, "C"); // we want posix (aka "C") weekday/month strings
2343 strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt);
2344 setlocale(LC_TIME, locale.c_str());
2345 return string(buffer);
2348 static string HTTPReply(int nStatus, const string& strMsg)
2351 return strprintf("HTTP/1.0 401 Authorization Required\r\n"
2353 "Server: ppcoin-json-rpc/%s\r\n"
2354 "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
2355 "Content-Type: text/html\r\n"
2356 "Content-Length: 296\r\n"
2358 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
2359 "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
2362 "<TITLE>Error</TITLE>\r\n"
2363 "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
2365 "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
2366 "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
2367 const char *cStatus;
2368 if (nStatus == 200) cStatus = "OK";
2369 else if (nStatus == 400) cStatus = "Bad Request";
2370 else if (nStatus == 403) cStatus = "Forbidden";
2371 else if (nStatus == 404) cStatus = "Not Found";
2372 else if (nStatus == 500) cStatus = "Internal Server Error";
2375 "HTTP/1.1 %d %s\r\n"
2377 "Connection: close\r\n"
2378 "Content-Length: %d\r\n"
2379 "Content-Type: application/json\r\n"
2380 "Server: ppcoin-json-rpc/%s\r\n"
2385 rfc1123Time().c_str(),
2387 FormatFullVersion().c_str(),
2391 int ReadHTTPStatus(std::basic_istream<char>& stream)
2394 getline(stream, str);
2395 vector<string> vWords;
2396 boost::split(vWords, str, boost::is_any_of(" "));
2397 if (vWords.size() < 2)
2399 return atoi(vWords[1].c_str());
2402 int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
2408 std::getline(stream, str);
2409 if (str.empty() || str == "\r")
2411 string::size_type nColon = str.find(":");
2412 if (nColon != string::npos)
2414 string strHeader = str.substr(0, nColon);
2415 boost::trim(strHeader);
2416 boost::to_lower(strHeader);
2417 string strValue = str.substr(nColon+1);
2418 boost::trim(strValue);
2419 mapHeadersRet[strHeader] = strValue;
2420 if (strHeader == "content-length")
2421 nLen = atoi(strValue.c_str());
2427 int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
2429 mapHeadersRet.clear();
2433 int nStatus = ReadHTTPStatus(stream);
2436 int nLen = ReadHTTPHeader(stream, mapHeadersRet);
2437 if (nLen < 0 || nLen > (int)MAX_SIZE)
2443 vector<char> vch(nLen);
2444 stream.read(&vch[0], nLen);
2445 strMessageRet = string(vch.begin(), vch.end());
2451 bool HTTPAuthorized(map<string, string>& mapHeaders)
2453 string strAuth = mapHeaders["authorization"];
2454 if (strAuth.substr(0,6) != "Basic ")
2456 string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
2457 string strUserPass = DecodeBase64(strUserPass64);
2458 return strUserPass == strRPCUserColonPass;
2462 // JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
2463 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
2464 // unspecified (HTTP errors and contents of 'error').
2466 // 1.0 spec: http://json-rpc.org/wiki/specification
2467 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
2468 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
2471 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
2474 request.push_back(Pair("method", strMethod));
2475 request.push_back(Pair("params", params));
2476 request.push_back(Pair("id", id));
2477 return write_string(Value(request), false) + "\n";
2480 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
2483 if (error.type() != null_type)
2484 reply.push_back(Pair("result", Value::null));
2486 reply.push_back(Pair("result", result));
2487 reply.push_back(Pair("error", error));
2488 reply.push_back(Pair("id", id));
2489 return write_string(Value(reply), false) + "\n";
2492 void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
2494 // Send error reply from json-rpc error object
2496 int code = find_value(objError, "code").get_int();
2497 if (code == -32600) nStatus = 400;
2498 else if (code == -32601) nStatus = 404;
2499 string strReply = JSONRPCReply(Value::null, objError, id);
2500 stream << HTTPReply(nStatus, strReply) << std::flush;
2503 bool ClientAllowed(const string& strAddress)
2505 if (strAddress == asio::ip::address_v4::loopback().to_string())
2507 const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
2508 BOOST_FOREACH(string strAllow, vAllow)
2509 if (WildcardMatch(strAddress, strAllow))
2515 // IOStream device that speaks SSL but can also speak non-SSL
2517 class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
2519 SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
2521 fUseSSL = fUseSSLIn;
2522 fNeedHandshake = fUseSSLIn;
2525 void handshake(ssl::stream_base::handshake_type role)
2527 if (!fNeedHandshake) return;
2528 fNeedHandshake = false;
2529 stream.handshake(role);
2531 std::streamsize read(char* s, std::streamsize n)
2533 handshake(ssl::stream_base::server); // HTTPS servers read first
2534 if (fUseSSL) return stream.read_some(asio::buffer(s, n));
2535 return stream.next_layer().read_some(asio::buffer(s, n));
2537 std::streamsize write(const char* s, std::streamsize n)
2539 handshake(ssl::stream_base::client); // HTTPS clients write first
2540 if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
2541 return asio::write(stream.next_layer(), asio::buffer(s, n));
2543 bool connect(const std::string& server, const std::string& port)
2545 ip::tcp::resolver resolver(stream.get_io_service());
2546 ip::tcp::resolver::query query(server.c_str(), port.c_str());
2547 ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
2548 ip::tcp::resolver::iterator end;
2549 boost::system::error_code error = asio::error::host_not_found;
2550 while (error && endpoint_iterator != end)
2552 stream.lowest_layer().close();
2553 stream.lowest_layer().connect(*endpoint_iterator++, error);
2561 bool fNeedHandshake;
2566 void ThreadRPCServer(void* parg)
2568 IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
2571 vnThreadsRunning[THREAD_RPCSERVER]++;
2572 ThreadRPCServer2(parg);
2573 vnThreadsRunning[THREAD_RPCSERVER]--;
2575 catch (std::exception& e) {
2576 vnThreadsRunning[THREAD_RPCSERVER]--;
2577 PrintException(&e, "ThreadRPCServer()");
2579 vnThreadsRunning[THREAD_RPCSERVER]--;
2580 PrintException(NULL, "ThreadRPCServer()");
2582 printf("ThreadRPCServer exiting\n");
2585 void ThreadRPCServer2(void* parg)
2587 printf("ThreadRPCServer started\n");
2589 strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
2590 if (mapArgs["-rpcpassword"] == "")
2592 unsigned char rand_pwd[32];
2593 RAND_bytes(rand_pwd, 32);
2594 string strWhatAmI = "To use ppcoind";
2595 if (mapArgs.count("-server"))
2596 strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
2597 else if (mapArgs.count("-daemon"))
2598 strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
2599 ThreadSafeMessageBox(strprintf(
2600 _("%s, you must set a rpcpassword in the configuration file:\n %s\n"
2601 "It is recommended you use the following random password:\n"
2602 "rpcuser=bitcoinrpc\n"
2604 "(you do not need to remember this password)\n"
2605 "If the file does not exist, create it with owner-readable-only file permissions.\n"),
2607 GetConfigFile().string().c_str(),
2608 EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str()),
2609 _("Error"), wxOK | wxMODAL);
2614 bool fUseSSL = GetBoolArg("-rpcssl");
2615 asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
2617 asio::io_service io_service;
2618 ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", RPC_PORT));
2619 ip::tcp::acceptor acceptor(io_service);
2622 acceptor.open(endpoint.protocol());
2623 acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
2624 acceptor.bind(endpoint);
2625 acceptor.listen(socket_base::max_connections);
2627 catch(boost::system::system_error &e)
2629 ThreadSafeMessageBox(strprintf(_("An error occured while setting up the RPC port %i for listening: %s"), endpoint.port(), e.what()),
2630 _("Error"), wxOK | wxMODAL);
2635 ssl::context context(io_service, ssl::context::sslv23);
2638 context.set_options(ssl::context::no_sslv2);
2640 filesystem::path pathCertFile(GetArg("-rpcsslcertificatechainfile", "server.cert"));
2641 if (!pathCertFile.is_complete()) pathCertFile = filesystem::path(GetDataDir()) / pathCertFile;
2642 if (filesystem::exists(pathCertFile)) context.use_certificate_chain_file(pathCertFile.string());
2643 else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", pathCertFile.string().c_str());
2645 filesystem::path pathPKFile(GetArg("-rpcsslprivatekeyfile", "server.pem"));
2646 if (!pathPKFile.is_complete()) pathPKFile = filesystem::path(GetDataDir()) / pathPKFile;
2647 if (filesystem::exists(pathPKFile)) context.use_private_key_file(pathPKFile.string(), ssl::context::pem);
2648 else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pathPKFile.string().c_str());
2650 string strCiphers = GetArg("-rpcsslciphers", "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
2651 SSL_CTX_set_cipher_list(context.impl(), strCiphers.c_str());
2656 // Accept connection
2657 SSLStream sslStream(io_service, context);
2658 SSLIOStreamDevice d(sslStream, fUseSSL);
2659 iostreams::stream<SSLIOStreamDevice> stream(d);
2661 ip::tcp::endpoint peer;
2662 vnThreadsRunning[THREAD_RPCSERVER]--;
2663 acceptor.accept(sslStream.lowest_layer(), peer);
2664 vnThreadsRunning[4]++;
2668 // Restrict callers by IP
2669 if (!ClientAllowed(peer.address().to_string()))
2671 // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
2673 stream << HTTPReply(403, "") << std::flush;
2677 map<string, string> mapHeaders;
2680 boost::thread api_caller(ReadHTTP, boost::ref(stream), boost::ref(mapHeaders), boost::ref(strRequest));
2681 if (!api_caller.timed_join(boost::posix_time::seconds(GetArg("-rpctimeout", 30))))
2684 printf("ThreadRPCServer ReadHTTP timeout\n");
2688 // Check authorization
2689 if (mapHeaders.count("authorization") == 0)
2691 stream << HTTPReply(401, "") << std::flush;
2694 if (!HTTPAuthorized(mapHeaders))
2696 printf("ThreadRPCServer incorrect password attempt from %s\n",peer.address().to_string().c_str());
2697 /* Deter brute-forcing short passwords.
2698 If this results in a DOS the user really
2699 shouldn't have their RPC port exposed.*/
2700 if (mapArgs["-rpcpassword"].size() < 20)
2703 stream << HTTPReply(401, "") << std::flush;
2707 Value id = Value::null;
2712 if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
2713 throw JSONRPCError(-32700, "Parse error");
2714 const Object& request = valRequest.get_obj();
2716 // Parse id now so errors from here on will have the id
2717 id = find_value(request, "id");
2720 Value valMethod = find_value(request, "method");
2721 if (valMethod.type() == null_type)
2722 throw JSONRPCError(-32600, "Missing method");
2723 if (valMethod.type() != str_type)
2724 throw JSONRPCError(-32600, "Method must be a string");
2725 string strMethod = valMethod.get_str();
2726 if (strMethod != "getwork" && strMethod != "getmemorypool")
2727 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
2730 Value valParams = find_value(request, "params");
2732 if (valParams.type() == array_type)
2733 params = valParams.get_array();
2734 else if (valParams.type() == null_type)
2737 throw JSONRPCError(-32600, "Params must be an array");
2740 const CRPCCommand *pcmd = tableRPC[strMethod];
2742 throw JSONRPCError(-32601, "Method not found");
2744 // Observe safe mode
2745 string strWarning = GetWarnings("rpc");
2746 if (strWarning != "" && !GetBoolArg("-disablesafemode") &&
2748 throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
2755 LOCK2(cs_main, pwalletMain->cs_wallet);
2756 result = pcmd->actor(params, false);
2760 string strReply = JSONRPCReply(result, Value::null, id);
2761 stream << HTTPReply(200, strReply) << std::flush;
2763 catch (std::exception& e)
2765 ErrorReply(stream, JSONRPCError(-1, e.what()), id);
2768 catch (Object& objError)
2770 ErrorReply(stream, objError, id);
2772 catch (std::exception& e)
2774 ErrorReply(stream, JSONRPCError(-32700, e.what()), id);
2782 Object CallRPC(const string& strMethod, const Array& params)
2784 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2785 throw runtime_error(strprintf(
2786 _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
2787 "If the file does not exist, create it with owner-readable-only file permissions."),
2788 GetConfigFile().string().c_str()));
2790 // Connect to localhost
2791 bool fUseSSL = GetBoolArg("-rpcssl");
2792 asio::io_service io_service;
2793 ssl::context context(io_service, ssl::context::sslv23);
2794 context.set_options(ssl::context::no_sslv2);
2795 SSLStream sslStream(io_service, context);
2796 SSLIOStreamDevice d(sslStream, fUseSSL);
2797 iostreams::stream<SSLIOStreamDevice> stream(d);
2798 if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", CBigNum(RPC_PORT).ToString().c_str())))
2799 throw runtime_error("couldn't connect to server");
2801 // HTTP basic authentication
2802 string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
2803 map<string, string> mapRequestHeaders;
2804 mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
2807 string strRequest = JSONRPCRequest(strMethod, params, 1);
2808 string strPost = HTTPPost(strRequest, mapRequestHeaders);
2809 stream << strPost << std::flush;
2812 map<string, string> mapHeaders;
2814 int nStatus = ReadHTTP(stream, mapHeaders, strReply);
2816 throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
2817 else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
2818 throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
2819 else if (strReply.empty())
2820 throw runtime_error("no response from server");
2824 if (!read_string(strReply, valReply))
2825 throw runtime_error("couldn't parse reply from server");
2826 const Object& reply = valReply.get_obj();
2828 throw runtime_error("expected reply to have result, error and id properties");
2836 template<typename T>
2837 void ConvertTo(Value& value)
2839 if (value.type() == str_type)
2841 // reinterpret string as unquoted json value
2843 if (!read_string(value.get_str(), value2))
2844 throw runtime_error("type mismatch");
2845 value = value2.get_value<T>();
2849 value = value.get_value<T>();
2853 int CommandLineRPC(int argc, char *argv[])
2860 while (argc > 1 && IsSwitchChar(argv[1][0]))
2868 throw runtime_error("too few parameters");
2869 string strMethod = argv[1];
2871 // Parameters default to strings
2873 for (int i = 2; i < argc; i++)
2874 params.push_back(argv[i]);
2875 int n = params.size();
2878 // Special case non-string parameter types
2880 if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
2881 if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2882 if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
2883 if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]);
2884 if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2885 if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2886 if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2887 if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
2888 if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2889 if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
2890 if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2891 if (strMethod == "getblockhash" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2892 if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]);
2893 if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2894 if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]);
2895 if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2896 if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2897 if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2898 if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2899 if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2900 if (strMethod == "walletpassphrase" && n > 2) ConvertTo<bool>(params[2]);
2901 if (strMethod == "listsinceblock" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2902 if (strMethod == "sendalert" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2903 if (strMethod == "sendalert" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2904 if (strMethod == "sendalert" && n > 4) ConvertTo<boost::int64_t>(params[4]);
2905 if (strMethod == "sendalert" && n > 5) ConvertTo<boost::int64_t>(params[5]);
2906 if (strMethod == "sendalert" && n > 6) ConvertTo<boost::int64_t>(params[6]);
2907 if (strMethod == "sendmany" && n > 1)
2909 string s = params[1].get_str();
2911 if (!read_string(s, v) || v.type() != obj_type)
2912 throw runtime_error("type mismatch");
2913 params[1] = v.get_obj();
2915 if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2916 if (strMethod == "reservebalance" && n > 0) ConvertTo<bool>(params[0]);
2917 if (strMethod == "reservebalance" && n > 1) ConvertTo<double>(params[1]);
2918 if (strMethod == "addmultisigaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2919 if (strMethod == "addmultisigaddress" && n > 1)
2921 string s = params[1].get_str();
2923 if (!read_string(s, v) || v.type() != array_type)
2924 throw runtime_error("type mismatch "+s);
2925 params[1] = v.get_array();
2929 Object reply = CallRPC(strMethod, params);
2932 const Value& result = find_value(reply, "result");
2933 const Value& error = find_value(reply, "error");
2935 if (error.type() != null_type)
2938 strPrint = "error: " + write_string(error, false);
2939 int code = find_value(error.get_obj(), "code").get_int();
2945 if (result.type() == null_type)
2947 else if (result.type() == str_type)
2948 strPrint = result.get_str();
2950 strPrint = write_string(result, true);
2953 catch (std::exception& e)
2955 strPrint = string("error: ") + e.what();
2960 PrintException(NULL, "CommandLineRPC()");
2965 fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
2974 int main(int argc, char *argv[])
2977 // Turn off microsoft heap dump noise
2978 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
2979 _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
2981 setbuf(stdin, NULL);
2982 setbuf(stdout, NULL);
2983 setbuf(stderr, NULL);
2987 if (argc >= 2 && string(argv[1]) == "-server")
2989 printf("server ready\n");
2990 ThreadRPCServer(NULL);
2994 return CommandLineRPC(argc, argv);
2997 catch (std::exception& e) {
2998 PrintException(&e, "main()");
3000 PrintException(NULL, "main()");
3006 const CRPCTable tableRPC;