1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2012 The Bitcoin developers
3 // Copyright (c) 2011-2012 The PPCoin developers
4 // Distributed under the MIT/X11 software license, see the accompanying
5 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
13 #include "checkpoints.h"
14 #include "ui_interface.h"
15 #include "bitcoinrpc.h"
18 #include <boost/asio.hpp>
19 #include <boost/filesystem.hpp>
20 #include <boost/iostreams/concepts.hpp>
21 #include <boost/iostreams/stream.hpp>
22 #include <boost/algorithm/string.hpp>
23 #include <boost/lexical_cast.hpp>
24 #include <boost/asio/ssl.hpp>
25 #include <boost/filesystem/fstream.hpp>
26 typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> SSLStream;
28 #define printf OutputDebugStringF
29 // MinGW 3.4.5 gets "fatal error: had to relocate PCH" if the json headers are
30 // precompiled in headers.h. The problem might be when the pch file goes over
31 // a certain size around 145MB. If we need access to json_spirit outside this
32 // file, we could use the compiled json_spirit option.
35 using namespace boost;
36 using namespace boost::asio;
37 using namespace json_spirit;
39 void ThreadRPCServer2(void* parg);
41 static std::string strRPCUserColonPass;
43 static int64 nWalletUnlockTime;
44 static CCriticalSection cs_nWalletUnlockTime;
46 extern Value dumpprivkey(const Array& params, bool fHelp);
47 extern Value importprivkey(const Array& params, bool fHelp);
49 Object JSONRPCError(int code, const string& message)
52 error.push_back(Pair("code", code));
53 error.push_back(Pair("message", message));
57 double GetDifficulty(const CBlockIndex* blockindex = NULL)
59 // Floating point number that is a multiple of the minimum difficulty,
60 // minimum difficulty = 1.0.
61 if (blockindex == NULL)
63 if (pindexBest == NULL)
66 blockindex = GetLastBlockIndex(pindexBest, false);
69 int nShift = (blockindex->nBits >> 24) & 0xff;
72 (double)0x0000ffff / (double)(blockindex->nBits & 0x00ffffff);
89 int64 AmountFromValue(const Value& value)
91 double dAmount = value.get_real();
92 if (dAmount <= 0.0 || dAmount > MAX_MONEY)
93 throw JSONRPCError(-3, "Invalid amount");
94 int64 nAmount = roundint64(dAmount * COIN);
95 if (!MoneyRange(nAmount))
96 throw JSONRPCError(-3, "Invalid amount");
100 Value ValueFromAmount(int64 amount)
102 return (double)amount / (double)COIN;
106 HexBits(unsigned int nBits)
112 uBits.nBits = htonl((int32_t)nBits);
113 return HexStr(BEGIN(uBits.cBits), END(uBits.cBits));
116 void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
118 int confirms = wtx.GetDepthInMainChain();
119 entry.push_back(Pair("confirmations", confirms));
122 entry.push_back(Pair("blockhash", wtx.hashBlock.GetHex()));
123 entry.push_back(Pair("blockindex", wtx.nIndex));
125 entry.push_back(Pair("txid", wtx.GetHash().GetHex()));
126 entry.push_back(Pair("time", (boost::int64_t)wtx.GetTxTime()));
127 BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
128 entry.push_back(Pair(item.first, item.second));
131 string AccountFromValue(const Value& value)
133 string strAccount = value.get_str();
134 if (strAccount == "*")
135 throw JSONRPCError(-11, "Invalid account name");
139 Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool fPrintTransactionDetail)
142 result.push_back(Pair("hash", block.GetHash().GetHex()));
143 result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION)));
144 result.push_back(Pair("height", blockindex->nHeight));
145 result.push_back(Pair("version", block.nVersion));
146 result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex()));
147 result.push_back(Pair("time", DateTimeStrFormat(block.GetBlockTime())));
148 result.push_back(Pair("nonce", (boost::uint64_t)block.nNonce));
149 result.push_back(Pair("bits", HexBits(block.nBits)));
150 result.push_back(Pair("difficulty", GetDifficulty(blockindex)));
151 result.push_back(Pair("mint", ValueFromAmount(blockindex->nMint)));
152 if (blockindex->pprev)
153 result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex()));
154 if (blockindex->pnext)
155 result.push_back(Pair("nextblockhash", blockindex->pnext->GetBlockHash().GetHex()));
157 BOOST_FOREACH (const CTransaction& tx, block.vtx)
159 if (fPrintTransactionDetail)
161 txinfo.push_back(tx.ToStringShort());
162 txinfo.push_back(DateTimeStrFormat(tx.nTime));
163 BOOST_FOREACH(const CTxIn& txin, tx.vin)
164 txinfo.push_back(txin.ToStringShort());
165 BOOST_FOREACH(const CTxOut& txout, tx.vout)
166 txinfo.push_back(txout.ToStringShort());
169 txinfo.push_back(tx.GetHash().GetHex());
171 result.push_back(Pair("tx", txinfo));
178 /// Note: This interface may still be subject to change.
181 string CRPCTable::help(string strCommand) const
184 set<rpcfn_type> setDone;
185 for (map<string, const CRPCCommand*>::const_iterator mi = mapCommands.begin(); mi != mapCommands.end(); ++mi)
187 const CRPCCommand *pcmd = mi->second;
188 string strMethod = mi->first;
189 // We already filter duplicates, but these deprecated screw up the sort order
190 if (strMethod == "getamountreceived" ||
191 strMethod == "getallreceived" ||
192 strMethod == "getblocknumber" || // deprecated
193 (strMethod.find("label") != string::npos))
195 if (strCommand != "" && strMethod != strCommand)
200 rpcfn_type pfn = pcmd->actor;
201 if (setDone.insert(pfn).second)
202 (*pfn)(params, true);
204 catch (std::exception& e)
206 // Help text is returned in an exception
207 string strHelp = string(e.what());
208 if (strCommand == "")
209 if (strHelp.find('\n') != string::npos)
210 strHelp = strHelp.substr(0, strHelp.find('\n'));
211 strRet += strHelp + "\n";
215 strRet = strprintf("help: unknown command: %s\n", strCommand.c_str());
216 strRet = strRet.substr(0,strRet.size()-1);
220 Value help(const Array& params, bool fHelp)
222 if (fHelp || params.size() > 1)
225 "List commands, or get help for a command.");
228 if (params.size() > 0)
229 strCommand = params[0].get_str();
231 return tableRPC.help(strCommand);
235 Value stop(const Array& params, bool fHelp)
237 if (fHelp || params.size() != 0)
240 "Stop ppcoin server.");
241 // Shutdown will take long enough that the response should get back
243 return "ppcoin server stopping";
247 Value getblockcount(const Array& params, bool fHelp)
249 if (fHelp || params.size() != 0)
252 "Returns the number of blocks in the longest block chain.");
259 Value getblocknumber(const Array& params, bool fHelp)
261 if (fHelp || params.size() != 0)
264 "Deprecated. Use getblockcount.");
270 Value getconnectioncount(const Array& params, bool fHelp)
272 if (fHelp || params.size() != 0)
274 "getconnectioncount\n"
275 "Returns the number of connections to other nodes.");
277 return (int)vNodes.size();
281 Value getdifficulty(const Array& params, bool fHelp)
283 if (fHelp || params.size() != 0)
286 "Returns difficulty as a multiple of the minimum difficulty.");
289 obj.push_back(Pair("proof-of-work", GetDifficulty()));
290 obj.push_back(Pair("proof-of-stake", GetDifficulty(GetLastBlockIndex(pindexBest, true))));
295 Value getgenerate(const Array& params, bool fHelp)
297 if (fHelp || params.size() != 0)
300 "Returns true or false.");
302 return GetBoolArg("-gen");
306 Value setgenerate(const Array& params, bool fHelp)
308 if (fHelp || params.size() < 1 || params.size() > 2)
310 "setgenerate <generate> [genproclimit]\n"
311 "<generate> is true or false to turn generation on or off.\n"
312 "Generation is limited to [genproclimit] processors, -1 is unlimited.");
314 bool fGenerate = true;
315 if (params.size() > 0)
316 fGenerate = params[0].get_bool();
318 if (params.size() > 1)
320 int nGenProcLimit = params[1].get_int();
321 mapArgs["-genproclimit"] = itostr(nGenProcLimit);
322 if (nGenProcLimit == 0)
325 mapArgs["-gen"] = (fGenerate ? "1" : "0");
327 GenerateBitcoins(fGenerate, pwalletMain);
332 Value gethashespersec(const Array& params, bool fHelp)
334 if (fHelp || params.size() != 0)
337 "Returns a recent hashes per second performance measurement while generating.");
339 if (GetTimeMillis() - nHPSTimerStart > 8000)
340 return (boost::int64_t)0;
341 return (boost::int64_t)dHashesPerSec;
345 Value getinfo(const Array& params, bool fHelp)
347 if (fHelp || params.size() != 0)
350 "Returns an object containing various state info.");
353 obj.push_back(Pair("version", FormatFullVersion()));
354 obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION));
355 obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
356 obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
357 obj.push_back(Pair("newmint", ValueFromAmount(pwalletMain->GetNewMint())));
358 obj.push_back(Pair("stake", ValueFromAmount(pwalletMain->GetStake())));
359 obj.push_back(Pair("blocks", (int)nBestHeight));
360 obj.push_back(Pair("moneysupply", ValueFromAmount(pindexBest->nMoneySupply)));
361 obj.push_back(Pair("connections", (int)vNodes.size()));
362 obj.push_back(Pair("proxy", (fUseProxy ? addrProxy.ToStringIPPort() : string())));
363 obj.push_back(Pair("ip", addrSeenByPeer.ToStringIP()));
364 obj.push_back(Pair("difficulty", (double)GetDifficulty()));
365 obj.push_back(Pair("testnet", fTestNet));
366 obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));
367 obj.push_back(Pair("keypoolsize", pwalletMain->GetKeyPoolSize()));
368 obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee)));
369 if (pwalletMain->IsCrypted())
370 obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime / 1000));
371 obj.push_back(Pair("errors", GetWarnings("statusbar")));
376 Value getmininginfo(const Array& params, bool fHelp)
378 if (fHelp || params.size() != 0)
381 "Returns an object containing mining-related information.");
384 obj.push_back(Pair("blocks", (int)nBestHeight));
385 obj.push_back(Pair("currentblocksize",(uint64_t)nLastBlockSize));
386 obj.push_back(Pair("currentblocktx",(uint64_t)nLastBlockTx));
387 obj.push_back(Pair("difficulty", (double)GetDifficulty()));
388 obj.push_back(Pair("errors", GetWarnings("statusbar")));
389 obj.push_back(Pair("generate", GetBoolArg("-gen")));
390 obj.push_back(Pair("genproclimit", (int)GetArg("-genproclimit", -1)));
391 obj.push_back(Pair("hashespersec", gethashespersec(params, false)));
392 obj.push_back(Pair("pooledtx", (uint64_t)mempool.size()));
393 obj.push_back(Pair("testnet", fTestNet));
398 Value getnewaddress(const Array& params, bool fHelp)
400 if (fHelp || params.size() > 1)
402 "getnewaddress [account]\n"
403 "Returns a new ppcoin address for receiving payments. "
404 "If [account] is specified (recommended), it is added to the address book "
405 "so payments received with the address will be credited to [account].");
407 // Parse the account first so we don't generate a key if there's an error
409 if (params.size() > 0)
410 strAccount = AccountFromValue(params[0]);
412 if (!pwalletMain->IsLocked())
413 pwalletMain->TopUpKeyPool();
415 // Generate a new key that is added to wallet
416 std::vector<unsigned char> newKey;
417 if (!pwalletMain->GetKeyFromPool(newKey, false))
418 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
419 CBitcoinAddress address(newKey);
421 pwalletMain->SetAddressBookName(address, strAccount);
423 return address.ToString();
427 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
429 CWalletDB walletdb(pwalletMain->strWalletFile);
432 walletdb.ReadAccount(strAccount, account);
434 bool bKeyUsed = false;
436 // Check if the current key has been used
437 if (!account.vchPubKey.empty())
439 CScript scriptPubKey;
440 scriptPubKey.SetBitcoinAddress(account.vchPubKey);
441 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
442 it != pwalletMain->mapWallet.end() && !account.vchPubKey.empty();
445 const CWalletTx& wtx = (*it).second;
446 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
447 if (txout.scriptPubKey == scriptPubKey)
452 // Generate a new key
453 if (account.vchPubKey.empty() || bForceNew || bKeyUsed)
455 if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false))
456 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
458 pwalletMain->SetAddressBookName(CBitcoinAddress(account.vchPubKey), strAccount);
459 walletdb.WriteAccount(strAccount, account);
462 return CBitcoinAddress(account.vchPubKey);
465 Value getaccountaddress(const Array& params, bool fHelp)
467 if (fHelp || params.size() != 1)
469 "getaccountaddress <account>\n"
470 "Returns the current ppcoin address for receiving payments to this account.");
472 // Parse the account first so we don't generate a key if there's an error
473 string strAccount = AccountFromValue(params[0]);
477 ret = GetAccountAddress(strAccount).ToString();
484 Value setaccount(const Array& params, bool fHelp)
486 if (fHelp || params.size() < 1 || params.size() > 2)
488 "setaccount <ppcoinaddress> <account>\n"
489 "Sets the account associated with the given address.");
491 CBitcoinAddress address(params[0].get_str());
492 if (!address.IsValid())
493 throw JSONRPCError(-5, "Invalid ppcoin address");
497 if (params.size() > 1)
498 strAccount = AccountFromValue(params[1]);
500 // Detect when changing the account of an address that is the 'unused current key' of another account:
501 if (pwalletMain->mapAddressBook.count(address))
503 string strOldAccount = pwalletMain->mapAddressBook[address];
504 if (address == GetAccountAddress(strOldAccount))
505 GetAccountAddress(strOldAccount, true);
508 pwalletMain->SetAddressBookName(address, strAccount);
514 Value getaccount(const Array& params, bool fHelp)
516 if (fHelp || params.size() != 1)
518 "getaccount <ppcoinaddress>\n"
519 "Returns the account associated with the given address.");
521 CBitcoinAddress address(params[0].get_str());
522 if (!address.IsValid())
523 throw JSONRPCError(-5, "Invalid ppcoin address");
526 map<CBitcoinAddress, string>::iterator mi = pwalletMain->mapAddressBook.find(address);
527 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
528 strAccount = (*mi).second;
533 Value getaddressesbyaccount(const Array& params, bool fHelp)
535 if (fHelp || params.size() != 1)
537 "getaddressesbyaccount <account>\n"
538 "Returns the list of addresses for the given account.");
540 string strAccount = AccountFromValue(params[0]);
542 // Find all addresses that have the given account
544 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
546 const CBitcoinAddress& address = item.first;
547 const string& strName = item.second;
548 if (strName == strAccount)
549 ret.push_back(address.ToString());
554 Value settxfee(const Array& params, bool fHelp)
556 if (fHelp || params.size() < 1 || params.size() > 1 || AmountFromValue(params[0]) < MIN_TX_FEE)
558 "settxfee <amount>\n"
559 "<amount> is a real and is rounded to 0.01 (cent)\n"
560 "Minimum and default transaction fee per KB is 1 cent");
562 nTransactionFee = AmountFromValue(params[0]);
563 nTransactionFee = (nTransactionFee / CENT) * CENT; // round to cent
567 Value sendtoaddress(const Array& params, bool fHelp)
569 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
571 "sendtoaddress <ppcoinaddress> <amount> [comment] [comment-to]\n"
572 "<amount> is a real and is rounded to the nearest 0.000001\n"
573 "requires wallet passphrase to be set with walletpassphrase first");
574 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
576 "sendtoaddress <ppcoinaddress> <amount> [comment] [comment-to]\n"
577 "<amount> is a real and is rounded to the nearest 0.000001");
579 CBitcoinAddress address(params[0].get_str());
580 if (!address.IsValid())
581 throw JSONRPCError(-5, "Invalid ppcoin address");
584 int64 nAmount = AmountFromValue(params[1]);
585 if (nAmount < MIN_TXOUT_AMOUNT)
586 throw JSONRPCError(-101, "Send amount too small");
590 if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
591 wtx.mapValue["comment"] = params[2].get_str();
592 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
593 wtx.mapValue["to"] = params[3].get_str();
595 if (pwalletMain->IsLocked())
596 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
598 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
600 throw JSONRPCError(-4, strError);
602 return wtx.GetHash().GetHex();
605 Value signmessage(const Array& params, bool fHelp)
607 if (fHelp || params.size() != 2)
609 "signmessage <ppcoinaddress> <message>\n"
610 "Sign a message with the private key of an address");
612 if (pwalletMain->IsLocked())
613 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
615 string strAddress = params[0].get_str();
616 string strMessage = params[1].get_str();
618 CBitcoinAddress addr(strAddress);
620 throw JSONRPCError(-3, "Invalid address");
623 if (!pwalletMain->GetKey(addr, key))
624 throw JSONRPCError(-4, "Private key not available");
626 CDataStream ss(SER_GETHASH, 0);
627 ss << strMessageMagic;
630 vector<unsigned char> vchSig;
631 if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig))
632 throw JSONRPCError(-5, "Sign failed");
634 return EncodeBase64(&vchSig[0], vchSig.size());
637 Value verifymessage(const Array& params, bool fHelp)
639 if (fHelp || params.size() != 3)
641 "verifymessage <ppcoinaddress> <signature> <message>\n"
642 "Verify a signed message");
644 string strAddress = params[0].get_str();
645 string strSign = params[1].get_str();
646 string strMessage = params[2].get_str();
648 CBitcoinAddress addr(strAddress);
650 throw JSONRPCError(-3, "Invalid address");
652 bool fInvalid = false;
653 vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
656 throw JSONRPCError(-5, "Malformed base64 encoding");
658 CDataStream ss(SER_GETHASH, 0);
659 ss << strMessageMagic;
663 if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
666 return (CBitcoinAddress(key.GetPubKey()) == addr);
670 Value getreceivedbyaddress(const Array& params, bool fHelp)
672 if (fHelp || params.size() < 1 || params.size() > 2)
674 "getreceivedbyaddress <ppcoinaddress> [minconf=1]\n"
675 "Returns the total amount received by <ppcoinaddress> in transactions with at least [minconf] confirmations.");
678 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
679 CScript scriptPubKey;
680 if (!address.IsValid())
681 throw JSONRPCError(-5, "Invalid ppcoin address");
682 scriptPubKey.SetBitcoinAddress(address);
683 if (!IsMine(*pwalletMain,scriptPubKey))
686 // Minimum confirmations
688 if (params.size() > 1)
689 nMinDepth = params[1].get_int();
693 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
695 const CWalletTx& wtx = (*it).second;
696 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
699 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
700 if (txout.scriptPubKey == scriptPubKey)
701 if (wtx.GetDepthInMainChain() >= nMinDepth)
702 nAmount += txout.nValue;
705 return ValueFromAmount(nAmount);
709 void GetAccountAddresses(string strAccount, set<CBitcoinAddress>& setAddress)
711 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
713 const CBitcoinAddress& address = item.first;
714 const string& strName = item.second;
715 if (strName == strAccount)
716 setAddress.insert(address);
721 Value getreceivedbyaccount(const Array& params, bool fHelp)
723 if (fHelp || params.size() < 1 || params.size() > 2)
725 "getreceivedbyaccount <account> [minconf=1]\n"
726 "Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.");
728 // Minimum confirmations
730 if (params.size() > 1)
731 nMinDepth = params[1].get_int();
733 // Get the set of pub keys assigned to account
734 string strAccount = AccountFromValue(params[0]);
735 set<CBitcoinAddress> setAddress;
736 GetAccountAddresses(strAccount, setAddress);
740 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
742 const CWalletTx& wtx = (*it).second;
743 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
746 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
748 CBitcoinAddress address;
749 if (ExtractAddress(txout.scriptPubKey, address) && pwalletMain->HaveKey(address) && setAddress.count(address))
750 if (wtx.GetDepthInMainChain() >= nMinDepth)
751 nAmount += txout.nValue;
755 return (double)nAmount / (double)COIN;
759 int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth)
763 // Tally wallet transactions
764 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
766 const CWalletTx& wtx = (*it).second;
770 int64 nGenerated, nReceived, nSent, nFee;
771 wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee);
773 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
774 nBalance += nReceived;
775 nBalance += nGenerated - nSent - nFee;
778 // Tally internal accounting entries
779 nBalance += walletdb.GetAccountCreditDebit(strAccount);
784 int64 GetAccountBalance(const string& strAccount, int nMinDepth)
786 CWalletDB walletdb(pwalletMain->strWalletFile);
787 return GetAccountBalance(walletdb, strAccount, nMinDepth);
791 Value getbalance(const Array& params, bool fHelp)
793 if (fHelp || params.size() > 2)
795 "getbalance [account] [minconf=1]\n"
796 "If [account] is not specified, returns the server's total available balance.\n"
797 "If [account] is specified, returns the balance in the account.");
799 if (params.size() == 0)
800 return ValueFromAmount(pwalletMain->GetBalance());
803 if (params.size() > 1)
804 nMinDepth = params[1].get_int();
806 if (params[0].get_str() == "*") {
807 // Calculate total balance a different way from GetBalance()
808 // (GetBalance() sums up all unspent TxOuts)
809 // getbalance and getbalance '*' should always return the same number.
811 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
813 const CWalletTx& wtx = (*it).second;
817 int64 allGeneratedImmature, allGeneratedMature, allFee;
818 allGeneratedImmature = allGeneratedMature = allFee = 0;
819 string strSentAccount;
820 list<pair<CBitcoinAddress, int64> > listReceived;
821 list<pair<CBitcoinAddress, int64> > listSent;
822 wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
823 if (wtx.GetDepthInMainChain() >= nMinDepth)
825 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listReceived)
826 nBalance += r.second;
828 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listSent)
829 nBalance -= r.second;
831 nBalance += allGeneratedMature;
833 return ValueFromAmount(nBalance);
836 string strAccount = AccountFromValue(params[0]);
838 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
840 return ValueFromAmount(nBalance);
844 Value movecmd(const Array& params, bool fHelp)
846 if (fHelp || params.size() < 3 || params.size() > 5)
848 "move <fromaccount> <toaccount> <amount> [minconf=1] [comment]\n"
849 "Move from one account in your wallet to another.");
851 string strFrom = AccountFromValue(params[0]);
852 string strTo = AccountFromValue(params[1]);
853 int64 nAmount = AmountFromValue(params[2]);
854 if (params.size() > 3)
855 // unused parameter, used to be nMinDepth, keep type-checking it though
856 (void)params[3].get_int();
858 if (params.size() > 4)
859 strComment = params[4].get_str();
861 CWalletDB walletdb(pwalletMain->strWalletFile);
862 if (!walletdb.TxnBegin())
863 throw JSONRPCError(-20, "database error");
865 int64 nNow = GetAdjustedTime();
868 CAccountingEntry debit;
869 debit.strAccount = strFrom;
870 debit.nCreditDebit = -nAmount;
872 debit.strOtherAccount = strTo;
873 debit.strComment = strComment;
874 walletdb.WriteAccountingEntry(debit);
877 CAccountingEntry credit;
878 credit.strAccount = strTo;
879 credit.nCreditDebit = nAmount;
881 credit.strOtherAccount = strFrom;
882 credit.strComment = strComment;
883 walletdb.WriteAccountingEntry(credit);
885 if (!walletdb.TxnCommit())
886 throw JSONRPCError(-20, "database error");
892 Value sendfrom(const Array& params, bool fHelp)
894 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
896 "sendfrom <fromaccount> <toppcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
897 "<amount> is a real and is rounded to the nearest 0.000001\n"
898 "requires wallet passphrase to be set with walletpassphrase first");
899 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
901 "sendfrom <fromaccount> <toppcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
902 "<amount> is a real and is rounded to the nearest 0.000001");
904 string strAccount = AccountFromValue(params[0]);
905 CBitcoinAddress address(params[1].get_str());
906 if (!address.IsValid())
907 throw JSONRPCError(-5, "Invalid ppcoin address");
908 int64 nAmount = AmountFromValue(params[2]);
909 if (nAmount < MIN_TXOUT_AMOUNT)
910 throw JSONRPCError(-101, "Send amount too small");
912 if (params.size() > 3)
913 nMinDepth = params[3].get_int();
916 wtx.strFromAccount = strAccount;
917 if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
918 wtx.mapValue["comment"] = params[4].get_str();
919 if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
920 wtx.mapValue["to"] = params[5].get_str();
922 if (pwalletMain->IsLocked())
923 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
926 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
927 if (nAmount > nBalance)
928 throw JSONRPCError(-6, "Account has insufficient funds");
931 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
933 throw JSONRPCError(-4, strError);
935 return wtx.GetHash().GetHex();
939 Value sendmany(const Array& params, bool fHelp)
941 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
943 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
944 "amounts are double-precision floating point numbers\n"
945 "requires wallet passphrase to be set with walletpassphrase first");
946 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
948 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
949 "amounts are double-precision floating point numbers");
951 string strAccount = AccountFromValue(params[0]);
952 Object sendTo = params[1].get_obj();
954 if (params.size() > 2)
955 nMinDepth = params[2].get_int();
958 wtx.strFromAccount = strAccount;
959 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
960 wtx.mapValue["comment"] = params[3].get_str();
962 set<CBitcoinAddress> setAddress;
963 vector<pair<CScript, int64> > vecSend;
965 int64 totalAmount = 0;
966 BOOST_FOREACH(const Pair& s, sendTo)
968 CBitcoinAddress address(s.name_);
969 if (!address.IsValid())
970 throw JSONRPCError(-5, string("Invalid ppcoin address:")+s.name_);
972 if (setAddress.count(address))
973 throw JSONRPCError(-8, string("Invalid parameter, duplicated address: ")+s.name_);
974 setAddress.insert(address);
976 CScript scriptPubKey;
977 scriptPubKey.SetBitcoinAddress(address);
978 int64 nAmount = AmountFromValue(s.value_);
979 if (nAmount < MIN_TXOUT_AMOUNT)
980 throw JSONRPCError(-101, "Send amount too small");
981 totalAmount += nAmount;
983 vecSend.push_back(make_pair(scriptPubKey, nAmount));
986 if (pwalletMain->IsLocked())
987 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
988 if (fWalletUnlockMintOnly)
989 throw JSONRPCError(-13, "Error: Wallet unlocked for block minting only.");
992 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
993 if (totalAmount > nBalance)
994 throw JSONRPCError(-6, "Account has insufficient funds");
997 CReserveKey keyChange(pwalletMain);
998 int64 nFeeRequired = 0;
999 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
1002 if (totalAmount + nFeeRequired > pwalletMain->GetBalance())
1003 throw JSONRPCError(-6, "Insufficient funds");
1004 throw JSONRPCError(-4, "Transaction creation failed");
1006 if (!pwalletMain->CommitTransaction(wtx, keyChange))
1007 throw JSONRPCError(-4, "Transaction commit failed");
1009 return wtx.GetHash().GetHex();
1012 Value addmultisigaddress(const Array& params, bool fHelp)
1014 if (fHelp || params.size() < 2 || params.size() > 3)
1016 string msg = "addmultisigaddress <nrequired> <'[\"key\",\"key\"]'> [account]\n"
1017 "Add a nrequired-to-sign multisignature address to the wallet\"\n"
1018 "each key is a bitcoin address or hex-encoded public key\n"
1019 "If [account] is specified, assign address to [account].";
1020 throw runtime_error(msg);
1023 int nRequired = params[0].get_int();
1024 const Array& keys = params[1].get_array();
1026 if (params.size() > 2)
1027 strAccount = AccountFromValue(params[2]);
1029 // Gather public keys
1031 throw runtime_error("a multisignature address must require at least one key to redeem");
1032 if ((int)keys.size() < nRequired)
1033 throw runtime_error(
1034 strprintf("not enough keys supplied "
1035 "(got %d keys, but need at least %d to redeem)", keys.size(), nRequired));
1036 std::vector<CKey> pubkeys;
1037 pubkeys.resize(keys.size());
1038 for (unsigned int i = 0; i < keys.size(); i++)
1040 const std::string& ks = keys[i].get_str();
1042 // Case 1: bitcoin address and we have full public key:
1043 CBitcoinAddress address(ks);
1044 if (address.IsValid())
1046 if (address.IsScript())
1047 throw runtime_error(
1048 strprintf("%s is a pay-to-script address",ks.c_str()));
1049 std::vector<unsigned char> vchPubKey;
1050 if (!pwalletMain->GetPubKey(address, vchPubKey))
1051 throw runtime_error(
1052 strprintf("no full public key for address %s",ks.c_str()));
1053 if (vchPubKey.empty() || !pubkeys[i].SetPubKey(vchPubKey))
1054 throw runtime_error(" Invalid public key: "+ks);
1057 // Case 2: hex public key
1060 vector<unsigned char> vchPubKey = ParseHex(ks);
1061 if (vchPubKey.empty() || !pubkeys[i].SetPubKey(vchPubKey))
1062 throw runtime_error(" Invalid public key: "+ks);
1066 throw runtime_error(" Invalid public key: "+ks);
1070 // Construct using pay-to-script-hash:
1072 inner.SetMultisig(nRequired, pubkeys);
1074 uint160 scriptHash = Hash160(inner);
1075 CScript scriptPubKey;
1076 scriptPubKey.SetPayToScriptHash(inner);
1077 pwalletMain->AddCScript(inner);
1078 CBitcoinAddress address;
1079 address.SetScriptHash160(scriptHash);
1081 pwalletMain->SetAddressBookName(address, strAccount);
1082 return address.ToString();
1093 nConf = std::numeric_limits<int>::max();
1097 Value ListReceived(const Array& params, bool fByAccounts)
1099 // Minimum confirmations
1101 if (params.size() > 0)
1102 nMinDepth = params[0].get_int();
1104 // Whether to include empty accounts
1105 bool fIncludeEmpty = false;
1106 if (params.size() > 1)
1107 fIncludeEmpty = params[1].get_bool();
1110 map<CBitcoinAddress, tallyitem> mapTally;
1111 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1113 const CWalletTx& wtx = (*it).second;
1115 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
1118 int nDepth = wtx.GetDepthInMainChain();
1119 if (nDepth < nMinDepth)
1122 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
1124 CBitcoinAddress address;
1125 if (!ExtractAddress(txout.scriptPubKey, address) || !pwalletMain->HaveKey(address) || !address.IsValid())
1128 tallyitem& item = mapTally[address];
1129 item.nAmount += txout.nValue;
1130 item.nConf = min(item.nConf, nDepth);
1136 map<string, tallyitem> mapAccountTally;
1137 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
1139 const CBitcoinAddress& address = item.first;
1140 const string& strAccount = item.second;
1141 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
1142 if (it == mapTally.end() && !fIncludeEmpty)
1146 int nConf = std::numeric_limits<int>::max();
1147 if (it != mapTally.end())
1149 nAmount = (*it).second.nAmount;
1150 nConf = (*it).second.nConf;
1155 tallyitem& item = mapAccountTally[strAccount];
1156 item.nAmount += nAmount;
1157 item.nConf = min(item.nConf, nConf);
1162 obj.push_back(Pair("address", address.ToString()));
1163 obj.push_back(Pair("account", strAccount));
1164 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1165 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1172 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
1174 int64 nAmount = (*it).second.nAmount;
1175 int nConf = (*it).second.nConf;
1177 obj.push_back(Pair("account", (*it).first));
1178 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1179 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1187 Value listreceivedbyaddress(const Array& params, bool fHelp)
1189 if (fHelp || params.size() > 2)
1190 throw runtime_error(
1191 "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
1192 "[minconf] is the minimum number of confirmations before payments are included.\n"
1193 "[includeempty] whether to include addresses that haven't received any payments.\n"
1194 "Returns an array of objects containing:\n"
1195 " \"address\" : receiving address\n"
1196 " \"account\" : the account of the receiving address\n"
1197 " \"amount\" : total amount received by the address\n"
1198 " \"confirmations\" : number of confirmations of the most recent transaction included");
1200 return ListReceived(params, false);
1203 Value listreceivedbyaccount(const Array& params, bool fHelp)
1205 if (fHelp || params.size() > 2)
1206 throw runtime_error(
1207 "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
1208 "[minconf] is the minimum number of confirmations before payments are included.\n"
1209 "[includeempty] whether to include accounts that haven't received any payments.\n"
1210 "Returns an array of objects containing:\n"
1211 " \"account\" : the account of the receiving addresses\n"
1212 " \"amount\" : total amount received by addresses with this account\n"
1213 " \"confirmations\" : number of confirmations of the most recent transaction included");
1215 return ListReceived(params, true);
1218 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret)
1220 int64 nGeneratedImmature, nGeneratedMature, nFee;
1221 string strSentAccount;
1222 list<pair<CBitcoinAddress, int64> > listReceived;
1223 list<pair<CBitcoinAddress, int64> > listSent;
1225 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1227 bool fAllAccounts = (strAccount == string("*"));
1229 // Generated blocks assigned to account ""
1230 if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == ""))
1233 entry.push_back(Pair("account", string("")));
1234 if (nGeneratedImmature)
1236 entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
1237 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
1241 entry.push_back(Pair("category", "generate"));
1242 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
1245 WalletTxToJSON(wtx, entry);
1246 ret.push_back(entry);
1250 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1252 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1255 entry.push_back(Pair("account", strSentAccount));
1256 entry.push_back(Pair("address", s.first.ToString()));
1257 entry.push_back(Pair("category", "send"));
1258 entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1259 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1261 WalletTxToJSON(wtx, entry);
1262 ret.push_back(entry);
1267 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1269 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1272 if (pwalletMain->mapAddressBook.count(r.first))
1273 account = pwalletMain->mapAddressBook[r.first];
1274 if (fAllAccounts || (account == strAccount))
1277 entry.push_back(Pair("account", account));
1278 entry.push_back(Pair("address", r.first.ToString()));
1279 entry.push_back(Pair("category", "receive"));
1280 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1282 WalletTxToJSON(wtx, entry);
1283 ret.push_back(entry);
1289 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1291 bool fAllAccounts = (strAccount == string("*"));
1293 if (fAllAccounts || acentry.strAccount == strAccount)
1296 entry.push_back(Pair("account", acentry.strAccount));
1297 entry.push_back(Pair("category", "move"));
1298 entry.push_back(Pair("time", (boost::int64_t)acentry.nTime));
1299 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1300 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1301 entry.push_back(Pair("comment", acentry.strComment));
1302 ret.push_back(entry);
1306 Value listtransactions(const Array& params, bool fHelp)
1308 if (fHelp || params.size() > 3)
1309 throw runtime_error(
1310 "listtransactions [account] [count=10] [from=0]\n"
1311 "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1313 string strAccount = "*";
1314 if (params.size() > 0)
1315 strAccount = params[0].get_str();
1317 if (params.size() > 1)
1318 nCount = params[1].get_int();
1320 if (params.size() > 2)
1321 nFrom = params[2].get_int();
1324 throw JSONRPCError(-8, "Negative count");
1326 throw JSONRPCError(-8, "Negative from");
1329 CWalletDB walletdb(pwalletMain->strWalletFile);
1331 // First: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap.
1332 typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
1333 typedef multimap<int64, TxPair > TxItems;
1336 // Note: maintaining indices in the database of (account,time) --> txid and (account, time) --> acentry
1337 // would make this much faster for applications that do this a lot.
1338 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1340 CWalletTx* wtx = &((*it).second);
1341 txByTime.insert(make_pair(wtx->GetTxTime(), TxPair(wtx, (CAccountingEntry*)0)));
1343 list<CAccountingEntry> acentries;
1344 walletdb.ListAccountCreditDebit(strAccount, acentries);
1345 BOOST_FOREACH(CAccountingEntry& entry, acentries)
1347 txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
1350 // iterate backwards until we have nCount items to return:
1351 for (TxItems::reverse_iterator it = txByTime.rbegin(); it != txByTime.rend(); ++it)
1353 CWalletTx *const pwtx = (*it).second.first;
1355 ListTransactions(*pwtx, strAccount, 0, true, ret);
1356 CAccountingEntry *const pacentry = (*it).second.second;
1358 AcentryToJSON(*pacentry, strAccount, ret);
1360 if (ret.size() >= (nCount+nFrom)) break;
1362 // ret is newest to oldest
1364 if (nFrom > (int)ret.size())
1366 if ((nFrom + nCount) > (int)ret.size())
1367 nCount = ret.size() - nFrom;
1368 Array::iterator first = ret.begin();
1369 std::advance(first, nFrom);
1370 Array::iterator last = ret.begin();
1371 std::advance(last, nFrom+nCount);
1373 if (last != ret.end()) ret.erase(last, ret.end());
1374 if (first != ret.begin()) ret.erase(ret.begin(), first);
1376 std::reverse(ret.begin(), ret.end()); // Return oldest to newest
1381 Value listaccounts(const Array& params, bool fHelp)
1383 if (fHelp || params.size() > 1)
1384 throw runtime_error(
1385 "listaccounts [minconf=1]\n"
1386 "Returns Object that has account names as keys, account balances as values.");
1389 if (params.size() > 0)
1390 nMinDepth = params[0].get_int();
1392 map<string, int64> mapAccountBalances;
1393 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& entry, pwalletMain->mapAddressBook) {
1394 if (pwalletMain->HaveKey(entry.first)) // This address belongs to me
1395 mapAccountBalances[entry.second] = 0;
1398 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1400 const CWalletTx& wtx = (*it).second;
1401 int64 nGeneratedImmature, nGeneratedMature, nFee;
1402 string strSentAccount;
1403 list<pair<CBitcoinAddress, int64> > listReceived;
1404 list<pair<CBitcoinAddress, int64> > listSent;
1405 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1406 mapAccountBalances[strSentAccount] -= nFee;
1407 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1408 mapAccountBalances[strSentAccount] -= s.second;
1409 if (wtx.GetDepthInMainChain() >= nMinDepth)
1411 mapAccountBalances[""] += nGeneratedMature;
1412 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1413 if (pwalletMain->mapAddressBook.count(r.first))
1414 mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1416 mapAccountBalances[""] += r.second;
1420 list<CAccountingEntry> acentries;
1421 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1422 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1423 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1426 BOOST_FOREACH(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) {
1427 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1432 Value listsinceblock(const Array& params, bool fHelp)
1435 throw runtime_error(
1436 "listsinceblock [blockhash] [target-confirmations]\n"
1437 "Get all transactions in blocks since block [blockhash], or all transactions if omitted");
1439 CBlockIndex *pindex = NULL;
1440 int target_confirms = 1;
1442 if (params.size() > 0)
1444 uint256 blockId = 0;
1446 blockId.SetHex(params[0].get_str());
1447 pindex = CBlockLocator(blockId).GetBlockIndex();
1450 if (params.size() > 1)
1452 target_confirms = params[1].get_int();
1454 if (target_confirms < 1)
1455 throw JSONRPCError(-8, "Invalid parameter");
1458 int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1;
1462 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1464 CWalletTx tx = (*it).second;
1466 if (depth == -1 || tx.GetDepthInMainChain() < depth)
1467 ListTransactions(tx, "*", 0, true, transactions);
1472 if (target_confirms == 1)
1474 lastblock = hashBestChain;
1478 int target_height = pindexBest->nHeight + 1 - target_confirms;
1481 for (block = pindexBest;
1482 block && block->nHeight > target_height;
1483 block = block->pprev) { }
1485 lastblock = block ? block->GetBlockHash() : 0;
1489 ret.push_back(Pair("transactions", transactions));
1490 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1495 Value gettransaction(const Array& params, bool fHelp)
1497 if (fHelp || params.size() != 1)
1498 throw runtime_error(
1499 "gettransaction <txid>\n"
1500 "Get detailed information about <txid>");
1503 hash.SetHex(params[0].get_str());
1507 if (!pwalletMain->mapWallet.count(hash))
1508 throw JSONRPCError(-5, "Invalid or non-wallet transaction id");
1509 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1511 int64 nCredit = wtx.GetCredit();
1512 int64 nDebit = wtx.GetDebit();
1513 int64 nNet = nCredit - nDebit;
1514 int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
1516 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1518 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1520 WalletTxToJSON(pwalletMain->mapWallet[hash], entry);
1523 ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
1524 entry.push_back(Pair("details", details));
1530 Value backupwallet(const Array& params, bool fHelp)
1532 if (fHelp || params.size() != 1)
1533 throw runtime_error(
1534 "backupwallet <destination>\n"
1535 "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1537 string strDest = params[0].get_str();
1538 BackupWallet(*pwalletMain, strDest);
1544 Value keypoolrefill(const Array& params, bool fHelp)
1546 if (pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1547 throw runtime_error(
1549 "Fills the keypool, requires wallet passphrase to be set.");
1550 if (!pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1551 throw runtime_error(
1553 "Fills the keypool.");
1555 if (pwalletMain->IsLocked())
1556 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
1558 pwalletMain->TopUpKeyPool();
1560 if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100))
1561 throw JSONRPCError(-4, "Error refreshing keypool.");
1567 void ThreadTopUpKeyPool(void* parg)
1569 pwalletMain->TopUpKeyPool();
1572 void ThreadCleanWalletPassphrase(void* parg)
1574 int64 nMyWakeTime = GetTimeMillis() + *((int64*)parg) * 1000;
1576 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1578 if (nWalletUnlockTime == 0)
1580 nWalletUnlockTime = nMyWakeTime;
1584 if (nWalletUnlockTime==0)
1586 int64 nToSleep = nWalletUnlockTime - GetTimeMillis();
1590 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1592 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1596 if (nWalletUnlockTime)
1598 nWalletUnlockTime = 0;
1599 pwalletMain->Lock();
1604 if (nWalletUnlockTime < nMyWakeTime)
1605 nWalletUnlockTime = nMyWakeTime;
1608 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1610 delete (int64*)parg;
1613 Value walletpassphrase(const Array& params, bool fHelp)
1615 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 3))
1616 throw runtime_error(
1617 "walletpassphrase <passphrase> <timeout> [mintonly]\n"
1618 "Stores the wallet decryption key in memory for <timeout> seconds.\n"
1619 "mintonly is optional true/false allowing only block minting.");
1622 if (!pwalletMain->IsCrypted())
1623 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1625 if (!pwalletMain->IsLocked())
1626 throw JSONRPCError(-17, "Error: Wallet is already unlocked, use walletlock first if need to change unlock settings.");
1628 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1629 SecureString strWalletPass;
1630 strWalletPass.reserve(100);
1631 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1632 // Alternately, find a way to make params[0] mlock()'d to begin with.
1633 strWalletPass = params[0].get_str().c_str();
1635 if (strWalletPass.length() > 0)
1637 if (!pwalletMain->Unlock(strWalletPass))
1638 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1641 throw runtime_error(
1642 "walletpassphrase <passphrase> <timeout>\n"
1643 "Stores the wallet decryption key in memory for <timeout> seconds.");
1645 CreateThread(ThreadTopUpKeyPool, NULL);
1646 int64* pnSleepTime = new int64(params[1].get_int64());
1647 CreateThread(ThreadCleanWalletPassphrase, pnSleepTime);
1649 // ppcoin: if user OS account compromised prevent trivial sendmoney commands
1650 if (params.size() > 2)
1651 fWalletUnlockMintOnly = params[2].get_bool();
1653 fWalletUnlockMintOnly = false;
1659 Value walletpassphrasechange(const Array& params, bool fHelp)
1661 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1662 throw runtime_error(
1663 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1664 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1667 if (!pwalletMain->IsCrypted())
1668 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1670 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1671 // Alternately, find a way to make params[0] mlock()'d to begin with.
1672 SecureString strOldWalletPass;
1673 strOldWalletPass.reserve(100);
1674 strOldWalletPass = params[0].get_str().c_str();
1676 SecureString strNewWalletPass;
1677 strNewWalletPass.reserve(100);
1678 strNewWalletPass = params[1].get_str().c_str();
1680 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1681 throw runtime_error(
1682 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1683 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1685 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1686 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1692 Value walletlock(const Array& params, bool fHelp)
1694 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1695 throw runtime_error(
1697 "Removes the wallet encryption key from memory, locking the wallet.\n"
1698 "After calling this method, you will need to call walletpassphrase again\n"
1699 "before being able to call any methods which require the wallet to be unlocked.");
1702 if (!pwalletMain->IsCrypted())
1703 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called.");
1706 LOCK(cs_nWalletUnlockTime);
1707 pwalletMain->Lock();
1708 nWalletUnlockTime = 0;
1715 Value encryptwallet(const Array& params, bool fHelp)
1717 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1718 throw runtime_error(
1719 "encryptwallet <passphrase>\n"
1720 "Encrypts the wallet with <passphrase>.");
1723 if (pwalletMain->IsCrypted())
1724 throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
1726 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1727 // Alternately, find a way to make params[0] mlock()'d to begin with.
1728 SecureString strWalletPass;
1729 strWalletPass.reserve(100);
1730 strWalletPass = params[0].get_str().c_str();
1732 if (strWalletPass.length() < 1)
1733 throw runtime_error(
1734 "encryptwallet <passphrase>\n"
1735 "Encrypts the wallet with <passphrase>.");
1737 if (!pwalletMain->EncryptWallet(strWalletPass))
1738 throw JSONRPCError(-16, "Error: Failed to encrypt the wallet.");
1740 // BDB seems to have a bad habit of writing old data into
1741 // slack space in .dat files; that is bad if the old data is
1742 // unencrypted private keys. So:
1744 return "wallet encrypted; ppcoin server stopping, restart to run with encrypted wallet";
1748 Value validateaddress(const Array& params, bool fHelp)
1750 if (fHelp || params.size() != 1)
1751 throw runtime_error(
1752 "validateaddress <ppcoinaddress>\n"
1753 "Return information about <ppcoinaddress>.");
1755 CBitcoinAddress address(params[0].get_str());
1756 bool isValid = address.IsValid();
1759 ret.push_back(Pair("isvalid", isValid));
1762 // Call Hash160ToAddress() so we always return current ADDRESSVERSION
1763 // version of the address:
1764 string currentAddress = address.ToString();
1765 ret.push_back(Pair("address", currentAddress));
1766 if (pwalletMain->HaveKey(address))
1768 ret.push_back(Pair("ismine", true));
1769 std::vector<unsigned char> vchPubKey;
1770 pwalletMain->GetPubKey(address, vchPubKey);
1771 ret.push_back(Pair("pubkey", HexStr(vchPubKey)));
1773 key.SetPubKey(vchPubKey);
1774 ret.push_back(Pair("iscompressed", key.IsCompressed()));
1776 else if (pwalletMain->HaveCScript(address.GetHash160()))
1778 ret.push_back(Pair("isscript", true));
1780 pwalletMain->GetCScript(address.GetHash160(), subscript);
1781 ret.push_back(Pair("ismine", ::IsMine(*pwalletMain, subscript)));
1782 std::vector<CBitcoinAddress> addresses;
1783 txnouttype whichType;
1785 ExtractAddresses(subscript, whichType, addresses, nRequired);
1786 ret.push_back(Pair("script", GetTxnOutputType(whichType)));
1788 BOOST_FOREACH(const CBitcoinAddress& addr, addresses)
1789 a.push_back(addr.ToString());
1790 ret.push_back(Pair("addresses", a));
1791 if (whichType == TX_MULTISIG)
1792 ret.push_back(Pair("sigsrequired", nRequired));
1795 ret.push_back(Pair("ismine", false));
1796 if (pwalletMain->mapAddressBook.count(address))
1797 ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
1802 Value getwork(const Array& params, bool fHelp)
1804 if (fHelp || params.size() > 1)
1805 throw runtime_error(
1807 "If [data] is not specified, returns formatted hash data to work on:\n"
1808 " \"midstate\" : precomputed hash state after hashing the first half of the data (DEPRECATED)\n" // deprecated
1809 " \"data\" : block data\n"
1810 " \"hash1\" : formatted hash buffer for second hash (DEPRECATED)\n" // deprecated
1811 " \"target\" : little endian hash target\n"
1812 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1815 throw JSONRPCError(-9, "PPCoin is not connected!");
1817 if (IsInitialBlockDownload())
1818 throw JSONRPCError(-10, "PPCoin is downloading blocks...");
1820 typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
1821 static mapNewBlock_t mapNewBlock;
1822 static vector<CBlock*> vNewBlock;
1823 static CReserveKey reservekey(pwalletMain);
1825 if (params.size() == 0)
1828 static unsigned int nTransactionsUpdatedLast;
1829 static CBlockIndex* pindexPrev;
1830 static int64 nStart;
1831 static CBlock* pblock;
1832 if (pindexPrev != pindexBest ||
1833 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
1835 if (pindexPrev != pindexBest)
1837 // Deallocate old blocks since they're obsolete now
1838 mapNewBlock.clear();
1839 BOOST_FOREACH(CBlock* pblock, vNewBlock)
1843 nTransactionsUpdatedLast = nTransactionsUpdated;
1844 pindexPrev = pindexBest;
1848 pblock = CreateNewBlock(pwalletMain);
1850 throw JSONRPCError(-7, "Out of memory");
1851 vNewBlock.push_back(pblock);
1855 pblock->UpdateTime(pindexPrev);
1858 // Update nExtraNonce
1859 static unsigned int nExtraNonce = 0;
1860 IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
1863 mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
1865 // Prebuild hash buffers
1869 FormatHashBuffers(pblock, pmidstate, pdata, phash1);
1871 uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
1874 result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate)))); // deprecated
1875 result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata))));
1876 result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1)))); // deprecated
1877 result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
1883 vector<unsigned char> vchData = ParseHex(params[0].get_str());
1884 if (vchData.size() != 128)
1885 throw JSONRPCError(-8, "Invalid parameter");
1886 CBlock* pdata = (CBlock*)&vchData[0];
1889 for (int i = 0; i < 128/4; i++)
1890 ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]);
1893 if (!mapNewBlock.count(pdata->hashMerkleRoot))
1895 CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
1897 pblock->nTime = pdata->nTime;
1898 pblock->nNonce = pdata->nNonce;
1899 pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
1900 pblock->hashMerkleRoot = pblock->BuildMerkleTree();
1901 if (!pblock->SignBlock(*pwalletMain))
1902 throw JSONRPCError(-100, "Unable to sign block, wallet locked?");
1904 return CheckWork(pblock, *pwalletMain, reservekey);
1909 Value getmemorypool(const Array& params, bool fHelp)
1911 if (fHelp || params.size() > 1)
1912 throw runtime_error(
1913 "getmemorypool [data]\n"
1914 "If [data] is not specified, returns data needed to construct a block to work on:\n"
1915 " \"version\" : block version\n"
1916 " \"previousblockhash\" : hash of current highest block\n"
1917 " \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
1918 " \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
1919 " \"coinbaseflags\" : data that should be included in coinbase so support for new features can be judged\n"
1920 " \"time\" : timestamp appropriate for next block\n"
1921 " \"mintime\" : minimum timestamp appropriate for next block\n"
1922 " \"curtime\" : current timestamp\n"
1923 " \"bits\" : compressed target of next block\n"
1924 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1926 if (params.size() == 0)
1929 throw JSONRPCError(-9, "PPCoin is not connected!");
1931 if (IsInitialBlockDownload())
1932 throw JSONRPCError(-10, "PPCoin is downloading blocks...");
1934 static CReserveKey reservekey(pwalletMain);
1937 static unsigned int nTransactionsUpdatedLast;
1938 static CBlockIndex* pindexPrev;
1939 static int64 nStart;
1940 static CBlock* pblock;
1941 if (pindexPrev != pindexBest ||
1942 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5))
1944 nTransactionsUpdatedLast = nTransactionsUpdated;
1945 pindexPrev = pindexBest;
1951 pblock = CreateNewBlock(pwalletMain);
1953 throw JSONRPCError(-7, "Out of memory");
1957 pblock->UpdateTime(pindexPrev);
1961 BOOST_FOREACH(CTransaction tx, pblock->vtx) {
1962 if(tx.IsCoinBase() || tx.IsCoinStake())
1965 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
1968 transactions.push_back(HexStr(ssTx.begin(), ssTx.end()));
1972 result.push_back(Pair("version", pblock->nVersion));
1973 result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
1974 result.push_back(Pair("transactions", transactions));
1975 result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
1976 result.push_back(Pair("coinbaseflags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end())));
1977 result.push_back(Pair("time", (int64_t)pblock->nTime));
1978 result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1));
1979 result.push_back(Pair("curtime", (int64_t)GetAdjustedTime()));
1980 result.push_back(Pair("bits", HexBits(pblock->nBits)));
1987 CDataStream ssBlock(ParseHex(params[0].get_str()), SER_NETWORK, PROTOCOL_VERSION);
1991 return ProcessBlock(NULL, &pblock);
1995 Value getblockhash(const Array& params, bool fHelp)
1997 if (fHelp || params.size() != 1)
1998 throw runtime_error(
1999 "getblockhash <index>\n"
2000 "Returns hash of block in best-block-chain at <index>.");
2002 int nHeight = params[0].get_int();
2003 if (nHeight < 0 || nHeight > nBestHeight)
2004 throw runtime_error("Block number out of range.");
2007 CBlockIndex* pblockindex = mapBlockIndex[hashBestChain];
2008 while (pblockindex->nHeight > nHeight)
2009 pblockindex = pblockindex->pprev;
2010 return pblockindex->phashBlock->GetHex();
2013 Value getblock(const Array& params, bool fHelp)
2015 if (fHelp || params.size() < 1 || params.size() > 2)
2016 throw runtime_error(
2017 "getblock <hash> [txinfo]\n"
2018 "txinfo optional to print more detailed tx info\n"
2019 "Returns details of a block with given block-hash.");
2021 std::string strHash = params[0].get_str();
2022 uint256 hash(strHash);
2024 if (mapBlockIndex.count(hash) == 0)
2025 throw JSONRPCError(-5, "Block not found");
2028 CBlockIndex* pblockindex = mapBlockIndex[hash];
2029 block.ReadFromDisk(pblockindex, true);
2031 return blockToJSON(block, pblockindex, params.size() > 1 ? params[1].get_bool() : false);
2035 // ppcoin: get information of sync-checkpoint
2036 Value getcheckpoint(const Array& params, bool fHelp)
2038 if (fHelp || params.size() != 0)
2039 throw runtime_error(
2041 "Show info of synchronized checkpoint.\n");
2044 CBlockIndex* pindexCheckpoint;
2046 result.push_back(Pair("synccheckpoint", Checkpoints::hashSyncCheckpoint.ToString().c_str()));
2047 pindexCheckpoint = mapBlockIndex[Checkpoints::hashSyncCheckpoint];
2048 result.push_back(Pair("height", pindexCheckpoint->nHeight));
2049 result.push_back(Pair("timestamp", DateTimeStrFormat(pindexCheckpoint->GetBlockTime()).c_str()));
2050 if (mapArgs.count("-checkpointkey"))
2051 result.push_back(Pair("checkpointmaster", true));
2057 // ppcoin: reserve balance from being staked for network protection
2058 Value reservebalance(const Array& params, bool fHelp)
2060 if (fHelp || params.size() > 2)
2061 throw runtime_error(
2062 "reservebalance [<reserve> [amount]]\n"
2063 "<reserve> is true or false to turn balance reserve on or off.\n"
2064 "<amount> is a real and rounded to cent.\n"
2065 "Set reserve amount not participating in network protection.\n"
2066 "If no parameters provided current setting is printed.\n");
2068 if (params.size() > 0)
2070 bool fReserve = params[0].get_bool();
2073 if (params.size() == 1)
2074 throw runtime_error("must provide amount to reserve balance.\n");
2075 int64 nAmount = AmountFromValue(params[1]);
2076 nAmount = (nAmount / CENT) * CENT; // round to cent
2078 throw runtime_error("amount cannot be negative.\n");
2079 mapArgs["-reservebalance"] = FormatMoney(nAmount).c_str();
2083 if (params.size() > 1)
2084 throw runtime_error("cannot specify amount to turn off reserve.\n");
2085 mapArgs["-reservebalance"] = "0";
2090 int64 nReserveBalance = 0;
2091 if (mapArgs.count("-reservebalance") && !ParseMoney(mapArgs["-reservebalance"], nReserveBalance))
2092 throw runtime_error("invalid reserve balance amount\n");
2093 result.push_back(Pair("reserve", (nReserveBalance > 0)));
2094 result.push_back(Pair("amount", ValueFromAmount(nReserveBalance)));
2099 // ppcoin: check wallet integrity
2100 Value checkwallet(const Array& params, bool fHelp)
2102 if (fHelp || params.size() > 0)
2103 throw runtime_error(
2105 "Check wallet for integrity.\n");
2108 int64 nBalanceInQuestion;
2110 if (pwalletMain->CheckSpentCoins(nMismatchSpent, nBalanceInQuestion))
2111 result.push_back(Pair("wallet check passed", true));
2114 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
2115 result.push_back(Pair("amount in question", ValueFromAmount(nBalanceInQuestion)));
2121 // ppcoin: repair wallet
2122 Value repairwallet(const Array& params, bool fHelp)
2124 if (fHelp || params.size() > 0)
2125 throw runtime_error(
2127 "Repair wallet if checkwallet reports any problem.\n");
2130 int64 nBalanceInQuestion;
2131 pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion);
2133 if (nMismatchSpent == 0)
2134 result.push_back(Pair("wallet check passed", true));
2137 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
2138 result.push_back(Pair("amount affected by repair", ValueFromAmount(nBalanceInQuestion)));
2143 // ppcoin: make a public-private key pair
2144 Value makekeypair(const Array& params, bool fHelp)
2146 if (fHelp || params.size() > 1)
2147 throw runtime_error(
2148 "makekeypair [prefix]\n"
2149 "Make a public/private key pair.\n"
2150 "[prefix] is optional preferred prefix for the public key.\n");
2152 string strPrefix = "";
2153 if (params.size() > 0)
2154 strPrefix = params[0].get_str();
2160 key.MakeNewKey(false);
2162 } while (nCount < 10000 && strPrefix != HexStr(key.GetPubKey()).substr(0, strPrefix.size()));
2164 if (strPrefix != HexStr(key.GetPubKey()).substr(0, strPrefix.size()))
2167 CPrivKey vchPrivKey = key.GetPrivKey();
2169 result.push_back(Pair("PrivateKey", HexStr<CPrivKey::iterator>(vchPrivKey.begin(), vchPrivKey.end())));
2170 result.push_back(Pair("PublicKey", HexStr(key.GetPubKey())));
2174 extern CCriticalSection cs_mapAlerts;
2175 extern map<uint256, CAlert> mapAlerts;
2177 // ppcoin: send alert.
2178 // There is a known deadlock situation with ThreadMessageHandler
2179 // ThreadMessageHandler: holds cs_vSend and acquiring cs_main in SendMessages()
2180 // ThreadRPCServer: holds cs_main and acquiring cs_vSend in alert.RelayTo()/PushMessage()/BeginMessage()
2181 Value sendalert(const Array& params, bool fHelp)
2183 if (fHelp || params.size() < 6)
2184 throw runtime_error(
2185 "sendalert <message> <privatekey> <minver> <maxver> <priority> <id> [cancelupto]\n"
2186 "<message> is the alert text message\n"
2187 "<privatekey> is hex string of alert master private key\n"
2188 "<minver> is the minimum applicable internal client version\n"
2189 "<maxver> is the maximum applicable internal client version\n"
2190 "<priority> is integer priority number\n"
2191 "<id> is the alert id\n"
2192 "[cancelupto] cancels all alert id's up to this number\n"
2193 "Returns true or false.");
2198 alert.strStatusBar = params[0].get_str();
2199 alert.nMinVer = params[2].get_int();
2200 alert.nMaxVer = params[3].get_int();
2201 alert.nPriority = params[4].get_int();
2202 alert.nID = params[5].get_int();
2203 if (params.size() > 6)
2204 alert.nCancel = params[6].get_int();
2205 alert.nVersion = PROTOCOL_VERSION;
2206 alert.nRelayUntil = GetAdjustedTime() + 365*24*60*60;
2207 alert.nExpiration = GetAdjustedTime() + 365*24*60*60;
2209 CDataStream sMsg(SER_NETWORK, PROTOCOL_VERSION);
2210 sMsg << (CUnsignedAlert)alert;
2211 alert.vchMsg = vector<unsigned char>(sMsg.begin(), sMsg.end());
2213 vector<unsigned char> vchPrivKey = ParseHex(params[1].get_str());
2214 key.SetPrivKey(CPrivKey(vchPrivKey.begin(), vchPrivKey.end())); // if key is not correct openssl may crash
2215 if (!key.Sign(Hash(alert.vchMsg.begin(), alert.vchMsg.end()), alert.vchSig))
2216 throw runtime_error(
2217 "Unable to sign alert, check private key?\n");
2218 if(!alert.ProcessAlert())
2219 throw runtime_error(
2220 "Failed to process alert.\n");
2224 BOOST_FOREACH(CNode* pnode, vNodes)
2225 alert.RelayTo(pnode);
2229 result.push_back(Pair("strStatusBar", alert.strStatusBar));
2230 result.push_back(Pair("nVersion", alert.nVersion));
2231 result.push_back(Pair("nMinVer", alert.nMinVer));
2232 result.push_back(Pair("nMaxVer", alert.nMaxVer));
2233 result.push_back(Pair("nPriority", alert.nPriority));
2234 result.push_back(Pair("nID", alert.nID));
2235 if (alert.nCancel > 0)
2236 result.push_back(Pair("nCancel", alert.nCancel));
2247 static const CRPCCommand vRPCCommands[] =
2248 { // name function safe mode?
2249 // ------------------------ ----------------------- ----------
2250 { "help", &help, true },
2251 { "stop", &stop, true },
2252 { "getblockcount", &getblockcount, true },
2253 { "getblocknumber", &getblocknumber, true },
2254 { "getconnectioncount", &getconnectioncount, true },
2255 { "getdifficulty", &getdifficulty, true },
2256 { "getgenerate", &getgenerate, true },
2257 { "setgenerate", &setgenerate, true },
2258 { "gethashespersec", &gethashespersec, true },
2259 { "getinfo", &getinfo, true },
2260 { "getmininginfo", &getmininginfo, true },
2261 { "getnewaddress", &getnewaddress, true },
2262 { "getaccountaddress", &getaccountaddress, true },
2263 { "setaccount", &setaccount, true },
2264 { "getaccount", &getaccount, false },
2265 { "getaddressesbyaccount", &getaddressesbyaccount, true },
2266 { "sendtoaddress", &sendtoaddress, false },
2267 { "getreceivedbyaddress", &getreceivedbyaddress, false },
2268 { "getreceivedbyaccount", &getreceivedbyaccount, false },
2269 { "listreceivedbyaddress", &listreceivedbyaddress, false },
2270 { "listreceivedbyaccount", &listreceivedbyaccount, false },
2271 { "backupwallet", &backupwallet, true },
2272 { "keypoolrefill", &keypoolrefill, true },
2273 { "walletpassphrase", &walletpassphrase, true },
2274 { "walletpassphrasechange", &walletpassphrasechange, false },
2275 { "walletlock", &walletlock, true },
2276 { "encryptwallet", &encryptwallet, false },
2277 { "validateaddress", &validateaddress, true },
2278 { "getbalance", &getbalance, false },
2279 { "move", &movecmd, false },
2280 { "sendfrom", &sendfrom, false },
2281 { "sendmany", &sendmany, false },
2282 { "addmultisigaddress", &addmultisigaddress, false },
2283 { "getblock", &getblock, false },
2284 { "getblockhash", &getblockhash, false },
2285 { "gettransaction", &gettransaction, false },
2286 { "listtransactions", &listtransactions, false },
2287 { "signmessage", &signmessage, false },
2288 { "verifymessage", &verifymessage, false },
2289 { "getwork", &getwork, true },
2290 { "listaccounts", &listaccounts, false },
2291 { "settxfee", &settxfee, false },
2292 { "getmemorypool", &getmemorypool, true },
2293 { "listsinceblock", &listsinceblock, false },
2294 { "dumpprivkey", &dumpprivkey, false },
2295 { "importprivkey", &importprivkey, false },
2296 { "getcheckpoint", &getcheckpoint, true },
2297 { "reservebalance", &reservebalance, false},
2298 { "checkwallet", &checkwallet, false},
2299 { "repairwallet", &repairwallet, false},
2300 { "makekeypair", &makekeypair, false},
2301 { "sendalert", &sendalert, false},
2304 CRPCTable::CRPCTable()
2307 for (vcidx = 0; vcidx < (sizeof(vRPCCommands) / sizeof(vRPCCommands[0])); vcidx++)
2309 const CRPCCommand *pcmd;
2311 pcmd = &vRPCCommands[vcidx];
2312 mapCommands[pcmd->name] = pcmd;
2316 const CRPCCommand *CRPCTable::operator[](string name) const
2318 map<string, const CRPCCommand*>::const_iterator it = mapCommands.find(name);
2319 if (it == mapCommands.end())
2321 return (*it).second;
2327 // This ain't Apache. We're just using HTTP header for the length field
2328 // and to be compatible with other JSON-RPC implementations.
2331 string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
2334 s << "POST / HTTP/1.1\r\n"
2335 << "User-Agent: ppcoin-json-rpc/" << FormatFullVersion() << "\r\n"
2336 << "Host: 127.0.0.1\r\n"
2337 << "Content-Type: application/json\r\n"
2338 << "Content-Length: " << strMsg.size() << "\r\n"
2339 << "Connection: close\r\n"
2340 << "Accept: application/json\r\n";
2341 BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
2342 s << item.first << ": " << item.second << "\r\n";
2343 s << "\r\n" << strMsg;
2348 string rfc1123Time()
2353 struct tm* now_gmt = gmtime(&now);
2354 string locale(setlocale(LC_TIME, NULL));
2355 setlocale(LC_TIME, "C"); // we want posix (aka "C") weekday/month strings
2356 strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt);
2357 setlocale(LC_TIME, locale.c_str());
2358 return string(buffer);
2361 static string HTTPReply(int nStatus, const string& strMsg)
2364 return strprintf("HTTP/1.0 401 Authorization Required\r\n"
2366 "Server: ppcoin-json-rpc/%s\r\n"
2367 "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
2368 "Content-Type: text/html\r\n"
2369 "Content-Length: 296\r\n"
2371 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
2372 "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
2375 "<TITLE>Error</TITLE>\r\n"
2376 "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
2378 "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
2379 "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
2380 const char *cStatus;
2381 if (nStatus == 200) cStatus = "OK";
2382 else if (nStatus == 400) cStatus = "Bad Request";
2383 else if (nStatus == 403) cStatus = "Forbidden";
2384 else if (nStatus == 404) cStatus = "Not Found";
2385 else if (nStatus == 500) cStatus = "Internal Server Error";
2388 "HTTP/1.1 %d %s\r\n"
2390 "Connection: close\r\n"
2391 "Content-Length: %d\r\n"
2392 "Content-Type: application/json\r\n"
2393 "Server: ppcoin-json-rpc/%s\r\n"
2398 rfc1123Time().c_str(),
2400 FormatFullVersion().c_str(),
2404 int ReadHTTPStatus(std::basic_istream<char>& stream)
2407 getline(stream, str);
2408 vector<string> vWords;
2409 boost::split(vWords, str, boost::is_any_of(" "));
2410 if (vWords.size() < 2)
2412 return atoi(vWords[1].c_str());
2415 int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
2421 std::getline(stream, str);
2422 if (str.empty() || str == "\r")
2424 string::size_type nColon = str.find(":");
2425 if (nColon != string::npos)
2427 string strHeader = str.substr(0, nColon);
2428 boost::trim(strHeader);
2429 boost::to_lower(strHeader);
2430 string strValue = str.substr(nColon+1);
2431 boost::trim(strValue);
2432 mapHeadersRet[strHeader] = strValue;
2433 if (strHeader == "content-length")
2434 nLen = atoi(strValue.c_str());
2440 int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
2442 mapHeadersRet.clear();
2446 int nStatus = ReadHTTPStatus(stream);
2449 int nLen = ReadHTTPHeader(stream, mapHeadersRet);
2450 if (nLen < 0 || nLen > (int)MAX_SIZE)
2456 vector<char> vch(nLen);
2457 stream.read(&vch[0], nLen);
2458 strMessageRet = string(vch.begin(), vch.end());
2464 bool HTTPAuthorized(map<string, string>& mapHeaders)
2466 string strAuth = mapHeaders["authorization"];
2467 if (strAuth.substr(0,6) != "Basic ")
2469 string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
2470 string strUserPass = DecodeBase64(strUserPass64);
2471 return strUserPass == strRPCUserColonPass;
2475 // JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
2476 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
2477 // unspecified (HTTP errors and contents of 'error').
2479 // 1.0 spec: http://json-rpc.org/wiki/specification
2480 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
2481 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
2484 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
2487 request.push_back(Pair("method", strMethod));
2488 request.push_back(Pair("params", params));
2489 request.push_back(Pair("id", id));
2490 return write_string(Value(request), false) + "\n";
2493 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
2496 if (error.type() != null_type)
2497 reply.push_back(Pair("result", Value::null));
2499 reply.push_back(Pair("result", result));
2500 reply.push_back(Pair("error", error));
2501 reply.push_back(Pair("id", id));
2502 return write_string(Value(reply), false) + "\n";
2505 void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
2507 // Send error reply from json-rpc error object
2509 int code = find_value(objError, "code").get_int();
2510 if (code == -32600) nStatus = 400;
2511 else if (code == -32601) nStatus = 404;
2512 string strReply = JSONRPCReply(Value::null, objError, id);
2513 stream << HTTPReply(nStatus, strReply) << std::flush;
2516 bool ClientAllowed(const string& strAddress)
2518 if (strAddress == asio::ip::address_v4::loopback().to_string())
2520 const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
2521 BOOST_FOREACH(string strAllow, vAllow)
2522 if (WildcardMatch(strAddress, strAllow))
2528 // IOStream device that speaks SSL but can also speak non-SSL
2530 class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
2532 SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
2534 fUseSSL = fUseSSLIn;
2535 fNeedHandshake = fUseSSLIn;
2538 void handshake(ssl::stream_base::handshake_type role)
2540 if (!fNeedHandshake) return;
2541 fNeedHandshake = false;
2542 stream.handshake(role);
2544 std::streamsize read(char* s, std::streamsize n)
2546 handshake(ssl::stream_base::server); // HTTPS servers read first
2547 if (fUseSSL) return stream.read_some(asio::buffer(s, n));
2548 return stream.next_layer().read_some(asio::buffer(s, n));
2550 std::streamsize write(const char* s, std::streamsize n)
2552 handshake(ssl::stream_base::client); // HTTPS clients write first
2553 if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
2554 return asio::write(stream.next_layer(), asio::buffer(s, n));
2556 bool connect(const std::string& server, const std::string& port)
2558 ip::tcp::resolver resolver(stream.get_io_service());
2559 ip::tcp::resolver::query query(server.c_str(), port.c_str());
2560 ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
2561 ip::tcp::resolver::iterator end;
2562 boost::system::error_code error = asio::error::host_not_found;
2563 while (error && endpoint_iterator != end)
2565 stream.lowest_layer().close();
2566 stream.lowest_layer().connect(*endpoint_iterator++, error);
2574 bool fNeedHandshake;
2579 void ThreadRPCServer(void* parg)
2581 IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
2584 vnThreadsRunning[THREAD_RPCSERVER]++;
2585 ThreadRPCServer2(parg);
2586 vnThreadsRunning[THREAD_RPCSERVER]--;
2588 catch (std::exception& e) {
2589 vnThreadsRunning[THREAD_RPCSERVER]--;
2590 PrintException(&e, "ThreadRPCServer()");
2592 vnThreadsRunning[THREAD_RPCSERVER]--;
2593 PrintException(NULL, "ThreadRPCServer()");
2595 printf("ThreadRPCServer exiting\n");
2598 void ThreadRPCServer2(void* parg)
2600 printf("ThreadRPCServer started\n");
2602 strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
2603 if (mapArgs["-rpcpassword"] == "")
2605 unsigned char rand_pwd[32];
2606 RAND_bytes(rand_pwd, 32);
2607 string strWhatAmI = "To use ppcoind";
2608 if (mapArgs.count("-server"))
2609 strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
2610 else if (mapArgs.count("-daemon"))
2611 strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
2612 ThreadSafeMessageBox(strprintf(
2613 _("%s, you must set a rpcpassword in the configuration file:\n %s\n"
2614 "It is recommended you use the following random password:\n"
2615 "rpcuser=bitcoinrpc\n"
2617 "(you do not need to remember this password)\n"
2618 "If the file does not exist, create it with owner-readable-only file permissions.\n"),
2620 GetConfigFile().string().c_str(),
2621 EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str()),
2622 _("Error"), wxOK | wxMODAL);
2627 bool fUseSSL = GetBoolArg("-rpcssl");
2628 asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
2630 asio::io_service io_service;
2631 ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", RPC_PORT));
2632 ip::tcp::acceptor acceptor(io_service);
2635 acceptor.open(endpoint.protocol());
2636 acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
2637 acceptor.bind(endpoint);
2638 acceptor.listen(socket_base::max_connections);
2640 catch(boost::system::system_error &e)
2642 ThreadSafeMessageBox(strprintf(_("An error occured while setting up the RPC port %i for listening: %s"), endpoint.port(), e.what()),
2643 _("Error"), wxOK | wxMODAL);
2648 ssl::context context(io_service, ssl::context::sslv23);
2651 context.set_options(ssl::context::no_sslv2);
2653 filesystem::path pathCertFile(GetArg("-rpcsslcertificatechainfile", "server.cert"));
2654 if (!pathCertFile.is_complete()) pathCertFile = filesystem::path(GetDataDir()) / pathCertFile;
2655 if (filesystem::exists(pathCertFile)) context.use_certificate_chain_file(pathCertFile.string());
2656 else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", pathCertFile.string().c_str());
2658 filesystem::path pathPKFile(GetArg("-rpcsslprivatekeyfile", "server.pem"));
2659 if (!pathPKFile.is_complete()) pathPKFile = filesystem::path(GetDataDir()) / pathPKFile;
2660 if (filesystem::exists(pathPKFile)) context.use_private_key_file(pathPKFile.string(), ssl::context::pem);
2661 else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pathPKFile.string().c_str());
2663 string strCiphers = GetArg("-rpcsslciphers", "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
2664 SSL_CTX_set_cipher_list(context.impl(), strCiphers.c_str());
2669 // Accept connection
2670 SSLStream sslStream(io_service, context);
2671 SSLIOStreamDevice d(sslStream, fUseSSL);
2672 iostreams::stream<SSLIOStreamDevice> stream(d);
2674 ip::tcp::endpoint peer;
2675 vnThreadsRunning[THREAD_RPCSERVER]--;
2676 acceptor.accept(sslStream.lowest_layer(), peer);
2677 vnThreadsRunning[4]++;
2681 // Restrict callers by IP
2682 if (!ClientAllowed(peer.address().to_string()))
2684 // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
2686 stream << HTTPReply(403, "") << std::flush;
2690 map<string, string> mapHeaders;
2693 boost::thread api_caller(ReadHTTP, boost::ref(stream), boost::ref(mapHeaders), boost::ref(strRequest));
2694 if (!api_caller.timed_join(boost::posix_time::seconds(GetArg("-rpctimeout", 30))))
2697 printf("ThreadRPCServer ReadHTTP timeout\n");
2701 // Check authorization
2702 if (mapHeaders.count("authorization") == 0)
2704 stream << HTTPReply(401, "") << std::flush;
2707 if (!HTTPAuthorized(mapHeaders))
2709 printf("ThreadRPCServer incorrect password attempt from %s\n",peer.address().to_string().c_str());
2710 /* Deter brute-forcing short passwords.
2711 If this results in a DOS the user really
2712 shouldn't have their RPC port exposed.*/
2713 if (mapArgs["-rpcpassword"].size() < 20)
2716 stream << HTTPReply(401, "") << std::flush;
2720 Value id = Value::null;
2725 if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
2726 throw JSONRPCError(-32700, "Parse error");
2727 const Object& request = valRequest.get_obj();
2729 // Parse id now so errors from here on will have the id
2730 id = find_value(request, "id");
2733 Value valMethod = find_value(request, "method");
2734 if (valMethod.type() == null_type)
2735 throw JSONRPCError(-32600, "Missing method");
2736 if (valMethod.type() != str_type)
2737 throw JSONRPCError(-32600, "Method must be a string");
2738 string strMethod = valMethod.get_str();
2739 if (strMethod != "getwork" && strMethod != "getmemorypool")
2740 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
2743 Value valParams = find_value(request, "params");
2745 if (valParams.type() == array_type)
2746 params = valParams.get_array();
2747 else if (valParams.type() == null_type)
2750 throw JSONRPCError(-32600, "Params must be an array");
2753 const CRPCCommand *pcmd = tableRPC[strMethod];
2755 throw JSONRPCError(-32601, "Method not found");
2757 // Observe safe mode
2758 string strWarning = GetWarnings("rpc");
2759 if (strWarning != "" && !GetBoolArg("-disablesafemode") &&
2761 throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
2768 LOCK2(cs_main, pwalletMain->cs_wallet);
2769 result = pcmd->actor(params, false);
2773 string strReply = JSONRPCReply(result, Value::null, id);
2774 stream << HTTPReply(200, strReply) << std::flush;
2776 catch (std::exception& e)
2778 ErrorReply(stream, JSONRPCError(-1, e.what()), id);
2781 catch (Object& objError)
2783 ErrorReply(stream, objError, id);
2785 catch (std::exception& e)
2787 ErrorReply(stream, JSONRPCError(-32700, e.what()), id);
2795 Object CallRPC(const string& strMethod, const Array& params)
2797 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2798 throw runtime_error(strprintf(
2799 _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
2800 "If the file does not exist, create it with owner-readable-only file permissions."),
2801 GetConfigFile().string().c_str()));
2803 // Connect to localhost
2804 bool fUseSSL = GetBoolArg("-rpcssl");
2805 asio::io_service io_service;
2806 ssl::context context(io_service, ssl::context::sslv23);
2807 context.set_options(ssl::context::no_sslv2);
2808 SSLStream sslStream(io_service, context);
2809 SSLIOStreamDevice d(sslStream, fUseSSL);
2810 iostreams::stream<SSLIOStreamDevice> stream(d);
2811 if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", CBigNum(RPC_PORT).ToString().c_str())))
2812 throw runtime_error("couldn't connect to server");
2814 // HTTP basic authentication
2815 string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
2816 map<string, string> mapRequestHeaders;
2817 mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
2820 string strRequest = JSONRPCRequest(strMethod, params, 1);
2821 string strPost = HTTPPost(strRequest, mapRequestHeaders);
2822 stream << strPost << std::flush;
2825 map<string, string> mapHeaders;
2827 int nStatus = ReadHTTP(stream, mapHeaders, strReply);
2829 throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
2830 else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
2831 throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
2832 else if (strReply.empty())
2833 throw runtime_error("no response from server");
2837 if (!read_string(strReply, valReply))
2838 throw runtime_error("couldn't parse reply from server");
2839 const Object& reply = valReply.get_obj();
2841 throw runtime_error("expected reply to have result, error and id properties");
2849 template<typename T>
2850 void ConvertTo(Value& value)
2852 if (value.type() == str_type)
2854 // reinterpret string as unquoted json value
2856 if (!read_string(value.get_str(), value2))
2857 throw runtime_error("type mismatch");
2858 value = value2.get_value<T>();
2862 value = value.get_value<T>();
2866 int CommandLineRPC(int argc, char *argv[])
2873 while (argc > 1 && IsSwitchChar(argv[1][0]))
2881 throw runtime_error("too few parameters");
2882 string strMethod = argv[1];
2884 // Parameters default to strings
2886 for (int i = 2; i < argc; i++)
2887 params.push_back(argv[i]);
2888 int n = params.size();
2891 // Special case non-string parameter types
2893 if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
2894 if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2895 if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
2896 if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]);
2897 if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2898 if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2899 if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2900 if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
2901 if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2902 if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
2903 if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2904 if (strMethod == "getblockhash" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2905 if (strMethod == "getblock" && n > 1) ConvertTo<bool>(params[1]);
2906 if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]);
2907 if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2908 if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]);
2909 if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2910 if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2911 if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2912 if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2913 if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2914 if (strMethod == "walletpassphrase" && n > 2) ConvertTo<bool>(params[2]);
2915 if (strMethod == "listsinceblock" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2916 if (strMethod == "sendalert" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2917 if (strMethod == "sendalert" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2918 if (strMethod == "sendalert" && n > 4) ConvertTo<boost::int64_t>(params[4]);
2919 if (strMethod == "sendalert" && n > 5) ConvertTo<boost::int64_t>(params[5]);
2920 if (strMethod == "sendalert" && n > 6) ConvertTo<boost::int64_t>(params[6]);
2921 if (strMethod == "sendmany" && n > 1)
2923 string s = params[1].get_str();
2925 if (!read_string(s, v) || v.type() != obj_type)
2926 throw runtime_error("type mismatch");
2927 params[1] = v.get_obj();
2929 if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2930 if (strMethod == "reservebalance" && n > 0) ConvertTo<bool>(params[0]);
2931 if (strMethod == "reservebalance" && n > 1) ConvertTo<double>(params[1]);
2932 if (strMethod == "addmultisigaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2933 if (strMethod == "addmultisigaddress" && n > 1)
2935 string s = params[1].get_str();
2937 if (!read_string(s, v) || v.type() != array_type)
2938 throw runtime_error("type mismatch "+s);
2939 params[1] = v.get_array();
2943 Object reply = CallRPC(strMethod, params);
2946 const Value& result = find_value(reply, "result");
2947 const Value& error = find_value(reply, "error");
2949 if (error.type() != null_type)
2952 strPrint = "error: " + write_string(error, false);
2953 int code = find_value(error.get_obj(), "code").get_int();
2959 if (result.type() == null_type)
2961 else if (result.type() == str_type)
2962 strPrint = result.get_str();
2964 strPrint = write_string(result, true);
2967 catch (std::exception& e)
2969 strPrint = string("error: ") + e.what();
2974 PrintException(NULL, "CommandLineRPC()");
2979 fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
2988 int main(int argc, char *argv[])
2991 // Turn off microsoft heap dump noise
2992 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
2993 _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
2995 setbuf(stdin, NULL);
2996 setbuf(stdout, NULL);
2997 setbuf(stderr, NULL);
3001 if (argc >= 2 && string(argv[1]) == "-server")
3003 printf("server ready\n");
3004 ThreadRPCServer(NULL);
3008 return CommandLineRPC(argc, argv);
3011 catch (std::exception& e) {
3012 PrintException(&e, "main()");
3014 PrintException(NULL, "main()");
3020 const CRPCTable tableRPC;