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", (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)));
151 if (blockindex->pprev)
152 result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex()));
153 if (blockindex->pnext)
154 result.push_back(Pair("nextblockhash", blockindex->pnext->GetBlockHash().GetHex()));
156 BOOST_FOREACH (const CTransaction& tx, block.vtx)
158 if (fPrintTransactionDetail)
160 txinfo.push_back(tx.ToStringShort());
161 BOOST_FOREACH(const CTxIn& txin, tx.vin)
162 txinfo.push_back(txin.ToStringShort());
163 BOOST_FOREACH(const CTxOut& txout, tx.vout)
164 txinfo.push_back(txout.ToStringShort());
167 txinfo.push_back(tx.GetHash().GetHex());
169 result.push_back(Pair("tx", txinfo));
176 /// Note: This interface may still be subject to change.
179 string CRPCTable::help(string strCommand) const
182 set<rpcfn_type> setDone;
183 for (map<string, const CRPCCommand*>::const_iterator mi = mapCommands.begin(); mi != mapCommands.end(); ++mi)
185 const CRPCCommand *pcmd = mi->second;
186 string strMethod = mi->first;
187 // We already filter duplicates, but these deprecated screw up the sort order
188 if (strMethod == "getamountreceived" ||
189 strMethod == "getallreceived" ||
190 strMethod == "getblocknumber" || // deprecated
191 (strMethod.find("label") != string::npos))
193 if (strCommand != "" && strMethod != strCommand)
198 rpcfn_type pfn = pcmd->actor;
199 if (setDone.insert(pfn).second)
200 (*pfn)(params, true);
202 catch (std::exception& e)
204 // Help text is returned in an exception
205 string strHelp = string(e.what());
206 if (strCommand == "")
207 if (strHelp.find('\n') != string::npos)
208 strHelp = strHelp.substr(0, strHelp.find('\n'));
209 strRet += strHelp + "\n";
213 strRet = strprintf("help: unknown command: %s\n", strCommand.c_str());
214 strRet = strRet.substr(0,strRet.size()-1);
218 Value help(const Array& params, bool fHelp)
220 if (fHelp || params.size() > 1)
223 "List commands, or get help for a command.");
226 if (params.size() > 0)
227 strCommand = params[0].get_str();
229 return tableRPC.help(strCommand);
233 Value stop(const Array& params, bool fHelp)
235 if (fHelp || params.size() != 0)
238 "Stop ppcoin server.");
239 // Shutdown will take long enough that the response should get back
241 return "ppcoin server stopping";
245 Value getblockcount(const Array& params, bool fHelp)
247 if (fHelp || params.size() != 0)
250 "Returns the number of blocks in the longest block chain.");
257 Value getblocknumber(const Array& params, bool fHelp)
259 if (fHelp || params.size() != 0)
262 "Deprecated. Use getblockcount.");
268 Value getconnectioncount(const Array& params, bool fHelp)
270 if (fHelp || params.size() != 0)
272 "getconnectioncount\n"
273 "Returns the number of connections to other nodes.");
275 return (int)vNodes.size();
279 Value getdifficulty(const Array& params, bool fHelp)
281 if (fHelp || params.size() != 0)
284 "Returns difficulty as a multiple of the minimum difficulty.");
287 obj.push_back(Pair("proof-of-work", GetDifficulty()));
288 obj.push_back(Pair("proof-of-stake", GetDifficulty(GetLastBlockIndex(pindexBest, true))));
293 Value getgenerate(const Array& params, bool fHelp)
295 if (fHelp || params.size() != 0)
298 "Returns true or false.");
300 return GetBoolArg("-gen");
304 Value setgenerate(const Array& params, bool fHelp)
306 if (fHelp || params.size() < 1 || params.size() > 2)
308 "setgenerate <generate> [genproclimit]\n"
309 "<generate> is true or false to turn generation on or off.\n"
310 "Generation is limited to [genproclimit] processors, -1 is unlimited.");
312 bool fGenerate = true;
313 if (params.size() > 0)
314 fGenerate = params[0].get_bool();
316 if (params.size() > 1)
318 int nGenProcLimit = params[1].get_int();
319 mapArgs["-genproclimit"] = itostr(nGenProcLimit);
320 if (nGenProcLimit == 0)
323 mapArgs["-gen"] = (fGenerate ? "1" : "0");
325 GenerateBitcoins(fGenerate, pwalletMain);
330 Value gethashespersec(const Array& params, bool fHelp)
332 if (fHelp || params.size() != 0)
335 "Returns a recent hashes per second performance measurement while generating.");
337 if (GetTimeMillis() - nHPSTimerStart > 8000)
338 return (boost::int64_t)0;
339 return (boost::int64_t)dHashesPerSec;
343 Value getinfo(const Array& params, bool fHelp)
345 if (fHelp || params.size() != 0)
348 "Returns an object containing various state info.");
351 obj.push_back(Pair("version", FormatFullVersion()));
352 obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION));
353 obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
354 obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
355 obj.push_back(Pair("newmint", ValueFromAmount(pwalletMain->GetNewMint())));
356 obj.push_back(Pair("stake", ValueFromAmount(pwalletMain->GetStake())));
357 obj.push_back(Pair("blocks", (int)nBestHeight));
358 obj.push_back(Pair("moneysupply", ValueFromAmount(pindexBest->nMoneySupply)));
359 obj.push_back(Pair("connections", (int)vNodes.size()));
360 obj.push_back(Pair("proxy", (fUseProxy ? addrProxy.ToStringIPPort() : string())));
361 obj.push_back(Pair("ip", addrSeenByPeer.ToStringIP()));
362 obj.push_back(Pair("difficulty", (double)GetDifficulty()));
363 obj.push_back(Pair("testnet", fTestNet));
364 obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));
365 obj.push_back(Pair("keypoolsize", pwalletMain->GetKeyPoolSize()));
366 obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee)));
367 if (pwalletMain->IsCrypted())
368 obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime / 1000));
369 obj.push_back(Pair("errors", GetWarnings("statusbar")));
374 Value getmininginfo(const Array& params, bool fHelp)
376 if (fHelp || params.size() != 0)
379 "Returns an object containing mining-related information.");
382 obj.push_back(Pair("blocks", (int)nBestHeight));
383 obj.push_back(Pair("currentblocksize",(uint64_t)nLastBlockSize));
384 obj.push_back(Pair("currentblocktx",(uint64_t)nLastBlockTx));
385 obj.push_back(Pair("difficulty", (double)GetDifficulty()));
386 obj.push_back(Pair("errors", GetWarnings("statusbar")));
387 obj.push_back(Pair("generate", GetBoolArg("-gen")));
388 obj.push_back(Pair("genproclimit", (int)GetArg("-genproclimit", -1)));
389 obj.push_back(Pair("hashespersec", gethashespersec(params, false)));
390 obj.push_back(Pair("pooledtx", (uint64_t)mempool.size()));
391 obj.push_back(Pair("testnet", fTestNet));
396 Value getnewaddress(const Array& params, bool fHelp)
398 if (fHelp || params.size() > 1)
400 "getnewaddress [account]\n"
401 "Returns a new ppcoin address for receiving payments. "
402 "If [account] is specified (recommended), it is added to the address book "
403 "so payments received with the address will be credited to [account].");
405 // Parse the account first so we don't generate a key if there's an error
407 if (params.size() > 0)
408 strAccount = AccountFromValue(params[0]);
410 if (!pwalletMain->IsLocked())
411 pwalletMain->TopUpKeyPool();
413 // Generate a new key that is added to wallet
414 std::vector<unsigned char> newKey;
415 if (!pwalletMain->GetKeyFromPool(newKey, false))
416 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
417 CBitcoinAddress address(newKey);
419 pwalletMain->SetAddressBookName(address, strAccount);
421 return address.ToString();
425 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
427 CWalletDB walletdb(pwalletMain->strWalletFile);
430 walletdb.ReadAccount(strAccount, account);
432 bool bKeyUsed = false;
434 // Check if the current key has been used
435 if (!account.vchPubKey.empty())
437 CScript scriptPubKey;
438 scriptPubKey.SetBitcoinAddress(account.vchPubKey);
439 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
440 it != pwalletMain->mapWallet.end() && !account.vchPubKey.empty();
443 const CWalletTx& wtx = (*it).second;
444 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
445 if (txout.scriptPubKey == scriptPubKey)
450 // Generate a new key
451 if (account.vchPubKey.empty() || bForceNew || bKeyUsed)
453 if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false))
454 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
456 pwalletMain->SetAddressBookName(CBitcoinAddress(account.vchPubKey), strAccount);
457 walletdb.WriteAccount(strAccount, account);
460 return CBitcoinAddress(account.vchPubKey);
463 Value getaccountaddress(const Array& params, bool fHelp)
465 if (fHelp || params.size() != 1)
467 "getaccountaddress <account>\n"
468 "Returns the current ppcoin address for receiving payments to this account.");
470 // Parse the account first so we don't generate a key if there's an error
471 string strAccount = AccountFromValue(params[0]);
475 ret = GetAccountAddress(strAccount).ToString();
482 Value setaccount(const Array& params, bool fHelp)
484 if (fHelp || params.size() < 1 || params.size() > 2)
486 "setaccount <ppcoinaddress> <account>\n"
487 "Sets the account associated with the given address.");
489 CBitcoinAddress address(params[0].get_str());
490 if (!address.IsValid())
491 throw JSONRPCError(-5, "Invalid ppcoin address");
495 if (params.size() > 1)
496 strAccount = AccountFromValue(params[1]);
498 // Detect when changing the account of an address that is the 'unused current key' of another account:
499 if (pwalletMain->mapAddressBook.count(address))
501 string strOldAccount = pwalletMain->mapAddressBook[address];
502 if (address == GetAccountAddress(strOldAccount))
503 GetAccountAddress(strOldAccount, true);
506 pwalletMain->SetAddressBookName(address, strAccount);
512 Value getaccount(const Array& params, bool fHelp)
514 if (fHelp || params.size() != 1)
516 "getaccount <ppcoinaddress>\n"
517 "Returns the account associated with the given address.");
519 CBitcoinAddress address(params[0].get_str());
520 if (!address.IsValid())
521 throw JSONRPCError(-5, "Invalid ppcoin address");
524 map<CBitcoinAddress, string>::iterator mi = pwalletMain->mapAddressBook.find(address);
525 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
526 strAccount = (*mi).second;
531 Value getaddressesbyaccount(const Array& params, bool fHelp)
533 if (fHelp || params.size() != 1)
535 "getaddressesbyaccount <account>\n"
536 "Returns the list of addresses for the given account.");
538 string strAccount = AccountFromValue(params[0]);
540 // Find all addresses that have the given account
542 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
544 const CBitcoinAddress& address = item.first;
545 const string& strName = item.second;
546 if (strName == strAccount)
547 ret.push_back(address.ToString());
552 Value settxfee(const Array& params, bool fHelp)
554 if (fHelp || params.size() < 1 || params.size() > 1 || AmountFromValue(params[0]) < MIN_TX_FEE)
556 "settxfee <amount>\n"
557 "<amount> is a real and is rounded to 0.01 (cent)\n"
558 "Minimum and default transaction fee per KB is 1 cent");
560 nTransactionFee = AmountFromValue(params[0]);
561 nTransactionFee = (nTransactionFee / CENT) * CENT; // round to cent
565 Value sendtoaddress(const Array& params, bool fHelp)
567 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
569 "sendtoaddress <ppcoinaddress> <amount> [comment] [comment-to]\n"
570 "<amount> is a real and is rounded to the nearest 0.000001\n"
571 "requires wallet passphrase to be set with walletpassphrase first");
572 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
574 "sendtoaddress <ppcoinaddress> <amount> [comment] [comment-to]\n"
575 "<amount> is a real and is rounded to the nearest 0.000001");
577 CBitcoinAddress address(params[0].get_str());
578 if (!address.IsValid())
579 throw JSONRPCError(-5, "Invalid ppcoin address");
582 int64 nAmount = AmountFromValue(params[1]);
583 if (nAmount < MIN_TXOUT_AMOUNT)
584 throw JSONRPCError(-101, "Send amount too small");
588 if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
589 wtx.mapValue["comment"] = params[2].get_str();
590 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
591 wtx.mapValue["to"] = params[3].get_str();
593 if (pwalletMain->IsLocked())
594 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
596 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
598 throw JSONRPCError(-4, strError);
600 return wtx.GetHash().GetHex();
603 Value signmessage(const Array& params, bool fHelp)
605 if (fHelp || params.size() != 2)
607 "signmessage <ppcoinaddress> <message>\n"
608 "Sign a message with the private key of an address");
610 if (pwalletMain->IsLocked())
611 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
613 string strAddress = params[0].get_str();
614 string strMessage = params[1].get_str();
616 CBitcoinAddress addr(strAddress);
618 throw JSONRPCError(-3, "Invalid address");
621 if (!pwalletMain->GetKey(addr, key))
622 throw JSONRPCError(-4, "Private key not available");
624 CDataStream ss(SER_GETHASH, 0);
625 ss << strMessageMagic;
628 vector<unsigned char> vchSig;
629 if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig))
630 throw JSONRPCError(-5, "Sign failed");
632 return EncodeBase64(&vchSig[0], vchSig.size());
635 Value verifymessage(const Array& params, bool fHelp)
637 if (fHelp || params.size() != 3)
639 "verifymessage <ppcoinaddress> <signature> <message>\n"
640 "Verify a signed message");
642 string strAddress = params[0].get_str();
643 string strSign = params[1].get_str();
644 string strMessage = params[2].get_str();
646 CBitcoinAddress addr(strAddress);
648 throw JSONRPCError(-3, "Invalid address");
650 bool fInvalid = false;
651 vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
654 throw JSONRPCError(-5, "Malformed base64 encoding");
656 CDataStream ss(SER_GETHASH, 0);
657 ss << strMessageMagic;
661 if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
664 return (CBitcoinAddress(key.GetPubKey()) == addr);
668 Value getreceivedbyaddress(const Array& params, bool fHelp)
670 if (fHelp || params.size() < 1 || params.size() > 2)
672 "getreceivedbyaddress <ppcoinaddress> [minconf=1]\n"
673 "Returns the total amount received by <ppcoinaddress> in transactions with at least [minconf] confirmations.");
676 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
677 CScript scriptPubKey;
678 if (!address.IsValid())
679 throw JSONRPCError(-5, "Invalid ppcoin address");
680 scriptPubKey.SetBitcoinAddress(address);
681 if (!IsMine(*pwalletMain,scriptPubKey))
684 // Minimum confirmations
686 if (params.size() > 1)
687 nMinDepth = params[1].get_int();
691 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
693 const CWalletTx& wtx = (*it).second;
694 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
697 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
698 if (txout.scriptPubKey == scriptPubKey)
699 if (wtx.GetDepthInMainChain() >= nMinDepth)
700 nAmount += txout.nValue;
703 return ValueFromAmount(nAmount);
707 void GetAccountAddresses(string strAccount, set<CBitcoinAddress>& setAddress)
709 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
711 const CBitcoinAddress& address = item.first;
712 const string& strName = item.second;
713 if (strName == strAccount)
714 setAddress.insert(address);
719 Value getreceivedbyaccount(const Array& params, bool fHelp)
721 if (fHelp || params.size() < 1 || params.size() > 2)
723 "getreceivedbyaccount <account> [minconf=1]\n"
724 "Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.");
726 // Minimum confirmations
728 if (params.size() > 1)
729 nMinDepth = params[1].get_int();
731 // Get the set of pub keys assigned to account
732 string strAccount = AccountFromValue(params[0]);
733 set<CBitcoinAddress> setAddress;
734 GetAccountAddresses(strAccount, setAddress);
738 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
740 const CWalletTx& wtx = (*it).second;
741 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
744 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
746 CBitcoinAddress address;
747 if (ExtractAddress(txout.scriptPubKey, address) && pwalletMain->HaveKey(address) && setAddress.count(address))
748 if (wtx.GetDepthInMainChain() >= nMinDepth)
749 nAmount += txout.nValue;
753 return (double)nAmount / (double)COIN;
757 int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth)
761 // Tally wallet transactions
762 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
764 const CWalletTx& wtx = (*it).second;
768 int64 nGenerated, nReceived, nSent, nFee;
769 wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee);
771 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
772 nBalance += nReceived;
773 nBalance += nGenerated - nSent - nFee;
776 // Tally internal accounting entries
777 nBalance += walletdb.GetAccountCreditDebit(strAccount);
782 int64 GetAccountBalance(const string& strAccount, int nMinDepth)
784 CWalletDB walletdb(pwalletMain->strWalletFile);
785 return GetAccountBalance(walletdb, strAccount, nMinDepth);
789 Value getbalance(const Array& params, bool fHelp)
791 if (fHelp || params.size() > 2)
793 "getbalance [account] [minconf=1]\n"
794 "If [account] is not specified, returns the server's total available balance.\n"
795 "If [account] is specified, returns the balance in the account.");
797 if (params.size() == 0)
798 return ValueFromAmount(pwalletMain->GetBalance());
801 if (params.size() > 1)
802 nMinDepth = params[1].get_int();
804 if (params[0].get_str() == "*") {
805 // Calculate total balance a different way from GetBalance()
806 // (GetBalance() sums up all unspent TxOuts)
807 // getbalance and getbalance '*' should always return the same number.
809 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
811 const CWalletTx& wtx = (*it).second;
815 int64 allGeneratedImmature, allGeneratedMature, allFee;
816 allGeneratedImmature = allGeneratedMature = allFee = 0;
817 string strSentAccount;
818 list<pair<CBitcoinAddress, int64> > listReceived;
819 list<pair<CBitcoinAddress, int64> > listSent;
820 wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
821 if (wtx.GetDepthInMainChain() >= nMinDepth)
823 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listReceived)
824 nBalance += r.second;
826 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listSent)
827 nBalance -= r.second;
829 nBalance += allGeneratedMature;
831 return ValueFromAmount(nBalance);
834 string strAccount = AccountFromValue(params[0]);
836 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
838 return ValueFromAmount(nBalance);
842 Value movecmd(const Array& params, bool fHelp)
844 if (fHelp || params.size() < 3 || params.size() > 5)
846 "move <fromaccount> <toaccount> <amount> [minconf=1] [comment]\n"
847 "Move from one account in your wallet to another.");
849 string strFrom = AccountFromValue(params[0]);
850 string strTo = AccountFromValue(params[1]);
851 int64 nAmount = AmountFromValue(params[2]);
852 if (params.size() > 3)
853 // unused parameter, used to be nMinDepth, keep type-checking it though
854 (void)params[3].get_int();
856 if (params.size() > 4)
857 strComment = params[4].get_str();
859 CWalletDB walletdb(pwalletMain->strWalletFile);
860 if (!walletdb.TxnBegin())
861 throw JSONRPCError(-20, "database error");
863 int64 nNow = GetAdjustedTime();
866 CAccountingEntry debit;
867 debit.strAccount = strFrom;
868 debit.nCreditDebit = -nAmount;
870 debit.strOtherAccount = strTo;
871 debit.strComment = strComment;
872 walletdb.WriteAccountingEntry(debit);
875 CAccountingEntry credit;
876 credit.strAccount = strTo;
877 credit.nCreditDebit = nAmount;
879 credit.strOtherAccount = strFrom;
880 credit.strComment = strComment;
881 walletdb.WriteAccountingEntry(credit);
883 if (!walletdb.TxnCommit())
884 throw JSONRPCError(-20, "database error");
890 Value sendfrom(const Array& params, bool fHelp)
892 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
894 "sendfrom <fromaccount> <toppcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
895 "<amount> is a real and is rounded to the nearest 0.000001\n"
896 "requires wallet passphrase to be set with walletpassphrase first");
897 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
899 "sendfrom <fromaccount> <toppcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
900 "<amount> is a real and is rounded to the nearest 0.000001");
902 string strAccount = AccountFromValue(params[0]);
903 CBitcoinAddress address(params[1].get_str());
904 if (!address.IsValid())
905 throw JSONRPCError(-5, "Invalid ppcoin address");
906 int64 nAmount = AmountFromValue(params[2]);
907 if (nAmount < MIN_TXOUT_AMOUNT)
908 throw JSONRPCError(-101, "Send amount too small");
910 if (params.size() > 3)
911 nMinDepth = params[3].get_int();
914 wtx.strFromAccount = strAccount;
915 if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
916 wtx.mapValue["comment"] = params[4].get_str();
917 if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
918 wtx.mapValue["to"] = params[5].get_str();
920 if (pwalletMain->IsLocked())
921 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
924 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
925 if (nAmount > nBalance)
926 throw JSONRPCError(-6, "Account has insufficient funds");
929 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
931 throw JSONRPCError(-4, strError);
933 return wtx.GetHash().GetHex();
937 Value sendmany(const Array& params, bool fHelp)
939 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
941 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
942 "amounts are double-precision floating point numbers\n"
943 "requires wallet passphrase to be set with walletpassphrase first");
944 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
946 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
947 "amounts are double-precision floating point numbers");
949 string strAccount = AccountFromValue(params[0]);
950 Object sendTo = params[1].get_obj();
952 if (params.size() > 2)
953 nMinDepth = params[2].get_int();
956 wtx.strFromAccount = strAccount;
957 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
958 wtx.mapValue["comment"] = params[3].get_str();
960 set<CBitcoinAddress> setAddress;
961 vector<pair<CScript, int64> > vecSend;
963 int64 totalAmount = 0;
964 BOOST_FOREACH(const Pair& s, sendTo)
966 CBitcoinAddress address(s.name_);
967 if (!address.IsValid())
968 throw JSONRPCError(-5, string("Invalid ppcoin address:")+s.name_);
970 if (setAddress.count(address))
971 throw JSONRPCError(-8, string("Invalid parameter, duplicated address: ")+s.name_);
972 setAddress.insert(address);
974 CScript scriptPubKey;
975 scriptPubKey.SetBitcoinAddress(address);
976 int64 nAmount = AmountFromValue(s.value_);
977 if (nAmount < MIN_TXOUT_AMOUNT)
978 throw JSONRPCError(-101, "Send amount too small");
979 totalAmount += nAmount;
981 vecSend.push_back(make_pair(scriptPubKey, nAmount));
984 if (pwalletMain->IsLocked())
985 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
986 if (fWalletUnlockMintOnly)
987 throw JSONRPCError(-13, "Error: Wallet unlocked for block minting only.");
990 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
991 if (totalAmount > nBalance)
992 throw JSONRPCError(-6, "Account has insufficient funds");
995 CReserveKey keyChange(pwalletMain);
996 int64 nFeeRequired = 0;
997 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
1000 if (totalAmount + nFeeRequired > pwalletMain->GetBalance())
1001 throw JSONRPCError(-6, "Insufficient funds");
1002 throw JSONRPCError(-4, "Transaction creation failed");
1004 if (!pwalletMain->CommitTransaction(wtx, keyChange))
1005 throw JSONRPCError(-4, "Transaction commit failed");
1007 return wtx.GetHash().GetHex();
1010 Value addmultisigaddress(const Array& params, bool fHelp)
1012 if (fHelp || params.size() < 2 || params.size() > 3)
1014 string msg = "addmultisigaddress <nrequired> <'[\"key\",\"key\"]'> [account]\n"
1015 "Add a nrequired-to-sign multisignature address to the wallet\"\n"
1016 "each key is a bitcoin address or hex-encoded public key\n"
1017 "If [account] is specified, assign address to [account].";
1018 throw runtime_error(msg);
1021 int nRequired = params[0].get_int();
1022 const Array& keys = params[1].get_array();
1024 if (params.size() > 2)
1025 strAccount = AccountFromValue(params[2]);
1027 // Gather public keys
1029 throw runtime_error("a multisignature address must require at least one key to redeem");
1030 if ((int)keys.size() < nRequired)
1031 throw runtime_error(
1032 strprintf("not enough keys supplied "
1033 "(got %d keys, but need at least %d to redeem)", keys.size(), nRequired));
1034 std::vector<CKey> pubkeys;
1035 pubkeys.resize(keys.size());
1036 for (unsigned int i = 0; i < keys.size(); i++)
1038 const std::string& ks = keys[i].get_str();
1040 // Case 1: bitcoin address and we have full public key:
1041 CBitcoinAddress address(ks);
1042 if (address.IsValid())
1044 if (address.IsScript())
1045 throw runtime_error(
1046 strprintf("%s is a pay-to-script address",ks.c_str()));
1047 std::vector<unsigned char> vchPubKey;
1048 if (!pwalletMain->GetPubKey(address, vchPubKey))
1049 throw runtime_error(
1050 strprintf("no full public key for address %s",ks.c_str()));
1051 if (vchPubKey.empty() || !pubkeys[i].SetPubKey(vchPubKey))
1052 throw runtime_error(" Invalid public key: "+ks);
1055 // Case 2: hex public key
1058 vector<unsigned char> vchPubKey = ParseHex(ks);
1059 if (vchPubKey.empty() || !pubkeys[i].SetPubKey(vchPubKey))
1060 throw runtime_error(" Invalid public key: "+ks);
1064 throw runtime_error(" Invalid public key: "+ks);
1068 // Construct using pay-to-script-hash:
1070 inner.SetMultisig(nRequired, pubkeys);
1072 uint160 scriptHash = Hash160(inner);
1073 CScript scriptPubKey;
1074 scriptPubKey.SetPayToScriptHash(inner);
1075 pwalletMain->AddCScript(inner);
1076 CBitcoinAddress address;
1077 address.SetScriptHash160(scriptHash);
1079 pwalletMain->SetAddressBookName(address, strAccount);
1080 return address.ToString();
1091 nConf = std::numeric_limits<int>::max();
1095 Value ListReceived(const Array& params, bool fByAccounts)
1097 // Minimum confirmations
1099 if (params.size() > 0)
1100 nMinDepth = params[0].get_int();
1102 // Whether to include empty accounts
1103 bool fIncludeEmpty = false;
1104 if (params.size() > 1)
1105 fIncludeEmpty = params[1].get_bool();
1108 map<CBitcoinAddress, tallyitem> mapTally;
1109 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1111 const CWalletTx& wtx = (*it).second;
1113 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
1116 int nDepth = wtx.GetDepthInMainChain();
1117 if (nDepth < nMinDepth)
1120 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
1122 CBitcoinAddress address;
1123 if (!ExtractAddress(txout.scriptPubKey, address) || !pwalletMain->HaveKey(address) || !address.IsValid())
1126 tallyitem& item = mapTally[address];
1127 item.nAmount += txout.nValue;
1128 item.nConf = min(item.nConf, nDepth);
1134 map<string, tallyitem> mapAccountTally;
1135 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
1137 const CBitcoinAddress& address = item.first;
1138 const string& strAccount = item.second;
1139 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
1140 if (it == mapTally.end() && !fIncludeEmpty)
1144 int nConf = std::numeric_limits<int>::max();
1145 if (it != mapTally.end())
1147 nAmount = (*it).second.nAmount;
1148 nConf = (*it).second.nConf;
1153 tallyitem& item = mapAccountTally[strAccount];
1154 item.nAmount += nAmount;
1155 item.nConf = min(item.nConf, nConf);
1160 obj.push_back(Pair("address", address.ToString()));
1161 obj.push_back(Pair("account", strAccount));
1162 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1163 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1170 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
1172 int64 nAmount = (*it).second.nAmount;
1173 int nConf = (*it).second.nConf;
1175 obj.push_back(Pair("account", (*it).first));
1176 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1177 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1185 Value listreceivedbyaddress(const Array& params, bool fHelp)
1187 if (fHelp || params.size() > 2)
1188 throw runtime_error(
1189 "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
1190 "[minconf] is the minimum number of confirmations before payments are included.\n"
1191 "[includeempty] whether to include addresses that haven't received any payments.\n"
1192 "Returns an array of objects containing:\n"
1193 " \"address\" : receiving address\n"
1194 " \"account\" : the account of the receiving address\n"
1195 " \"amount\" : total amount received by the address\n"
1196 " \"confirmations\" : number of confirmations of the most recent transaction included");
1198 return ListReceived(params, false);
1201 Value listreceivedbyaccount(const Array& params, bool fHelp)
1203 if (fHelp || params.size() > 2)
1204 throw runtime_error(
1205 "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
1206 "[minconf] is the minimum number of confirmations before payments are included.\n"
1207 "[includeempty] whether to include accounts that haven't received any payments.\n"
1208 "Returns an array of objects containing:\n"
1209 " \"account\" : the account of the receiving addresses\n"
1210 " \"amount\" : total amount received by addresses with this account\n"
1211 " \"confirmations\" : number of confirmations of the most recent transaction included");
1213 return ListReceived(params, true);
1216 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret)
1218 int64 nGeneratedImmature, nGeneratedMature, nFee;
1219 string strSentAccount;
1220 list<pair<CBitcoinAddress, int64> > listReceived;
1221 list<pair<CBitcoinAddress, int64> > listSent;
1223 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1225 bool fAllAccounts = (strAccount == string("*"));
1227 // Generated blocks assigned to account ""
1228 if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == ""))
1231 entry.push_back(Pair("account", string("")));
1232 if (nGeneratedImmature)
1234 entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
1235 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
1239 entry.push_back(Pair("category", "generate"));
1240 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
1243 WalletTxToJSON(wtx, entry);
1244 ret.push_back(entry);
1248 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1250 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1253 entry.push_back(Pair("account", strSentAccount));
1254 entry.push_back(Pair("address", s.first.ToString()));
1255 entry.push_back(Pair("category", "send"));
1256 entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1257 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1259 WalletTxToJSON(wtx, entry);
1260 ret.push_back(entry);
1265 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1267 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1270 if (pwalletMain->mapAddressBook.count(r.first))
1271 account = pwalletMain->mapAddressBook[r.first];
1272 if (fAllAccounts || (account == strAccount))
1275 entry.push_back(Pair("account", account));
1276 entry.push_back(Pair("address", r.first.ToString()));
1277 entry.push_back(Pair("category", "receive"));
1278 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1280 WalletTxToJSON(wtx, entry);
1281 ret.push_back(entry);
1287 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1289 bool fAllAccounts = (strAccount == string("*"));
1291 if (fAllAccounts || acentry.strAccount == strAccount)
1294 entry.push_back(Pair("account", acentry.strAccount));
1295 entry.push_back(Pair("category", "move"));
1296 entry.push_back(Pair("time", (boost::int64_t)acentry.nTime));
1297 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1298 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1299 entry.push_back(Pair("comment", acentry.strComment));
1300 ret.push_back(entry);
1304 Value listtransactions(const Array& params, bool fHelp)
1306 if (fHelp || params.size() > 3)
1307 throw runtime_error(
1308 "listtransactions [account] [count=10] [from=0]\n"
1309 "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1311 string strAccount = "*";
1312 if (params.size() > 0)
1313 strAccount = params[0].get_str();
1315 if (params.size() > 1)
1316 nCount = params[1].get_int();
1318 if (params.size() > 2)
1319 nFrom = params[2].get_int();
1322 throw JSONRPCError(-8, "Negative count");
1324 throw JSONRPCError(-8, "Negative from");
1327 CWalletDB walletdb(pwalletMain->strWalletFile);
1329 // First: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap.
1330 typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
1331 typedef multimap<int64, TxPair > TxItems;
1334 // Note: maintaining indices in the database of (account,time) --> txid and (account, time) --> acentry
1335 // would make this much faster for applications that do this a lot.
1336 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1338 CWalletTx* wtx = &((*it).second);
1339 txByTime.insert(make_pair(wtx->GetTxTime(), TxPair(wtx, (CAccountingEntry*)0)));
1341 list<CAccountingEntry> acentries;
1342 walletdb.ListAccountCreditDebit(strAccount, acentries);
1343 BOOST_FOREACH(CAccountingEntry& entry, acentries)
1345 txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
1348 // iterate backwards until we have nCount items to return:
1349 for (TxItems::reverse_iterator it = txByTime.rbegin(); it != txByTime.rend(); ++it)
1351 CWalletTx *const pwtx = (*it).second.first;
1353 ListTransactions(*pwtx, strAccount, 0, true, ret);
1354 CAccountingEntry *const pacentry = (*it).second.second;
1356 AcentryToJSON(*pacentry, strAccount, ret);
1358 if (ret.size() >= (nCount+nFrom)) break;
1360 // ret is newest to oldest
1362 if (nFrom > (int)ret.size())
1364 if ((nFrom + nCount) > (int)ret.size())
1365 nCount = ret.size() - nFrom;
1366 Array::iterator first = ret.begin();
1367 std::advance(first, nFrom);
1368 Array::iterator last = ret.begin();
1369 std::advance(last, nFrom+nCount);
1371 if (last != ret.end()) ret.erase(last, ret.end());
1372 if (first != ret.begin()) ret.erase(ret.begin(), first);
1374 std::reverse(ret.begin(), ret.end()); // Return oldest to newest
1379 Value listaccounts(const Array& params, bool fHelp)
1381 if (fHelp || params.size() > 1)
1382 throw runtime_error(
1383 "listaccounts [minconf=1]\n"
1384 "Returns Object that has account names as keys, account balances as values.");
1387 if (params.size() > 0)
1388 nMinDepth = params[0].get_int();
1390 map<string, int64> mapAccountBalances;
1391 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& entry, pwalletMain->mapAddressBook) {
1392 if (pwalletMain->HaveKey(entry.first)) // This address belongs to me
1393 mapAccountBalances[entry.second] = 0;
1396 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1398 const CWalletTx& wtx = (*it).second;
1399 int64 nGeneratedImmature, nGeneratedMature, nFee;
1400 string strSentAccount;
1401 list<pair<CBitcoinAddress, int64> > listReceived;
1402 list<pair<CBitcoinAddress, int64> > listSent;
1403 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1404 mapAccountBalances[strSentAccount] -= nFee;
1405 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1406 mapAccountBalances[strSentAccount] -= s.second;
1407 if (wtx.GetDepthInMainChain() >= nMinDepth)
1409 mapAccountBalances[""] += nGeneratedMature;
1410 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1411 if (pwalletMain->mapAddressBook.count(r.first))
1412 mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1414 mapAccountBalances[""] += r.second;
1418 list<CAccountingEntry> acentries;
1419 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1420 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1421 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1424 BOOST_FOREACH(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) {
1425 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1430 Value listsinceblock(const Array& params, bool fHelp)
1433 throw runtime_error(
1434 "listsinceblock [blockhash] [target-confirmations]\n"
1435 "Get all transactions in blocks since block [blockhash], or all transactions if omitted");
1437 CBlockIndex *pindex = NULL;
1438 int target_confirms = 1;
1440 if (params.size() > 0)
1442 uint256 blockId = 0;
1444 blockId.SetHex(params[0].get_str());
1445 pindex = CBlockLocator(blockId).GetBlockIndex();
1448 if (params.size() > 1)
1450 target_confirms = params[1].get_int();
1452 if (target_confirms < 1)
1453 throw JSONRPCError(-8, "Invalid parameter");
1456 int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1;
1460 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1462 CWalletTx tx = (*it).second;
1464 if (depth == -1 || tx.GetDepthInMainChain() < depth)
1465 ListTransactions(tx, "*", 0, true, transactions);
1470 if (target_confirms == 1)
1472 lastblock = hashBestChain;
1476 int target_height = pindexBest->nHeight + 1 - target_confirms;
1479 for (block = pindexBest;
1480 block && block->nHeight > target_height;
1481 block = block->pprev) { }
1483 lastblock = block ? block->GetBlockHash() : 0;
1487 ret.push_back(Pair("transactions", transactions));
1488 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1493 Value gettransaction(const Array& params, bool fHelp)
1495 if (fHelp || params.size() != 1)
1496 throw runtime_error(
1497 "gettransaction <txid>\n"
1498 "Get detailed information about <txid>");
1501 hash.SetHex(params[0].get_str());
1505 if (!pwalletMain->mapWallet.count(hash))
1506 throw JSONRPCError(-5, "Invalid or non-wallet transaction id");
1507 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1509 int64 nCredit = wtx.GetCredit();
1510 int64 nDebit = wtx.GetDebit();
1511 int64 nNet = nCredit - nDebit;
1512 int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
1514 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1516 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1518 WalletTxToJSON(pwalletMain->mapWallet[hash], entry);
1521 ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
1522 entry.push_back(Pair("details", details));
1528 Value backupwallet(const Array& params, bool fHelp)
1530 if (fHelp || params.size() != 1)
1531 throw runtime_error(
1532 "backupwallet <destination>\n"
1533 "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1535 string strDest = params[0].get_str();
1536 BackupWallet(*pwalletMain, strDest);
1542 Value keypoolrefill(const Array& params, bool fHelp)
1544 if (pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1545 throw runtime_error(
1547 "Fills the keypool, requires wallet passphrase to be set.");
1548 if (!pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1549 throw runtime_error(
1551 "Fills the keypool.");
1553 if (pwalletMain->IsLocked())
1554 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
1556 pwalletMain->TopUpKeyPool();
1558 if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100))
1559 throw JSONRPCError(-4, "Error refreshing keypool.");
1565 void ThreadTopUpKeyPool(void* parg)
1567 pwalletMain->TopUpKeyPool();
1570 void ThreadCleanWalletPassphrase(void* parg)
1572 int64 nMyWakeTime = GetTimeMillis() + *((int64*)parg) * 1000;
1574 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1576 if (nWalletUnlockTime == 0)
1578 nWalletUnlockTime = nMyWakeTime;
1582 if (nWalletUnlockTime==0)
1584 int64 nToSleep = nWalletUnlockTime - GetTimeMillis();
1588 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1590 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1594 if (nWalletUnlockTime)
1596 nWalletUnlockTime = 0;
1597 pwalletMain->Lock();
1602 if (nWalletUnlockTime < nMyWakeTime)
1603 nWalletUnlockTime = nMyWakeTime;
1606 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1608 delete (int64*)parg;
1611 Value walletpassphrase(const Array& params, bool fHelp)
1613 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 3))
1614 throw runtime_error(
1615 "walletpassphrase <passphrase> <timeout> [mintonly]\n"
1616 "Stores the wallet decryption key in memory for <timeout> seconds.\n"
1617 "mintonly is optional true/false allowing only block minting.");
1620 if (!pwalletMain->IsCrypted())
1621 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1623 if (!pwalletMain->IsLocked())
1624 throw JSONRPCError(-17, "Error: Wallet is already unlocked, use walletlock first if need to change unlock settings.");
1626 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1627 SecureString strWalletPass;
1628 strWalletPass.reserve(100);
1629 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1630 // Alternately, find a way to make params[0] mlock()'d to begin with.
1631 strWalletPass = params[0].get_str().c_str();
1633 if (strWalletPass.length() > 0)
1635 if (!pwalletMain->Unlock(strWalletPass))
1636 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1639 throw runtime_error(
1640 "walletpassphrase <passphrase> <timeout>\n"
1641 "Stores the wallet decryption key in memory for <timeout> seconds.");
1643 CreateThread(ThreadTopUpKeyPool, NULL);
1644 int64* pnSleepTime = new int64(params[1].get_int64());
1645 CreateThread(ThreadCleanWalletPassphrase, pnSleepTime);
1647 // ppcoin: if user OS account compromised prevent trivial sendmoney commands
1648 if (params.size() > 2)
1649 fWalletUnlockMintOnly = params[2].get_bool();
1651 fWalletUnlockMintOnly = false;
1657 Value walletpassphrasechange(const Array& params, bool fHelp)
1659 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1660 throw runtime_error(
1661 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1662 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1665 if (!pwalletMain->IsCrypted())
1666 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1668 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1669 // Alternately, find a way to make params[0] mlock()'d to begin with.
1670 SecureString strOldWalletPass;
1671 strOldWalletPass.reserve(100);
1672 strOldWalletPass = params[0].get_str().c_str();
1674 SecureString strNewWalletPass;
1675 strNewWalletPass.reserve(100);
1676 strNewWalletPass = params[1].get_str().c_str();
1678 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1679 throw runtime_error(
1680 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1681 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1683 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1684 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1690 Value walletlock(const Array& params, bool fHelp)
1692 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1693 throw runtime_error(
1695 "Removes the wallet encryption key from memory, locking the wallet.\n"
1696 "After calling this method, you will need to call walletpassphrase again\n"
1697 "before being able to call any methods which require the wallet to be unlocked.");
1700 if (!pwalletMain->IsCrypted())
1701 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called.");
1704 LOCK(cs_nWalletUnlockTime);
1705 pwalletMain->Lock();
1706 nWalletUnlockTime = 0;
1713 Value encryptwallet(const Array& params, bool fHelp)
1715 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1716 throw runtime_error(
1717 "encryptwallet <passphrase>\n"
1718 "Encrypts the wallet with <passphrase>.");
1721 if (pwalletMain->IsCrypted())
1722 throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
1724 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1725 // Alternately, find a way to make params[0] mlock()'d to begin with.
1726 SecureString strWalletPass;
1727 strWalletPass.reserve(100);
1728 strWalletPass = params[0].get_str().c_str();
1730 if (strWalletPass.length() < 1)
1731 throw runtime_error(
1732 "encryptwallet <passphrase>\n"
1733 "Encrypts the wallet with <passphrase>.");
1735 if (!pwalletMain->EncryptWallet(strWalletPass))
1736 throw JSONRPCError(-16, "Error: Failed to encrypt the wallet.");
1738 // BDB seems to have a bad habit of writing old data into
1739 // slack space in .dat files; that is bad if the old data is
1740 // unencrypted private keys. So:
1742 return "wallet encrypted; ppcoin server stopping, restart to run with encrypted wallet";
1746 Value validateaddress(const Array& params, bool fHelp)
1748 if (fHelp || params.size() != 1)
1749 throw runtime_error(
1750 "validateaddress <ppcoinaddress>\n"
1751 "Return information about <ppcoinaddress>.");
1753 CBitcoinAddress address(params[0].get_str());
1754 bool isValid = address.IsValid();
1757 ret.push_back(Pair("isvalid", isValid));
1760 // Call Hash160ToAddress() so we always return current ADDRESSVERSION
1761 // version of the address:
1762 string currentAddress = address.ToString();
1763 ret.push_back(Pair("address", currentAddress));
1764 if (pwalletMain->HaveKey(address))
1766 ret.push_back(Pair("ismine", true));
1767 std::vector<unsigned char> vchPubKey;
1768 pwalletMain->GetPubKey(address, vchPubKey);
1769 ret.push_back(Pair("pubkey", HexStr(vchPubKey)));
1771 key.SetPubKey(vchPubKey);
1772 ret.push_back(Pair("iscompressed", key.IsCompressed()));
1774 else if (pwalletMain->HaveCScript(address.GetHash160()))
1776 ret.push_back(Pair("isscript", true));
1778 pwalletMain->GetCScript(address.GetHash160(), subscript);
1779 ret.push_back(Pair("ismine", ::IsMine(*pwalletMain, subscript)));
1780 std::vector<CBitcoinAddress> addresses;
1781 txnouttype whichType;
1783 ExtractAddresses(subscript, whichType, addresses, nRequired);
1784 ret.push_back(Pair("script", GetTxnOutputType(whichType)));
1786 BOOST_FOREACH(const CBitcoinAddress& addr, addresses)
1787 a.push_back(addr.ToString());
1788 ret.push_back(Pair("addresses", a));
1789 if (whichType == TX_MULTISIG)
1790 ret.push_back(Pair("sigsrequired", nRequired));
1793 ret.push_back(Pair("ismine", false));
1794 if (pwalletMain->mapAddressBook.count(address))
1795 ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
1800 Value getwork(const Array& params, bool fHelp)
1802 if (fHelp || params.size() > 1)
1803 throw runtime_error(
1805 "If [data] is not specified, returns formatted hash data to work on:\n"
1806 " \"midstate\" : precomputed hash state after hashing the first half of the data (DEPRECATED)\n" // deprecated
1807 " \"data\" : block data\n"
1808 " \"hash1\" : formatted hash buffer for second hash (DEPRECATED)\n" // deprecated
1809 " \"target\" : little endian hash target\n"
1810 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1813 throw JSONRPCError(-9, "PPCoin is not connected!");
1815 if (IsInitialBlockDownload())
1816 throw JSONRPCError(-10, "PPCoin is downloading blocks...");
1818 typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
1819 static mapNewBlock_t mapNewBlock;
1820 static vector<CBlock*> vNewBlock;
1821 static CReserveKey reservekey(pwalletMain);
1823 if (params.size() == 0)
1826 static unsigned int nTransactionsUpdatedLast;
1827 static CBlockIndex* pindexPrev;
1828 static int64 nStart;
1829 static CBlock* pblock;
1830 if (pindexPrev != pindexBest ||
1831 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
1833 if (pindexPrev != pindexBest)
1835 // Deallocate old blocks since they're obsolete now
1836 mapNewBlock.clear();
1837 BOOST_FOREACH(CBlock* pblock, vNewBlock)
1841 nTransactionsUpdatedLast = nTransactionsUpdated;
1842 pindexPrev = pindexBest;
1846 pblock = CreateNewBlock(pwalletMain);
1848 throw JSONRPCError(-7, "Out of memory");
1849 vNewBlock.push_back(pblock);
1853 pblock->UpdateTime(pindexPrev);
1856 // Update nExtraNonce
1857 static unsigned int nExtraNonce = 0;
1858 IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
1861 mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
1863 // Prebuild hash buffers
1867 FormatHashBuffers(pblock, pmidstate, pdata, phash1);
1869 uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
1872 result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate)))); // deprecated
1873 result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata))));
1874 result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1)))); // deprecated
1875 result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
1881 vector<unsigned char> vchData = ParseHex(params[0].get_str());
1882 if (vchData.size() != 128)
1883 throw JSONRPCError(-8, "Invalid parameter");
1884 CBlock* pdata = (CBlock*)&vchData[0];
1887 for (int i = 0; i < 128/4; i++)
1888 ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]);
1891 if (!mapNewBlock.count(pdata->hashMerkleRoot))
1893 CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
1895 pblock->nTime = pdata->nTime;
1896 pblock->nNonce = pdata->nNonce;
1897 pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
1898 pblock->hashMerkleRoot = pblock->BuildMerkleTree();
1899 if (!pblock->SignBlock(*pwalletMain))
1900 throw JSONRPCError(-100, "Unable to sign block, wallet locked?");
1902 return CheckWork(pblock, *pwalletMain, reservekey);
1907 Value getmemorypool(const Array& params, bool fHelp)
1909 if (fHelp || params.size() > 1)
1910 throw runtime_error(
1911 "getmemorypool [data]\n"
1912 "If [data] is not specified, returns data needed to construct a block to work on:\n"
1913 " \"version\" : block version\n"
1914 " \"previousblockhash\" : hash of current highest block\n"
1915 " \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
1916 " \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
1917 " \"coinbaseflags\" : data that should be included in coinbase so support for new features can be judged\n"
1918 " \"time\" : timestamp appropriate for next block\n"
1919 " \"mintime\" : minimum timestamp appropriate for next block\n"
1920 " \"curtime\" : current timestamp\n"
1921 " \"bits\" : compressed target of next block\n"
1922 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1924 if (params.size() == 0)
1927 throw JSONRPCError(-9, "PPCoin is not connected!");
1929 if (IsInitialBlockDownload())
1930 throw JSONRPCError(-10, "PPCoin is downloading blocks...");
1932 static CReserveKey reservekey(pwalletMain);
1935 static unsigned int nTransactionsUpdatedLast;
1936 static CBlockIndex* pindexPrev;
1937 static int64 nStart;
1938 static CBlock* pblock;
1939 if (pindexPrev != pindexBest ||
1940 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5))
1942 nTransactionsUpdatedLast = nTransactionsUpdated;
1943 pindexPrev = pindexBest;
1949 pblock = CreateNewBlock(pwalletMain);
1951 throw JSONRPCError(-7, "Out of memory");
1955 pblock->UpdateTime(pindexPrev);
1959 BOOST_FOREACH(CTransaction tx, pblock->vtx) {
1960 if(tx.IsCoinBase() || tx.IsCoinStake())
1963 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
1966 transactions.push_back(HexStr(ssTx.begin(), ssTx.end()));
1970 result.push_back(Pair("version", pblock->nVersion));
1971 result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
1972 result.push_back(Pair("transactions", transactions));
1973 result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
1974 result.push_back(Pair("coinbaseflags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end())));
1975 result.push_back(Pair("time", (int64_t)pblock->nTime));
1976 result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1));
1977 result.push_back(Pair("curtime", (int64_t)GetAdjustedTime()));
1978 result.push_back(Pair("bits", HexBits(pblock->nBits)));
1985 CDataStream ssBlock(ParseHex(params[0].get_str()), SER_NETWORK, PROTOCOL_VERSION);
1989 return ProcessBlock(NULL, &pblock);
1993 Value getblockhash(const Array& params, bool fHelp)
1995 if (fHelp || params.size() != 1)
1996 throw runtime_error(
1997 "getblockhash <index>\n"
1998 "Returns hash of block in best-block-chain at <index>.");
2000 int nHeight = params[0].get_int();
2001 if (nHeight < 0 || nHeight > nBestHeight)
2002 throw runtime_error("Block number out of range.");
2005 CBlockIndex* pblockindex = mapBlockIndex[hashBestChain];
2006 while (pblockindex->nHeight > nHeight)
2007 pblockindex = pblockindex->pprev;
2008 return pblockindex->phashBlock->GetHex();
2011 Value getblock(const Array& params, bool fHelp)
2013 if (fHelp || params.size() < 1 || params.size() > 2)
2014 throw runtime_error(
2015 "getblock <hash> [txinfo]\n"
2016 "txinfo optional to print more detailed tx info\n"
2017 "Returns details of a block with given block-hash.");
2019 std::string strHash = params[0].get_str();
2020 uint256 hash(strHash);
2022 if (mapBlockIndex.count(hash) == 0)
2023 throw JSONRPCError(-5, "Block not found");
2026 CBlockIndex* pblockindex = mapBlockIndex[hash];
2027 block.ReadFromDisk(pblockindex, true);
2029 return blockToJSON(block, pblockindex, params.size() > 1 ? params[1].get_bool() : false);
2033 // ppcoin: get information of sync-checkpoint
2034 Value getcheckpoint(const Array& params, bool fHelp)
2036 if (fHelp || params.size() != 0)
2037 throw runtime_error(
2039 "Show info of synchronized checkpoint.\n");
2042 CBlockIndex* pindexCheckpoint;
2044 result.push_back(Pair("synccheckpoint", Checkpoints::hashSyncCheckpoint.ToString().c_str()));
2045 pindexCheckpoint = mapBlockIndex[Checkpoints::hashSyncCheckpoint];
2046 result.push_back(Pair("height", pindexCheckpoint->nHeight));
2047 result.push_back(Pair("timestamp", DateTimeStrFormat(pindexCheckpoint->GetBlockTime()).c_str()));
2048 if (mapArgs.count("-checkpointkey"))
2049 result.push_back(Pair("checkpointmaster", true));
2055 // ppcoin: reserve balance from being staked for network protection
2056 Value reservebalance(const Array& params, bool fHelp)
2058 if (fHelp || params.size() > 2)
2059 throw runtime_error(
2060 "reservebalance [<reserve> [amount]]\n"
2061 "<reserve> is true or false to turn balance reserve on or off.\n"
2062 "<amount> is a real and rounded to cent.\n"
2063 "Set reserve amount not participating in network protection.\n"
2064 "If no parameters provided current setting is printed.\n");
2066 if (params.size() > 0)
2068 bool fReserve = params[0].get_bool();
2071 if (params.size() == 1)
2072 throw runtime_error("must provide amount to reserve balance.\n");
2073 int64 nAmount = AmountFromValue(params[1]);
2074 nAmount = (nAmount / CENT) * CENT; // round to cent
2076 throw runtime_error("amount cannot be negative.\n");
2077 mapArgs["-reservebalance"] = FormatMoney(nAmount).c_str();
2081 if (params.size() > 1)
2082 throw runtime_error("cannot specify amount to turn off reserve.\n");
2083 mapArgs["-reservebalance"] = "0";
2088 int64 nReserveBalance = 0;
2089 if (mapArgs.count("-reservebalance") && !ParseMoney(mapArgs["-reservebalance"], nReserveBalance))
2090 throw runtime_error("invalid reserve balance amount\n");
2091 result.push_back(Pair("reserve", (nReserveBalance > 0)));
2092 result.push_back(Pair("amount", ValueFromAmount(nReserveBalance)));
2097 // ppcoin: check wallet integrity
2098 Value checkwallet(const Array& params, bool fHelp)
2100 if (fHelp || params.size() > 0)
2101 throw runtime_error(
2103 "Check wallet for integrity.\n");
2106 int64 nBalanceInQuestion;
2107 if (!pwalletMain->CheckSpentCoins(nMismatchSpent, nBalanceInQuestion))
2110 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
2111 result.push_back(Pair("amount in question", ValueFromAmount(nBalanceInQuestion)));
2118 // ppcoin: repair wallet
2119 Value repairwallet(const Array& params, bool fHelp)
2121 if (fHelp || params.size() > 0)
2122 throw runtime_error(
2124 "Repair wallet if checkwallet reports any problem.\n");
2127 int64 nBalanceInQuestion;
2128 pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion);
2130 if (nMismatchSpent == 0)
2132 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;