1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2012 The Bitcoin developers
3 // Copyright (c) 2011-2012 The PPCoin developers
4 // Distributed under the MIT/X11 software license, see the accompanying
5 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
13 #include "checkpoints.h"
14 #include "ui_interface.h"
15 #include "bitcoinrpc.h"
18 #include <boost/asio.hpp>
19 #include <boost/filesystem.hpp>
20 #include <boost/iostreams/concepts.hpp>
21 #include <boost/iostreams/stream.hpp>
22 #include <boost/algorithm/string.hpp>
23 #include <boost/lexical_cast.hpp>
24 #include <boost/asio/ssl.hpp>
25 #include <boost/filesystem/fstream.hpp>
26 typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> SSLStream;
28 #define printf OutputDebugStringF
29 // MinGW 3.4.5 gets "fatal error: had to relocate PCH" if the json headers are
30 // precompiled in headers.h. The problem might be when the pch file goes over
31 // a certain size around 145MB. If we need access to json_spirit outside this
32 // file, we could use the compiled json_spirit option.
35 using namespace boost;
36 using namespace boost::asio;
37 using namespace json_spirit;
39 void ThreadRPCServer2(void* parg);
41 static std::string strRPCUserColonPass;
43 static int64 nWalletUnlockTime;
44 static CCriticalSection cs_nWalletUnlockTime;
46 extern Value dumpprivkey(const Array& params, bool fHelp);
47 extern Value importprivkey(const Array& params, bool fHelp);
49 Object JSONRPCError(int code, const string& message)
52 error.push_back(Pair("code", code));
53 error.push_back(Pair("message", message));
57 double GetDifficulty(const CBlockIndex* blockindex = NULL)
59 // Floating point number that is a multiple of the minimum difficulty,
60 // minimum difficulty = 1.0.
61 if (blockindex == NULL)
63 if (pindexBest == NULL)
66 blockindex = GetLastBlockIndex(pindexBest, false);
69 int nShift = (blockindex->nBits >> 24) & 0xff;
72 (double)0x0000ffff / (double)(blockindex->nBits & 0x00ffffff);
89 int64 AmountFromValue(const Value& value)
91 double dAmount = value.get_real();
92 if (dAmount <= 0.0 || dAmount > MAX_MONEY)
93 throw JSONRPCError(-3, "Invalid amount");
94 int64 nAmount = roundint64(dAmount * COIN);
95 if (!MoneyRange(nAmount))
96 throw JSONRPCError(-3, "Invalid amount");
100 Value ValueFromAmount(int64 amount)
102 return (double)amount / (double)COIN;
106 HexBits(unsigned int nBits)
112 uBits.nBits = htonl((int32_t)nBits);
113 return HexStr(BEGIN(uBits.cBits), END(uBits.cBits));
116 void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
118 int confirms = wtx.GetDepthInMainChain();
119 entry.push_back(Pair("confirmations", confirms));
122 entry.push_back(Pair("blockhash", wtx.hashBlock.GetHex()));
123 entry.push_back(Pair("blockindex", wtx.nIndex));
125 entry.push_back(Pair("txid", wtx.GetHash().GetHex()));
126 entry.push_back(Pair("time", (boost::int64_t)wtx.GetTxTime()));
127 BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
128 entry.push_back(Pair(item.first, item.second));
131 string AccountFromValue(const Value& value)
133 string strAccount = value.get_str();
134 if (strAccount == "*")
135 throw JSONRPCError(-11, "Invalid account name");
139 Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex)
142 result.push_back(Pair("hash", block.GetHash().GetHex()));
143 result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION)));
144 result.push_back(Pair("height", blockindex->nHeight));
145 result.push_back(Pair("version", block.nVersion));
146 result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex()));
147 result.push_back(Pair("time", (boost::int64_t)block.GetBlockTime()));
148 result.push_back(Pair("nonce", (boost::uint64_t)block.nNonce));
149 result.push_back(Pair("bits", HexBits(block.nBits)));
150 result.push_back(Pair("difficulty", GetDifficulty(blockindex)));
152 BOOST_FOREACH (const CTransaction&tx, block.vtx)
153 txhashes.push_back(tx.GetHash().GetHex());
154 result.push_back(Pair("tx", txhashes));
156 if (blockindex->pprev)
157 result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex()));
158 if (blockindex->pnext)
159 result.push_back(Pair("nextblockhash", blockindex->pnext->GetBlockHash().GetHex()));
166 /// Note: This interface may still be subject to change.
169 string CRPCTable::help(string strCommand) const
172 set<rpcfn_type> setDone;
173 for (map<string, const CRPCCommand*>::const_iterator mi = mapCommands.begin(); mi != mapCommands.end(); ++mi)
175 const CRPCCommand *pcmd = mi->second;
176 string strMethod = mi->first;
177 // We already filter duplicates, but these deprecated screw up the sort order
178 if (strMethod == "getamountreceived" ||
179 strMethod == "getallreceived" ||
180 strMethod == "getblocknumber" || // deprecated
181 (strMethod.find("label") != string::npos))
183 if (strCommand != "" && strMethod != strCommand)
188 rpcfn_type pfn = pcmd->actor;
189 if (setDone.insert(pfn).second)
190 (*pfn)(params, true);
192 catch (std::exception& e)
194 // Help text is returned in an exception
195 string strHelp = string(e.what());
196 if (strCommand == "")
197 if (strHelp.find('\n') != string::npos)
198 strHelp = strHelp.substr(0, strHelp.find('\n'));
199 strRet += strHelp + "\n";
203 strRet = strprintf("help: unknown command: %s\n", strCommand.c_str());
204 strRet = strRet.substr(0,strRet.size()-1);
208 Value help(const Array& params, bool fHelp)
210 if (fHelp || params.size() > 1)
213 "List commands, or get help for a command.");
216 if (params.size() > 0)
217 strCommand = params[0].get_str();
219 return tableRPC.help(strCommand);
223 Value stop(const Array& params, bool fHelp)
225 if (fHelp || params.size() != 0)
228 "Stop ppcoin server.");
229 // Shutdown will take long enough that the response should get back
231 return "ppcoin server stopping";
235 Value getblockcount(const Array& params, bool fHelp)
237 if (fHelp || params.size() != 0)
240 "Returns the number of blocks in the longest block chain.");
247 Value getblocknumber(const Array& params, bool fHelp)
249 if (fHelp || params.size() != 0)
252 "Deprecated. Use getblockcount.");
258 Value getconnectioncount(const Array& params, bool fHelp)
260 if (fHelp || params.size() != 0)
262 "getconnectioncount\n"
263 "Returns the number of connections to other nodes.");
265 return (int)vNodes.size();
269 Value getdifficulty(const Array& params, bool fHelp)
271 if (fHelp || params.size() != 0)
274 "Returns difficulty as a multiple of the minimum difficulty.");
277 obj.push_back(Pair("proof-of-work", GetDifficulty()));
278 obj.push_back(Pair("proof-of-stake", GetDifficulty(GetLastBlockIndex(pindexBest, true))));
283 Value getgenerate(const Array& params, bool fHelp)
285 if (fHelp || params.size() != 0)
288 "Returns true or false.");
290 return GetBoolArg("-gen");
294 Value setgenerate(const Array& params, bool fHelp)
296 if (fHelp || params.size() < 1 || params.size() > 2)
298 "setgenerate <generate> [genproclimit]\n"
299 "<generate> is true or false to turn generation on or off.\n"
300 "Generation is limited to [genproclimit] processors, -1 is unlimited.");
302 bool fGenerate = true;
303 if (params.size() > 0)
304 fGenerate = params[0].get_bool();
306 if (params.size() > 1)
308 int nGenProcLimit = params[1].get_int();
309 mapArgs["-genproclimit"] = itostr(nGenProcLimit);
310 if (nGenProcLimit == 0)
313 mapArgs["-gen"] = (fGenerate ? "1" : "0");
315 GenerateBitcoins(fGenerate, pwalletMain);
320 Value gethashespersec(const Array& params, bool fHelp)
322 if (fHelp || params.size() != 0)
325 "Returns a recent hashes per second performance measurement while generating.");
327 if (GetTimeMillis() - nHPSTimerStart > 8000)
328 return (boost::int64_t)0;
329 return (boost::int64_t)dHashesPerSec;
333 Value getinfo(const Array& params, bool fHelp)
335 if (fHelp || params.size() != 0)
338 "Returns an object containing various state info.");
341 obj.push_back(Pair("version", FormatFullVersion()));
342 obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION));
343 obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
344 obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
345 obj.push_back(Pair("newmint", ValueFromAmount(pwalletMain->GetNewMint())));
346 obj.push_back(Pair("stake", ValueFromAmount(pwalletMain->GetStake())));
347 obj.push_back(Pair("blocks", (int)nBestHeight));
348 obj.push_back(Pair("moneysupply", ValueFromAmount(pindexBest->nMoneySupply)));
349 obj.push_back(Pair("connections", (int)vNodes.size()));
350 obj.push_back(Pair("proxy", (fUseProxy ? addrProxy.ToStringIPPort() : string())));
351 obj.push_back(Pair("ip", addrSeenByPeer.ToStringIP()));
352 obj.push_back(Pair("difficulty", (double)GetDifficulty()));
353 obj.push_back(Pair("testnet", fTestNet));
354 obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));
355 obj.push_back(Pair("keypoolsize", pwalletMain->GetKeyPoolSize()));
356 obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee)));
357 if (pwalletMain->IsCrypted())
358 obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime / 1000));
359 obj.push_back(Pair("errors", GetWarnings("statusbar")));
364 Value getmininginfo(const Array& params, bool fHelp)
366 if (fHelp || params.size() != 0)
369 "Returns an object containing mining-related information.");
372 obj.push_back(Pair("blocks", (int)nBestHeight));
373 obj.push_back(Pair("currentblocksize",(uint64_t)nLastBlockSize));
374 obj.push_back(Pair("currentblocktx",(uint64_t)nLastBlockTx));
375 obj.push_back(Pair("difficulty", (double)GetDifficulty()));
376 obj.push_back(Pair("errors", GetWarnings("statusbar")));
377 obj.push_back(Pair("generate", GetBoolArg("-gen")));
378 obj.push_back(Pair("genproclimit", (int)GetArg("-genproclimit", -1)));
379 obj.push_back(Pair("hashespersec", gethashespersec(params, false)));
380 obj.push_back(Pair("pooledtx", (uint64_t)mempool.size()));
381 obj.push_back(Pair("testnet", fTestNet));
386 Value getnewaddress(const Array& params, bool fHelp)
388 if (fHelp || params.size() > 1)
390 "getnewaddress [account]\n"
391 "Returns a new ppcoin address for receiving payments. "
392 "If [account] is specified (recommended), it is added to the address book "
393 "so payments received with the address will be credited to [account].");
395 // Parse the account first so we don't generate a key if there's an error
397 if (params.size() > 0)
398 strAccount = AccountFromValue(params[0]);
400 if (!pwalletMain->IsLocked())
401 pwalletMain->TopUpKeyPool();
403 // Generate a new key that is added to wallet
404 std::vector<unsigned char> newKey;
405 if (!pwalletMain->GetKeyFromPool(newKey, false))
406 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
407 CBitcoinAddress address(newKey);
409 pwalletMain->SetAddressBookName(address, strAccount);
411 return address.ToString();
415 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
417 CWalletDB walletdb(pwalletMain->strWalletFile);
420 walletdb.ReadAccount(strAccount, account);
422 bool bKeyUsed = false;
424 // Check if the current key has been used
425 if (!account.vchPubKey.empty())
427 CScript scriptPubKey;
428 scriptPubKey.SetBitcoinAddress(account.vchPubKey);
429 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
430 it != pwalletMain->mapWallet.end() && !account.vchPubKey.empty();
433 const CWalletTx& wtx = (*it).second;
434 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
435 if (txout.scriptPubKey == scriptPubKey)
440 // Generate a new key
441 if (account.vchPubKey.empty() || bForceNew || bKeyUsed)
443 if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false))
444 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
446 pwalletMain->SetAddressBookName(CBitcoinAddress(account.vchPubKey), strAccount);
447 walletdb.WriteAccount(strAccount, account);
450 return CBitcoinAddress(account.vchPubKey);
453 Value getaccountaddress(const Array& params, bool fHelp)
455 if (fHelp || params.size() != 1)
457 "getaccountaddress <account>\n"
458 "Returns the current ppcoin address for receiving payments to this account.");
460 // Parse the account first so we don't generate a key if there's an error
461 string strAccount = AccountFromValue(params[0]);
465 ret = GetAccountAddress(strAccount).ToString();
472 Value setaccount(const Array& params, bool fHelp)
474 if (fHelp || params.size() < 1 || params.size() > 2)
476 "setaccount <ppcoinaddress> <account>\n"
477 "Sets the account associated with the given address.");
479 CBitcoinAddress address(params[0].get_str());
480 if (!address.IsValid())
481 throw JSONRPCError(-5, "Invalid ppcoin address");
485 if (params.size() > 1)
486 strAccount = AccountFromValue(params[1]);
488 // Detect when changing the account of an address that is the 'unused current key' of another account:
489 if (pwalletMain->mapAddressBook.count(address))
491 string strOldAccount = pwalletMain->mapAddressBook[address];
492 if (address == GetAccountAddress(strOldAccount))
493 GetAccountAddress(strOldAccount, true);
496 pwalletMain->SetAddressBookName(address, strAccount);
502 Value getaccount(const Array& params, bool fHelp)
504 if (fHelp || params.size() != 1)
506 "getaccount <ppcoinaddress>\n"
507 "Returns the account associated with the given address.");
509 CBitcoinAddress address(params[0].get_str());
510 if (!address.IsValid())
511 throw JSONRPCError(-5, "Invalid ppcoin address");
514 map<CBitcoinAddress, string>::iterator mi = pwalletMain->mapAddressBook.find(address);
515 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
516 strAccount = (*mi).second;
521 Value getaddressesbyaccount(const Array& params, bool fHelp)
523 if (fHelp || params.size() != 1)
525 "getaddressesbyaccount <account>\n"
526 "Returns the list of addresses for the given account.");
528 string strAccount = AccountFromValue(params[0]);
530 // Find all addresses that have the given account
532 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
534 const CBitcoinAddress& address = item.first;
535 const string& strName = item.second;
536 if (strName == strAccount)
537 ret.push_back(address.ToString());
542 Value settxfee(const Array& params, bool fHelp)
544 if (fHelp || params.size() < 1 || params.size() > 1 || AmountFromValue(params[0]) < MIN_TX_FEE)
546 "settxfee <amount>\n"
547 "<amount> is a real and is rounded to 0.01 (cent)\n"
548 "Minimum and default transaction fee per KB is 1 cent");
550 nTransactionFee = AmountFromValue(params[0]);
551 nTransactionFee = (nTransactionFee / CENT) * CENT; // round to cent
555 Value sendtoaddress(const Array& params, bool fHelp)
557 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
559 "sendtoaddress <ppcoinaddress> <amount> [comment] [comment-to]\n"
560 "<amount> is a real and is rounded to the nearest 0.000001\n"
561 "requires wallet passphrase to be set with walletpassphrase first");
562 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
564 "sendtoaddress <ppcoinaddress> <amount> [comment] [comment-to]\n"
565 "<amount> is a real and is rounded to the nearest 0.000001");
567 CBitcoinAddress address(params[0].get_str());
568 if (!address.IsValid())
569 throw JSONRPCError(-5, "Invalid ppcoin address");
572 int64 nAmount = AmountFromValue(params[1]);
573 if (nAmount < MIN_TXOUT_AMOUNT)
574 throw JSONRPCError(-101, "Send amount too small");
578 if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
579 wtx.mapValue["comment"] = params[2].get_str();
580 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
581 wtx.mapValue["to"] = params[3].get_str();
583 if (pwalletMain->IsLocked())
584 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
586 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
588 throw JSONRPCError(-4, strError);
590 return wtx.GetHash().GetHex();
593 Value signmessage(const Array& params, bool fHelp)
595 if (fHelp || params.size() != 2)
597 "signmessage <ppcoinaddress> <message>\n"
598 "Sign a message with the private key of an address");
600 if (pwalletMain->IsLocked())
601 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
603 string strAddress = params[0].get_str();
604 string strMessage = params[1].get_str();
606 CBitcoinAddress addr(strAddress);
608 throw JSONRPCError(-3, "Invalid address");
611 if (!pwalletMain->GetKey(addr, key))
612 throw JSONRPCError(-4, "Private key not available");
614 CDataStream ss(SER_GETHASH, 0);
615 ss << strMessageMagic;
618 vector<unsigned char> vchSig;
619 if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig))
620 throw JSONRPCError(-5, "Sign failed");
622 return EncodeBase64(&vchSig[0], vchSig.size());
625 Value verifymessage(const Array& params, bool fHelp)
627 if (fHelp || params.size() != 3)
629 "verifymessage <ppcoinaddress> <signature> <message>\n"
630 "Verify a signed message");
632 string strAddress = params[0].get_str();
633 string strSign = params[1].get_str();
634 string strMessage = params[2].get_str();
636 CBitcoinAddress addr(strAddress);
638 throw JSONRPCError(-3, "Invalid address");
640 bool fInvalid = false;
641 vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
644 throw JSONRPCError(-5, "Malformed base64 encoding");
646 CDataStream ss(SER_GETHASH, 0);
647 ss << strMessageMagic;
651 if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
654 return (CBitcoinAddress(key.GetPubKey()) == addr);
658 Value getreceivedbyaddress(const Array& params, bool fHelp)
660 if (fHelp || params.size() < 1 || params.size() > 2)
662 "getreceivedbyaddress <ppcoinaddress> [minconf=1]\n"
663 "Returns the total amount received by <ppcoinaddress> in transactions with at least [minconf] confirmations.");
666 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
667 CScript scriptPubKey;
668 if (!address.IsValid())
669 throw JSONRPCError(-5, "Invalid ppcoin address");
670 scriptPubKey.SetBitcoinAddress(address);
671 if (!IsMine(*pwalletMain,scriptPubKey))
674 // Minimum confirmations
676 if (params.size() > 1)
677 nMinDepth = params[1].get_int();
681 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
683 const CWalletTx& wtx = (*it).second;
684 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
687 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
688 if (txout.scriptPubKey == scriptPubKey)
689 if (wtx.GetDepthInMainChain() >= nMinDepth)
690 nAmount += txout.nValue;
693 return ValueFromAmount(nAmount);
697 void GetAccountAddresses(string strAccount, set<CBitcoinAddress>& setAddress)
699 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
701 const CBitcoinAddress& address = item.first;
702 const string& strName = item.second;
703 if (strName == strAccount)
704 setAddress.insert(address);
709 Value getreceivedbyaccount(const Array& params, bool fHelp)
711 if (fHelp || params.size() < 1 || params.size() > 2)
713 "getreceivedbyaccount <account> [minconf=1]\n"
714 "Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.");
716 // Minimum confirmations
718 if (params.size() > 1)
719 nMinDepth = params[1].get_int();
721 // Get the set of pub keys assigned to account
722 string strAccount = AccountFromValue(params[0]);
723 set<CBitcoinAddress> setAddress;
724 GetAccountAddresses(strAccount, setAddress);
728 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
730 const CWalletTx& wtx = (*it).second;
731 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
734 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
736 CBitcoinAddress address;
737 if (ExtractAddress(txout.scriptPubKey, address) && pwalletMain->HaveKey(address) && setAddress.count(address))
738 if (wtx.GetDepthInMainChain() >= nMinDepth)
739 nAmount += txout.nValue;
743 return (double)nAmount / (double)COIN;
747 int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth)
751 // Tally wallet transactions
752 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
754 const CWalletTx& wtx = (*it).second;
758 int64 nGenerated, nReceived, nSent, nFee;
759 wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee);
761 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
762 nBalance += nReceived;
763 nBalance += nGenerated - nSent - nFee;
766 // Tally internal accounting entries
767 nBalance += walletdb.GetAccountCreditDebit(strAccount);
772 int64 GetAccountBalance(const string& strAccount, int nMinDepth)
774 CWalletDB walletdb(pwalletMain->strWalletFile);
775 return GetAccountBalance(walletdb, strAccount, nMinDepth);
779 Value getbalance(const Array& params, bool fHelp)
781 if (fHelp || params.size() > 2)
783 "getbalance [account] [minconf=1]\n"
784 "If [account] is not specified, returns the server's total available balance.\n"
785 "If [account] is specified, returns the balance in the account.");
787 if (params.size() == 0)
788 return ValueFromAmount(pwalletMain->GetBalance());
791 if (params.size() > 1)
792 nMinDepth = params[1].get_int();
794 if (params[0].get_str() == "*") {
795 // Calculate total balance a different way from GetBalance()
796 // (GetBalance() sums up all unspent TxOuts)
797 // getbalance and getbalance '*' should always return the same number.
799 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
801 const CWalletTx& wtx = (*it).second;
805 int64 allGeneratedImmature, allGeneratedMature, allFee;
806 allGeneratedImmature = allGeneratedMature = allFee = 0;
807 string strSentAccount;
808 list<pair<CBitcoinAddress, int64> > listReceived;
809 list<pair<CBitcoinAddress, int64> > listSent;
810 wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
811 if (wtx.GetDepthInMainChain() >= nMinDepth)
813 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listReceived)
814 nBalance += r.second;
816 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listSent)
817 nBalance -= r.second;
819 nBalance += allGeneratedMature;
821 return ValueFromAmount(nBalance);
824 string strAccount = AccountFromValue(params[0]);
826 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
828 return ValueFromAmount(nBalance);
832 Value movecmd(const Array& params, bool fHelp)
834 if (fHelp || params.size() < 3 || params.size() > 5)
836 "move <fromaccount> <toaccount> <amount> [minconf=1] [comment]\n"
837 "Move from one account in your wallet to another.");
839 string strFrom = AccountFromValue(params[0]);
840 string strTo = AccountFromValue(params[1]);
841 int64 nAmount = AmountFromValue(params[2]);
842 if (params.size() > 3)
843 // unused parameter, used to be nMinDepth, keep type-checking it though
844 (void)params[3].get_int();
846 if (params.size() > 4)
847 strComment = params[4].get_str();
849 CWalletDB walletdb(pwalletMain->strWalletFile);
850 if (!walletdb.TxnBegin())
851 throw JSONRPCError(-20, "database error");
853 int64 nNow = GetAdjustedTime();
856 CAccountingEntry debit;
857 debit.strAccount = strFrom;
858 debit.nCreditDebit = -nAmount;
860 debit.strOtherAccount = strTo;
861 debit.strComment = strComment;
862 walletdb.WriteAccountingEntry(debit);
865 CAccountingEntry credit;
866 credit.strAccount = strTo;
867 credit.nCreditDebit = nAmount;
869 credit.strOtherAccount = strFrom;
870 credit.strComment = strComment;
871 walletdb.WriteAccountingEntry(credit);
873 if (!walletdb.TxnCommit())
874 throw JSONRPCError(-20, "database error");
880 Value sendfrom(const Array& params, bool fHelp)
882 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
884 "sendfrom <fromaccount> <toppcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
885 "<amount> is a real and is rounded to the nearest 0.000001\n"
886 "requires wallet passphrase to be set with walletpassphrase first");
887 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
889 "sendfrom <fromaccount> <toppcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
890 "<amount> is a real and is rounded to the nearest 0.000001");
892 string strAccount = AccountFromValue(params[0]);
893 CBitcoinAddress address(params[1].get_str());
894 if (!address.IsValid())
895 throw JSONRPCError(-5, "Invalid ppcoin address");
896 int64 nAmount = AmountFromValue(params[2]);
897 if (nAmount < MIN_TXOUT_AMOUNT)
898 throw JSONRPCError(-101, "Send amount too small");
900 if (params.size() > 3)
901 nMinDepth = params[3].get_int();
904 wtx.strFromAccount = strAccount;
905 if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
906 wtx.mapValue["comment"] = params[4].get_str();
907 if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
908 wtx.mapValue["to"] = params[5].get_str();
910 if (pwalletMain->IsLocked())
911 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
914 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
915 if (nAmount > nBalance)
916 throw JSONRPCError(-6, "Account has insufficient funds");
919 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
921 throw JSONRPCError(-4, strError);
923 return wtx.GetHash().GetHex();
927 Value sendmany(const Array& params, bool fHelp)
929 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
931 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
932 "amounts are double-precision floating point numbers\n"
933 "requires wallet passphrase to be set with walletpassphrase first");
934 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
936 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
937 "amounts are double-precision floating point numbers");
939 string strAccount = AccountFromValue(params[0]);
940 Object sendTo = params[1].get_obj();
942 if (params.size() > 2)
943 nMinDepth = params[2].get_int();
946 wtx.strFromAccount = strAccount;
947 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
948 wtx.mapValue["comment"] = params[3].get_str();
950 set<CBitcoinAddress> setAddress;
951 vector<pair<CScript, int64> > vecSend;
953 int64 totalAmount = 0;
954 BOOST_FOREACH(const Pair& s, sendTo)
956 CBitcoinAddress address(s.name_);
957 if (!address.IsValid())
958 throw JSONRPCError(-5, string("Invalid ppcoin address:")+s.name_);
960 if (setAddress.count(address))
961 throw JSONRPCError(-8, string("Invalid parameter, duplicated address: ")+s.name_);
962 setAddress.insert(address);
964 CScript scriptPubKey;
965 scriptPubKey.SetBitcoinAddress(address);
966 int64 nAmount = AmountFromValue(s.value_);
967 if (nAmount < MIN_TXOUT_AMOUNT)
968 throw JSONRPCError(-101, "Send amount too small");
969 totalAmount += nAmount;
971 vecSend.push_back(make_pair(scriptPubKey, nAmount));
974 if (pwalletMain->IsLocked())
975 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
976 if (fWalletUnlockMintOnly)
977 throw JSONRPCError(-13, "Error: Wallet unlocked for block minting only.");
980 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
981 if (totalAmount > nBalance)
982 throw JSONRPCError(-6, "Account has insufficient funds");
985 CReserveKey keyChange(pwalletMain);
986 int64 nFeeRequired = 0;
987 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
990 if (totalAmount + nFeeRequired > pwalletMain->GetBalance())
991 throw JSONRPCError(-6, "Insufficient funds");
992 throw JSONRPCError(-4, "Transaction creation failed");
994 if (!pwalletMain->CommitTransaction(wtx, keyChange))
995 throw JSONRPCError(-4, "Transaction commit failed");
997 return wtx.GetHash().GetHex();
1000 Value addmultisigaddress(const Array& params, bool fHelp)
1002 if (fHelp || params.size() < 2 || params.size() > 3)
1004 string msg = "addmultisigaddress <nrequired> <'[\"key\",\"key\"]'> [account]\n"
1005 "Add a nrequired-to-sign multisignature address to the wallet\"\n"
1006 "each key is a bitcoin address or hex-encoded public key\n"
1007 "If [account] is specified, assign address to [account].";
1008 throw runtime_error(msg);
1011 int nRequired = params[0].get_int();
1012 const Array& keys = params[1].get_array();
1014 if (params.size() > 2)
1015 strAccount = AccountFromValue(params[2]);
1017 // Gather public keys
1019 throw runtime_error("a multisignature address must require at least one key to redeem");
1020 if ((int)keys.size() < nRequired)
1021 throw runtime_error(
1022 strprintf("not enough keys supplied "
1023 "(got %d keys, but need at least %d to redeem)", keys.size(), nRequired));
1024 std::vector<CKey> pubkeys;
1025 pubkeys.resize(keys.size());
1026 for (unsigned int i = 0; i < keys.size(); i++)
1028 const std::string& ks = keys[i].get_str();
1030 // Case 1: bitcoin address and we have full public key:
1031 CBitcoinAddress address(ks);
1032 if (address.IsValid())
1034 if (address.IsScript())
1035 throw runtime_error(
1036 strprintf("%s is a pay-to-script address",ks.c_str()));
1037 std::vector<unsigned char> vchPubKey;
1038 if (!pwalletMain->GetPubKey(address, vchPubKey))
1039 throw runtime_error(
1040 strprintf("no full public key for address %s",ks.c_str()));
1041 if (vchPubKey.empty() || !pubkeys[i].SetPubKey(vchPubKey))
1042 throw runtime_error(" Invalid public key: "+ks);
1045 // Case 2: hex public key
1048 vector<unsigned char> vchPubKey = ParseHex(ks);
1049 if (vchPubKey.empty() || !pubkeys[i].SetPubKey(vchPubKey))
1050 throw runtime_error(" Invalid public key: "+ks);
1054 throw runtime_error(" Invalid public key: "+ks);
1058 // Construct using pay-to-script-hash:
1060 inner.SetMultisig(nRequired, pubkeys);
1062 uint160 scriptHash = Hash160(inner);
1063 CScript scriptPubKey;
1064 scriptPubKey.SetPayToScriptHash(inner);
1065 pwalletMain->AddCScript(inner);
1066 CBitcoinAddress address;
1067 address.SetScriptHash160(scriptHash);
1069 pwalletMain->SetAddressBookName(address, strAccount);
1070 return address.ToString();
1081 nConf = std::numeric_limits<int>::max();
1085 Value ListReceived(const Array& params, bool fByAccounts)
1087 // Minimum confirmations
1089 if (params.size() > 0)
1090 nMinDepth = params[0].get_int();
1092 // Whether to include empty accounts
1093 bool fIncludeEmpty = false;
1094 if (params.size() > 1)
1095 fIncludeEmpty = params[1].get_bool();
1098 map<CBitcoinAddress, tallyitem> mapTally;
1099 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1101 const CWalletTx& wtx = (*it).second;
1103 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
1106 int nDepth = wtx.GetDepthInMainChain();
1107 if (nDepth < nMinDepth)
1110 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
1112 CBitcoinAddress address;
1113 if (!ExtractAddress(txout.scriptPubKey, address) || !pwalletMain->HaveKey(address) || !address.IsValid())
1116 tallyitem& item = mapTally[address];
1117 item.nAmount += txout.nValue;
1118 item.nConf = min(item.nConf, nDepth);
1124 map<string, tallyitem> mapAccountTally;
1125 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
1127 const CBitcoinAddress& address = item.first;
1128 const string& strAccount = item.second;
1129 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
1130 if (it == mapTally.end() && !fIncludeEmpty)
1134 int nConf = std::numeric_limits<int>::max();
1135 if (it != mapTally.end())
1137 nAmount = (*it).second.nAmount;
1138 nConf = (*it).second.nConf;
1143 tallyitem& item = mapAccountTally[strAccount];
1144 item.nAmount += nAmount;
1145 item.nConf = min(item.nConf, nConf);
1150 obj.push_back(Pair("address", address.ToString()));
1151 obj.push_back(Pair("account", strAccount));
1152 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1153 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1160 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
1162 int64 nAmount = (*it).second.nAmount;
1163 int nConf = (*it).second.nConf;
1165 obj.push_back(Pair("account", (*it).first));
1166 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1167 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1175 Value listreceivedbyaddress(const Array& params, bool fHelp)
1177 if (fHelp || params.size() > 2)
1178 throw runtime_error(
1179 "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
1180 "[minconf] is the minimum number of confirmations before payments are included.\n"
1181 "[includeempty] whether to include addresses that haven't received any payments.\n"
1182 "Returns an array of objects containing:\n"
1183 " \"address\" : receiving address\n"
1184 " \"account\" : the account of the receiving address\n"
1185 " \"amount\" : total amount received by the address\n"
1186 " \"confirmations\" : number of confirmations of the most recent transaction included");
1188 return ListReceived(params, false);
1191 Value listreceivedbyaccount(const Array& params, bool fHelp)
1193 if (fHelp || params.size() > 2)
1194 throw runtime_error(
1195 "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
1196 "[minconf] is the minimum number of confirmations before payments are included.\n"
1197 "[includeempty] whether to include accounts that haven't received any payments.\n"
1198 "Returns an array of objects containing:\n"
1199 " \"account\" : the account of the receiving addresses\n"
1200 " \"amount\" : total amount received by addresses with this account\n"
1201 " \"confirmations\" : number of confirmations of the most recent transaction included");
1203 return ListReceived(params, true);
1206 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret)
1208 int64 nGeneratedImmature, nGeneratedMature, nFee;
1209 string strSentAccount;
1210 list<pair<CBitcoinAddress, int64> > listReceived;
1211 list<pair<CBitcoinAddress, int64> > listSent;
1213 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1215 bool fAllAccounts = (strAccount == string("*"));
1217 // Generated blocks assigned to account ""
1218 if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == ""))
1221 entry.push_back(Pair("account", string("")));
1222 if (nGeneratedImmature)
1224 entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
1225 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
1229 entry.push_back(Pair("category", "generate"));
1230 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
1233 WalletTxToJSON(wtx, entry);
1234 ret.push_back(entry);
1238 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1240 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1243 entry.push_back(Pair("account", strSentAccount));
1244 entry.push_back(Pair("address", s.first.ToString()));
1245 entry.push_back(Pair("category", "send"));
1246 entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1247 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1249 WalletTxToJSON(wtx, entry);
1250 ret.push_back(entry);
1255 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1257 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1260 if (pwalletMain->mapAddressBook.count(r.first))
1261 account = pwalletMain->mapAddressBook[r.first];
1262 if (fAllAccounts || (account == strAccount))
1265 entry.push_back(Pair("account", account));
1266 entry.push_back(Pair("address", r.first.ToString()));
1267 entry.push_back(Pair("category", "receive"));
1268 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1270 WalletTxToJSON(wtx, entry);
1271 ret.push_back(entry);
1277 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1279 bool fAllAccounts = (strAccount == string("*"));
1281 if (fAllAccounts || acentry.strAccount == strAccount)
1284 entry.push_back(Pair("account", acentry.strAccount));
1285 entry.push_back(Pair("category", "move"));
1286 entry.push_back(Pair("time", (boost::int64_t)acentry.nTime));
1287 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1288 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1289 entry.push_back(Pair("comment", acentry.strComment));
1290 ret.push_back(entry);
1294 Value listtransactions(const Array& params, bool fHelp)
1296 if (fHelp || params.size() > 3)
1297 throw runtime_error(
1298 "listtransactions [account] [count=10] [from=0]\n"
1299 "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1301 string strAccount = "*";
1302 if (params.size() > 0)
1303 strAccount = params[0].get_str();
1305 if (params.size() > 1)
1306 nCount = params[1].get_int();
1308 if (params.size() > 2)
1309 nFrom = params[2].get_int();
1312 throw JSONRPCError(-8, "Negative count");
1314 throw JSONRPCError(-8, "Negative from");
1317 CWalletDB walletdb(pwalletMain->strWalletFile);
1319 // First: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap.
1320 typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
1321 typedef multimap<int64, TxPair > TxItems;
1324 // Note: maintaining indices in the database of (account,time) --> txid and (account, time) --> acentry
1325 // would make this much faster for applications that do this a lot.
1326 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1328 CWalletTx* wtx = &((*it).second);
1329 txByTime.insert(make_pair(wtx->GetTxTime(), TxPair(wtx, (CAccountingEntry*)0)));
1331 list<CAccountingEntry> acentries;
1332 walletdb.ListAccountCreditDebit(strAccount, acentries);
1333 BOOST_FOREACH(CAccountingEntry& entry, acentries)
1335 txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
1338 // iterate backwards until we have nCount items to return:
1339 for (TxItems::reverse_iterator it = txByTime.rbegin(); it != txByTime.rend(); ++it)
1341 CWalletTx *const pwtx = (*it).second.first;
1343 ListTransactions(*pwtx, strAccount, 0, true, ret);
1344 CAccountingEntry *const pacentry = (*it).second.second;
1346 AcentryToJSON(*pacentry, strAccount, ret);
1348 if (ret.size() >= (nCount+nFrom)) break;
1350 // ret is newest to oldest
1352 if (nFrom > (int)ret.size())
1354 if ((nFrom + nCount) > (int)ret.size())
1355 nCount = ret.size() - nFrom;
1356 Array::iterator first = ret.begin();
1357 std::advance(first, nFrom);
1358 Array::iterator last = ret.begin();
1359 std::advance(last, nFrom+nCount);
1361 if (last != ret.end()) ret.erase(last, ret.end());
1362 if (first != ret.begin()) ret.erase(ret.begin(), first);
1364 std::reverse(ret.begin(), ret.end()); // Return oldest to newest
1369 Value listaccounts(const Array& params, bool fHelp)
1371 if (fHelp || params.size() > 1)
1372 throw runtime_error(
1373 "listaccounts [minconf=1]\n"
1374 "Returns Object that has account names as keys, account balances as values.");
1377 if (params.size() > 0)
1378 nMinDepth = params[0].get_int();
1380 map<string, int64> mapAccountBalances;
1381 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& entry, pwalletMain->mapAddressBook) {
1382 if (pwalletMain->HaveKey(entry.first)) // This address belongs to me
1383 mapAccountBalances[entry.second] = 0;
1386 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1388 const CWalletTx& wtx = (*it).second;
1389 int64 nGeneratedImmature, nGeneratedMature, nFee;
1390 string strSentAccount;
1391 list<pair<CBitcoinAddress, int64> > listReceived;
1392 list<pair<CBitcoinAddress, int64> > listSent;
1393 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1394 mapAccountBalances[strSentAccount] -= nFee;
1395 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1396 mapAccountBalances[strSentAccount] -= s.second;
1397 if (wtx.GetDepthInMainChain() >= nMinDepth)
1399 mapAccountBalances[""] += nGeneratedMature;
1400 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1401 if (pwalletMain->mapAddressBook.count(r.first))
1402 mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1404 mapAccountBalances[""] += r.second;
1408 list<CAccountingEntry> acentries;
1409 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1410 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1411 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1414 BOOST_FOREACH(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) {
1415 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1420 Value listsinceblock(const Array& params, bool fHelp)
1423 throw runtime_error(
1424 "listsinceblock [blockhash] [target-confirmations]\n"
1425 "Get all transactions in blocks since block [blockhash], or all transactions if omitted");
1427 CBlockIndex *pindex = NULL;
1428 int target_confirms = 1;
1430 if (params.size() > 0)
1432 uint256 blockId = 0;
1434 blockId.SetHex(params[0].get_str());
1435 pindex = CBlockLocator(blockId).GetBlockIndex();
1438 if (params.size() > 1)
1440 target_confirms = params[1].get_int();
1442 if (target_confirms < 1)
1443 throw JSONRPCError(-8, "Invalid parameter");
1446 int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1;
1450 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1452 CWalletTx tx = (*it).second;
1454 if (depth == -1 || tx.GetDepthInMainChain() < depth)
1455 ListTransactions(tx, "*", 0, true, transactions);
1460 if (target_confirms == 1)
1462 lastblock = hashBestChain;
1466 int target_height = pindexBest->nHeight + 1 - target_confirms;
1469 for (block = pindexBest;
1470 block && block->nHeight > target_height;
1471 block = block->pprev) { }
1473 lastblock = block ? block->GetBlockHash() : 0;
1477 ret.push_back(Pair("transactions", transactions));
1478 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1483 Value gettransaction(const Array& params, bool fHelp)
1485 if (fHelp || params.size() != 1)
1486 throw runtime_error(
1487 "gettransaction <txid>\n"
1488 "Get detailed information about <txid>");
1491 hash.SetHex(params[0].get_str());
1495 if (!pwalletMain->mapWallet.count(hash))
1496 throw JSONRPCError(-5, "Invalid or non-wallet transaction id");
1497 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1499 int64 nCredit = wtx.GetCredit();
1500 int64 nDebit = wtx.GetDebit();
1501 int64 nNet = nCredit - nDebit;
1502 int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
1504 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1506 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1508 WalletTxToJSON(pwalletMain->mapWallet[hash], entry);
1511 ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
1512 entry.push_back(Pair("details", details));
1518 Value backupwallet(const Array& params, bool fHelp)
1520 if (fHelp || params.size() != 1)
1521 throw runtime_error(
1522 "backupwallet <destination>\n"
1523 "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1525 string strDest = params[0].get_str();
1526 BackupWallet(*pwalletMain, strDest);
1532 Value keypoolrefill(const Array& params, bool fHelp)
1534 if (pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1535 throw runtime_error(
1537 "Fills the keypool, requires wallet passphrase to be set.");
1538 if (!pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1539 throw runtime_error(
1541 "Fills the keypool.");
1543 if (pwalletMain->IsLocked())
1544 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
1546 pwalletMain->TopUpKeyPool();
1548 if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100))
1549 throw JSONRPCError(-4, "Error refreshing keypool.");
1555 void ThreadTopUpKeyPool(void* parg)
1557 pwalletMain->TopUpKeyPool();
1560 void ThreadCleanWalletPassphrase(void* parg)
1562 int64 nMyWakeTime = GetTimeMillis() + *((int64*)parg) * 1000;
1564 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1566 if (nWalletUnlockTime == 0)
1568 nWalletUnlockTime = nMyWakeTime;
1572 if (nWalletUnlockTime==0)
1574 int64 nToSleep = nWalletUnlockTime - GetTimeMillis();
1578 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1580 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1584 if (nWalletUnlockTime)
1586 nWalletUnlockTime = 0;
1587 pwalletMain->Lock();
1592 if (nWalletUnlockTime < nMyWakeTime)
1593 nWalletUnlockTime = nMyWakeTime;
1596 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1598 delete (int64*)parg;
1601 Value walletpassphrase(const Array& params, bool fHelp)
1603 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 3))
1604 throw runtime_error(
1605 "walletpassphrase <passphrase> <timeout> [mintonly]\n"
1606 "Stores the wallet decryption key in memory for <timeout> seconds.\n"
1607 "mintonly is optional true/false allowing only block minting.");
1610 if (!pwalletMain->IsCrypted())
1611 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1613 if (!pwalletMain->IsLocked())
1614 throw JSONRPCError(-17, "Error: Wallet is already unlocked, use walletlock first if need to change unlock settings.");
1616 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1617 SecureString strWalletPass;
1618 strWalletPass.reserve(100);
1619 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1620 // Alternately, find a way to make params[0] mlock()'d to begin with.
1621 strWalletPass = params[0].get_str().c_str();
1623 if (strWalletPass.length() > 0)
1625 if (!pwalletMain->Unlock(strWalletPass))
1626 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1629 throw runtime_error(
1630 "walletpassphrase <passphrase> <timeout>\n"
1631 "Stores the wallet decryption key in memory for <timeout> seconds.");
1633 CreateThread(ThreadTopUpKeyPool, NULL);
1634 int64* pnSleepTime = new int64(params[1].get_int64());
1635 CreateThread(ThreadCleanWalletPassphrase, pnSleepTime);
1637 // ppcoin: if user OS account compromised prevent trivial sendmoney commands
1638 if (params.size() > 2)
1639 fWalletUnlockMintOnly = params[2].get_bool();
1641 fWalletUnlockMintOnly = false;
1647 Value walletpassphrasechange(const Array& params, bool fHelp)
1649 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1650 throw runtime_error(
1651 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1652 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1655 if (!pwalletMain->IsCrypted())
1656 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1658 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1659 // Alternately, find a way to make params[0] mlock()'d to begin with.
1660 SecureString strOldWalletPass;
1661 strOldWalletPass.reserve(100);
1662 strOldWalletPass = params[0].get_str().c_str();
1664 SecureString strNewWalletPass;
1665 strNewWalletPass.reserve(100);
1666 strNewWalletPass = params[1].get_str().c_str();
1668 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1669 throw runtime_error(
1670 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1671 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1673 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1674 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1680 Value walletlock(const Array& params, bool fHelp)
1682 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1683 throw runtime_error(
1685 "Removes the wallet encryption key from memory, locking the wallet.\n"
1686 "After calling this method, you will need to call walletpassphrase again\n"
1687 "before being able to call any methods which require the wallet to be unlocked.");
1690 if (!pwalletMain->IsCrypted())
1691 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called.");
1694 LOCK(cs_nWalletUnlockTime);
1695 pwalletMain->Lock();
1696 nWalletUnlockTime = 0;
1703 Value encryptwallet(const Array& params, bool fHelp)
1705 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1706 throw runtime_error(
1707 "encryptwallet <passphrase>\n"
1708 "Encrypts the wallet with <passphrase>.");
1711 if (pwalletMain->IsCrypted())
1712 throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
1714 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1715 // Alternately, find a way to make params[0] mlock()'d to begin with.
1716 SecureString strWalletPass;
1717 strWalletPass.reserve(100);
1718 strWalletPass = params[0].get_str().c_str();
1720 if (strWalletPass.length() < 1)
1721 throw runtime_error(
1722 "encryptwallet <passphrase>\n"
1723 "Encrypts the wallet with <passphrase>.");
1725 if (!pwalletMain->EncryptWallet(strWalletPass))
1726 throw JSONRPCError(-16, "Error: Failed to encrypt the wallet.");
1728 // BDB seems to have a bad habit of writing old data into
1729 // slack space in .dat files; that is bad if the old data is
1730 // unencrypted private keys. So:
1732 return "wallet encrypted; ppcoin server stopping, restart to run with encrypted wallet";
1736 Value validateaddress(const Array& params, bool fHelp)
1738 if (fHelp || params.size() != 1)
1739 throw runtime_error(
1740 "validateaddress <ppcoinaddress>\n"
1741 "Return information about <ppcoinaddress>.");
1743 CBitcoinAddress address(params[0].get_str());
1744 bool isValid = address.IsValid();
1747 ret.push_back(Pair("isvalid", isValid));
1750 // Call Hash160ToAddress() so we always return current ADDRESSVERSION
1751 // version of the address:
1752 string currentAddress = address.ToString();
1753 ret.push_back(Pair("address", currentAddress));
1754 if (pwalletMain->HaveKey(address))
1756 ret.push_back(Pair("ismine", true));
1757 std::vector<unsigned char> vchPubKey;
1758 pwalletMain->GetPubKey(address, vchPubKey);
1759 ret.push_back(Pair("pubkey", HexStr(vchPubKey)));
1761 key.SetPubKey(vchPubKey);
1762 ret.push_back(Pair("iscompressed", key.IsCompressed()));
1764 else if (pwalletMain->HaveCScript(address.GetHash160()))
1766 ret.push_back(Pair("isscript", true));
1768 pwalletMain->GetCScript(address.GetHash160(), subscript);
1769 ret.push_back(Pair("ismine", ::IsMine(*pwalletMain, subscript)));
1770 std::vector<CBitcoinAddress> addresses;
1771 txnouttype whichType;
1773 ExtractAddresses(subscript, whichType, addresses, nRequired);
1774 ret.push_back(Pair("script", GetTxnOutputType(whichType)));
1776 BOOST_FOREACH(const CBitcoinAddress& addr, addresses)
1777 a.push_back(addr.ToString());
1778 ret.push_back(Pair("addresses", a));
1779 if (whichType == TX_MULTISIG)
1780 ret.push_back(Pair("sigsrequired", nRequired));
1783 ret.push_back(Pair("ismine", false));
1784 if (pwalletMain->mapAddressBook.count(address))
1785 ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
1790 Value getwork(const Array& params, bool fHelp)
1792 if (fHelp || params.size() > 1)
1793 throw runtime_error(
1795 "If [data] is not specified, returns formatted hash data to work on:\n"
1796 " \"midstate\" : precomputed hash state after hashing the first half of the data (DEPRECATED)\n" // deprecated
1797 " \"data\" : block data\n"
1798 " \"hash1\" : formatted hash buffer for second hash (DEPRECATED)\n" // deprecated
1799 " \"target\" : little endian hash target\n"
1800 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1803 throw JSONRPCError(-9, "PPCoin is not connected!");
1805 if (IsInitialBlockDownload())
1806 throw JSONRPCError(-10, "PPCoin is downloading blocks...");
1808 typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
1809 static mapNewBlock_t mapNewBlock;
1810 static vector<CBlock*> vNewBlock;
1811 static CReserveKey reservekey(pwalletMain);
1813 if (params.size() == 0)
1816 static unsigned int nTransactionsUpdatedLast;
1817 static CBlockIndex* pindexPrev;
1818 static int64 nStart;
1819 static CBlock* pblock;
1820 if (pindexPrev != pindexBest ||
1821 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
1823 if (pindexPrev != pindexBest)
1825 // Deallocate old blocks since they're obsolete now
1826 mapNewBlock.clear();
1827 BOOST_FOREACH(CBlock* pblock, vNewBlock)
1831 nTransactionsUpdatedLast = nTransactionsUpdated;
1832 pindexPrev = pindexBest;
1836 pblock = CreateNewBlock(pwalletMain);
1838 throw JSONRPCError(-7, "Out of memory");
1839 vNewBlock.push_back(pblock);
1843 pblock->UpdateTime(pindexPrev);
1846 // Update nExtraNonce
1847 static unsigned int nExtraNonce = 0;
1848 IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
1851 mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
1853 // Prebuild hash buffers
1857 FormatHashBuffers(pblock, pmidstate, pdata, phash1);
1859 uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
1862 result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate)))); // deprecated
1863 result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata))));
1864 result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1)))); // deprecated
1865 result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
1871 vector<unsigned char> vchData = ParseHex(params[0].get_str());
1872 if (vchData.size() != 128)
1873 throw JSONRPCError(-8, "Invalid parameter");
1874 CBlock* pdata = (CBlock*)&vchData[0];
1877 for (int i = 0; i < 128/4; i++)
1878 ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]);
1881 if (!mapNewBlock.count(pdata->hashMerkleRoot))
1883 CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
1885 pblock->nTime = pdata->nTime;
1886 pblock->nNonce = pdata->nNonce;
1887 pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
1888 pblock->hashMerkleRoot = pblock->BuildMerkleTree();
1889 if (!pblock->SignBlock(*pwalletMain))
1890 throw JSONRPCError(-100, "Unable to sign block, wallet locked?");
1892 return CheckWork(pblock, *pwalletMain, reservekey);
1897 Value getmemorypool(const Array& params, bool fHelp)
1899 if (fHelp || params.size() > 1)
1900 throw runtime_error(
1901 "getmemorypool [data]\n"
1902 "If [data] is not specified, returns data needed to construct a block to work on:\n"
1903 " \"version\" : block version\n"
1904 " \"previousblockhash\" : hash of current highest block\n"
1905 " \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
1906 " \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
1907 " \"coinbaseflags\" : data that should be included in coinbase so support for new features can be judged\n"
1908 " \"time\" : timestamp appropriate for next block\n"
1909 " \"mintime\" : minimum timestamp appropriate for next block\n"
1910 " \"curtime\" : current timestamp\n"
1911 " \"bits\" : compressed target of next block\n"
1912 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1914 if (params.size() == 0)
1917 throw JSONRPCError(-9, "PPCoin is not connected!");
1919 if (IsInitialBlockDownload())
1920 throw JSONRPCError(-10, "PPCoin is downloading blocks...");
1922 static CReserveKey reservekey(pwalletMain);
1925 static unsigned int nTransactionsUpdatedLast;
1926 static CBlockIndex* pindexPrev;
1927 static int64 nStart;
1928 static CBlock* pblock;
1929 if (pindexPrev != pindexBest ||
1930 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5))
1932 nTransactionsUpdatedLast = nTransactionsUpdated;
1933 pindexPrev = pindexBest;
1939 pblock = CreateNewBlock(pwalletMain);
1941 throw JSONRPCError(-7, "Out of memory");
1945 pblock->UpdateTime(pindexPrev);
1949 BOOST_FOREACH(CTransaction tx, pblock->vtx) {
1950 if(tx.IsCoinBase() || tx.IsCoinStake())
1953 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
1956 transactions.push_back(HexStr(ssTx.begin(), ssTx.end()));
1960 result.push_back(Pair("version", pblock->nVersion));
1961 result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
1962 result.push_back(Pair("transactions", transactions));
1963 result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
1964 result.push_back(Pair("coinbaseflags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end())));
1965 result.push_back(Pair("time", (int64_t)pblock->nTime));
1966 result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1));
1967 result.push_back(Pair("curtime", (int64_t)GetAdjustedTime()));
1968 result.push_back(Pair("bits", HexBits(pblock->nBits)));
1975 CDataStream ssBlock(ParseHex(params[0].get_str()), SER_NETWORK, PROTOCOL_VERSION);
1979 return ProcessBlock(NULL, &pblock);
1983 Value getblockhash(const Array& params, bool fHelp)
1985 if (fHelp || params.size() != 1)
1986 throw runtime_error(
1987 "getblockhash <index>\n"
1988 "Returns hash of block in best-block-chain at <index>.");
1990 int nHeight = params[0].get_int();
1991 if (nHeight < 0 || nHeight > nBestHeight)
1992 throw runtime_error("Block number out of range.");
1995 CBlockIndex* pblockindex = mapBlockIndex[hashBestChain];
1996 while (pblockindex->nHeight > nHeight)
1997 pblockindex = pblockindex->pprev;
1998 return pblockindex->phashBlock->GetHex();
2001 Value getblock(const Array& params, bool fHelp)
2003 if (fHelp || params.size() != 1)
2004 throw runtime_error(
2006 "Returns details of a block with given block-hash.");
2008 std::string strHash = params[0].get_str();
2009 uint256 hash(strHash);
2011 if (mapBlockIndex.count(hash) == 0)
2012 throw JSONRPCError(-5, "Block not found");
2015 CBlockIndex* pblockindex = mapBlockIndex[hash];
2016 block.ReadFromDisk(pblockindex, true);
2018 return blockToJSON(block, pblockindex);
2022 // ppcoin: get information of sync-checkpoint
2023 Value getcheckpoint(const Array& params, bool fHelp)
2025 if (fHelp || params.size() != 0)
2026 throw runtime_error(
2028 "Show info of synchronized checkpoint.\n");
2031 CBlockIndex* pindexCheckpoint;
2033 result.push_back(Pair("synccheckpoint", Checkpoints::hashSyncCheckpoint.ToString().c_str()));
2034 pindexCheckpoint = mapBlockIndex[Checkpoints::hashSyncCheckpoint];
2035 result.push_back(Pair("height", pindexCheckpoint->nHeight));
2036 result.push_back(Pair("timestamp", DateTimeStrFormat(pindexCheckpoint->GetBlockTime()).c_str()));
2037 if (mapArgs.count("-checkpointkey"))
2038 result.push_back(Pair("checkpointmaster", true));
2044 // ppcoin: reserve balance from being staked for network protection
2045 Value reservebalance(const Array& params, bool fHelp)
2047 if (fHelp || params.size() > 2)
2048 throw runtime_error(
2049 "reservebalance [<reserve> [amount]]\n"
2050 "<reserve> is true or false to turn balance reserve on or off.\n"
2051 "<amount> is a real and rounded to cent.\n"
2052 "Set reserve amount not participating in network protection.\n"
2053 "If no parameters provided current setting is printed.\n");
2055 if (params.size() > 0)
2057 bool fReserve = params[0].get_bool();
2060 if (params.size() == 1)
2061 throw runtime_error("must provide amount to reserve balance.\n");
2062 int64 nAmount = AmountFromValue(params[1]);
2063 nAmount = (nAmount / CENT) * CENT; // round to cent
2065 throw runtime_error("amount cannot be negative.\n");
2066 mapArgs["-reservebalance"] = FormatMoney(nAmount).c_str();
2070 if (params.size() > 1)
2071 throw runtime_error("cannot specify amount to turn off reserve.\n");
2072 mapArgs["-reservebalance"] = "0";
2077 int64 nReserveBalance = 0;
2078 if (mapArgs.count("-reservebalance") && !ParseMoney(mapArgs["-reservebalance"], nReserveBalance))
2079 throw runtime_error("invalid reserve balance amount\n");
2080 result.push_back(Pair("reserve", (nReserveBalance > 0)));
2081 result.push_back(Pair("amount", ValueFromAmount(nReserveBalance)));
2086 // ppcoin: check wallet integrity
2087 Value checkwallet(const Array& params, bool fHelp)
2089 if (fHelp || params.size() > 0)
2090 throw runtime_error(
2092 "Check wallet for integrity.\n");
2095 int64 nBalanceInQuestion;
2096 if (!pwalletMain->CheckSpentCoins(nMismatchSpent, nBalanceInQuestion))
2099 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
2100 result.push_back(Pair("amount in question", ValueFromAmount(nBalanceInQuestion)));
2107 // ppcoin: repair wallet
2108 Value repairwallet(const Array& params, bool fHelp)
2110 if (fHelp || params.size() > 0)
2111 throw runtime_error(
2113 "Repair wallet if checkwallet reports any problem.\n");
2116 int64 nBalanceInQuestion;
2117 pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion);
2119 if (nMismatchSpent == 0)
2121 result.push_back(Pair("wallet check passed", true));
2125 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
2126 result.push_back(Pair("amount affected by repair", ValueFromAmount(nBalanceInQuestion)));
2131 // ppcoin: make a public-private key pair
2132 Value makekeypair(const Array& params, bool fHelp)
2134 if (fHelp || params.size() > 1)
2135 throw runtime_error(
2136 "makekeypair [prefix]\n"
2137 "Make a public/private key pair.\n"
2138 "[prefix] is optional preferred prefix for the public key.\n");
2140 string strPrefix = "";
2141 if (params.size() > 0)
2142 strPrefix = params[0].get_str();
2148 key.MakeNewKey(false);
2150 } while (nCount < 10000 && strPrefix != HexStr(key.GetPubKey()).substr(0, strPrefix.size()));
2152 if (strPrefix != HexStr(key.GetPubKey()).substr(0, strPrefix.size()))
2155 CPrivKey vchPrivKey = key.GetPrivKey();
2157 result.push_back(Pair("PrivateKey", HexStr<CPrivKey::iterator>(vchPrivKey.begin(), vchPrivKey.end())));
2158 result.push_back(Pair("PublicKey", HexStr(key.GetPubKey())));
2162 extern CCriticalSection cs_mapAlerts;
2163 extern map<uint256, CAlert> mapAlerts;
2165 // ppcoin: send alert.
2166 // There is a known deadlock situation with ThreadMessageHandler
2167 // ThreadMessageHandler: holds cs_vSend and acquiring cs_main in SendMessages()
2168 // ThreadRPCServer: holds cs_main and acquiring cs_vSend in alert.RelayTo()/PushMessage()/BeginMessage()
2169 Value sendalert(const Array& params, bool fHelp)
2171 if (fHelp || params.size() < 6)
2172 throw runtime_error(
2173 "sendalert <message> <privatekey> <minver> <maxver> <priority> <id> [cancelupto]\n"
2174 "<message> is the alert text message\n"
2175 "<privatekey> is hex string of alert master private key\n"
2176 "<minver> is the minimum applicable internal client version\n"
2177 "<maxver> is the maximum applicable internal client version\n"
2178 "<priority> is integer priority number\n"
2179 "<id> is the alert id\n"
2180 "[cancelupto] cancels all alert id's up to this number\n"
2181 "Returns true or false.");
2186 alert.strStatusBar = params[0].get_str();
2187 alert.nMinVer = params[2].get_int();
2188 alert.nMaxVer = params[3].get_int();
2189 alert.nPriority = params[4].get_int();
2190 alert.nID = params[5].get_int();
2191 if (params.size() > 6)
2192 alert.nCancel = params[6].get_int();
2193 alert.nVersion = PROTOCOL_VERSION;
2194 alert.nRelayUntil = GetAdjustedTime() + 365*24*60*60;
2195 alert.nExpiration = GetAdjustedTime() + 365*24*60*60;
2197 CDataStream sMsg(SER_NETWORK, PROTOCOL_VERSION);
2198 sMsg << (CUnsignedAlert)alert;
2199 alert.vchMsg = vector<unsigned char>(sMsg.begin(), sMsg.end());
2201 vector<unsigned char> vchPrivKey = ParseHex(params[1].get_str());
2202 key.SetPrivKey(CPrivKey(vchPrivKey.begin(), vchPrivKey.end())); // if key is not correct openssl may crash
2203 if (!key.Sign(Hash(alert.vchMsg.begin(), alert.vchMsg.end()), alert.vchSig))
2204 throw runtime_error(
2205 "Unable to sign alert, check private key?\n");
2206 if(!alert.ProcessAlert())
2207 throw runtime_error(
2208 "Failed to process alert.\n");
2212 BOOST_FOREACH(CNode* pnode, vNodes)
2213 alert.RelayTo(pnode);
2217 result.push_back(Pair("strStatusBar", alert.strStatusBar));
2218 result.push_back(Pair("nVersion", alert.nVersion));
2219 result.push_back(Pair("nMinVer", alert.nMinVer));
2220 result.push_back(Pair("nMaxVer", alert.nMaxVer));
2221 result.push_back(Pair("nPriority", alert.nPriority));
2222 result.push_back(Pair("nID", alert.nID));
2223 if (alert.nCancel > 0)
2224 result.push_back(Pair("nCancel", alert.nCancel));
2235 static const CRPCCommand vRPCCommands[] =
2236 { // name function safe mode?
2237 // ------------------------ ----------------------- ----------
2238 { "help", &help, true },
2239 { "stop", &stop, true },
2240 { "getblockcount", &getblockcount, true },
2241 { "getblocknumber", &getblocknumber, true },
2242 { "getconnectioncount", &getconnectioncount, true },
2243 { "getdifficulty", &getdifficulty, true },
2244 { "getgenerate", &getgenerate, true },
2245 { "setgenerate", &setgenerate, true },
2246 { "gethashespersec", &gethashespersec, true },
2247 { "getinfo", &getinfo, true },
2248 { "getmininginfo", &getmininginfo, true },
2249 { "getnewaddress", &getnewaddress, true },
2250 { "getaccountaddress", &getaccountaddress, true },
2251 { "setaccount", &setaccount, true },
2252 { "getaccount", &getaccount, false },
2253 { "getaddressesbyaccount", &getaddressesbyaccount, true },
2254 { "sendtoaddress", &sendtoaddress, false },
2255 { "getreceivedbyaddress", &getreceivedbyaddress, false },
2256 { "getreceivedbyaccount", &getreceivedbyaccount, false },
2257 { "listreceivedbyaddress", &listreceivedbyaddress, false },
2258 { "listreceivedbyaccount", &listreceivedbyaccount, false },
2259 { "backupwallet", &backupwallet, true },
2260 { "keypoolrefill", &keypoolrefill, true },
2261 { "walletpassphrase", &walletpassphrase, true },
2262 { "walletpassphrasechange", &walletpassphrasechange, false },
2263 { "walletlock", &walletlock, true },
2264 { "encryptwallet", &encryptwallet, false },
2265 { "validateaddress", &validateaddress, true },
2266 { "getbalance", &getbalance, false },
2267 { "move", &movecmd, false },
2268 { "sendfrom", &sendfrom, false },
2269 { "sendmany", &sendmany, false },
2270 { "addmultisigaddress", &addmultisigaddress, false },
2271 { "getblock", &getblock, false },
2272 { "getblockhash", &getblockhash, false },
2273 { "gettransaction", &gettransaction, false },
2274 { "listtransactions", &listtransactions, false },
2275 { "signmessage", &signmessage, false },
2276 { "verifymessage", &verifymessage, false },
2277 { "getwork", &getwork, true },
2278 { "listaccounts", &listaccounts, false },
2279 { "settxfee", &settxfee, false },
2280 { "getmemorypool", &getmemorypool, true },
2281 { "listsinceblock", &listsinceblock, false },
2282 { "dumpprivkey", &dumpprivkey, false },
2283 { "importprivkey", &importprivkey, false },
2284 { "getcheckpoint", &getcheckpoint, true },
2285 { "reservebalance", &reservebalance, false},
2286 { "checkwallet", &checkwallet, false},
2287 { "repairwallet", &repairwallet, false},
2288 { "makekeypair", &makekeypair, false},
2289 { "sendalert", &sendalert, false},
2292 CRPCTable::CRPCTable()
2295 for (vcidx = 0; vcidx < (sizeof(vRPCCommands) / sizeof(vRPCCommands[0])); vcidx++)
2297 const CRPCCommand *pcmd;
2299 pcmd = &vRPCCommands[vcidx];
2300 mapCommands[pcmd->name] = pcmd;
2304 const CRPCCommand *CRPCTable::operator[](string name) const
2306 map<string, const CRPCCommand*>::const_iterator it = mapCommands.find(name);
2307 if (it == mapCommands.end())
2309 return (*it).second;
2315 // This ain't Apache. We're just using HTTP header for the length field
2316 // and to be compatible with other JSON-RPC implementations.
2319 string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
2322 s << "POST / HTTP/1.1\r\n"
2323 << "User-Agent: ppcoin-json-rpc/" << FormatFullVersion() << "\r\n"
2324 << "Host: 127.0.0.1\r\n"
2325 << "Content-Type: application/json\r\n"
2326 << "Content-Length: " << strMsg.size() << "\r\n"
2327 << "Connection: close\r\n"
2328 << "Accept: application/json\r\n";
2329 BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
2330 s << item.first << ": " << item.second << "\r\n";
2331 s << "\r\n" << strMsg;
2336 string rfc1123Time()
2341 struct tm* now_gmt = gmtime(&now);
2342 string locale(setlocale(LC_TIME, NULL));
2343 setlocale(LC_TIME, "C"); // we want posix (aka "C") weekday/month strings
2344 strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt);
2345 setlocale(LC_TIME, locale.c_str());
2346 return string(buffer);
2349 static string HTTPReply(int nStatus, const string& strMsg)
2352 return strprintf("HTTP/1.0 401 Authorization Required\r\n"
2354 "Server: ppcoin-json-rpc/%s\r\n"
2355 "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
2356 "Content-Type: text/html\r\n"
2357 "Content-Length: 296\r\n"
2359 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
2360 "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
2363 "<TITLE>Error</TITLE>\r\n"
2364 "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
2366 "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
2367 "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
2368 const char *cStatus;
2369 if (nStatus == 200) cStatus = "OK";
2370 else if (nStatus == 400) cStatus = "Bad Request";
2371 else if (nStatus == 403) cStatus = "Forbidden";
2372 else if (nStatus == 404) cStatus = "Not Found";
2373 else if (nStatus == 500) cStatus = "Internal Server Error";
2376 "HTTP/1.1 %d %s\r\n"
2378 "Connection: close\r\n"
2379 "Content-Length: %d\r\n"
2380 "Content-Type: application/json\r\n"
2381 "Server: ppcoin-json-rpc/%s\r\n"
2386 rfc1123Time().c_str(),
2388 FormatFullVersion().c_str(),
2392 int ReadHTTPStatus(std::basic_istream<char>& stream)
2395 getline(stream, str);
2396 vector<string> vWords;
2397 boost::split(vWords, str, boost::is_any_of(" "));
2398 if (vWords.size() < 2)
2400 return atoi(vWords[1].c_str());
2403 int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
2409 std::getline(stream, str);
2410 if (str.empty() || str == "\r")
2412 string::size_type nColon = str.find(":");
2413 if (nColon != string::npos)
2415 string strHeader = str.substr(0, nColon);
2416 boost::trim(strHeader);
2417 boost::to_lower(strHeader);
2418 string strValue = str.substr(nColon+1);
2419 boost::trim(strValue);
2420 mapHeadersRet[strHeader] = strValue;
2421 if (strHeader == "content-length")
2422 nLen = atoi(strValue.c_str());
2428 int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
2430 mapHeadersRet.clear();
2434 int nStatus = ReadHTTPStatus(stream);
2437 int nLen = ReadHTTPHeader(stream, mapHeadersRet);
2438 if (nLen < 0 || nLen > (int)MAX_SIZE)
2444 vector<char> vch(nLen);
2445 stream.read(&vch[0], nLen);
2446 strMessageRet = string(vch.begin(), vch.end());
2452 bool HTTPAuthorized(map<string, string>& mapHeaders)
2454 string strAuth = mapHeaders["authorization"];
2455 if (strAuth.substr(0,6) != "Basic ")
2457 string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
2458 string strUserPass = DecodeBase64(strUserPass64);
2459 return strUserPass == strRPCUserColonPass;
2463 // JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
2464 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
2465 // unspecified (HTTP errors and contents of 'error').
2467 // 1.0 spec: http://json-rpc.org/wiki/specification
2468 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
2469 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
2472 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
2475 request.push_back(Pair("method", strMethod));
2476 request.push_back(Pair("params", params));
2477 request.push_back(Pair("id", id));
2478 return write_string(Value(request), false) + "\n";
2481 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
2484 if (error.type() != null_type)
2485 reply.push_back(Pair("result", Value::null));
2487 reply.push_back(Pair("result", result));
2488 reply.push_back(Pair("error", error));
2489 reply.push_back(Pair("id", id));
2490 return write_string(Value(reply), false) + "\n";
2493 void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
2495 // Send error reply from json-rpc error object
2497 int code = find_value(objError, "code").get_int();
2498 if (code == -32600) nStatus = 400;
2499 else if (code == -32601) nStatus = 404;
2500 string strReply = JSONRPCReply(Value::null, objError, id);
2501 stream << HTTPReply(nStatus, strReply) << std::flush;
2504 bool ClientAllowed(const string& strAddress)
2506 if (strAddress == asio::ip::address_v4::loopback().to_string())
2508 const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
2509 BOOST_FOREACH(string strAllow, vAllow)
2510 if (WildcardMatch(strAddress, strAllow))
2516 // IOStream device that speaks SSL but can also speak non-SSL
2518 class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
2520 SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
2522 fUseSSL = fUseSSLIn;
2523 fNeedHandshake = fUseSSLIn;
2526 void handshake(ssl::stream_base::handshake_type role)
2528 if (!fNeedHandshake) return;
2529 fNeedHandshake = false;
2530 stream.handshake(role);
2532 std::streamsize read(char* s, std::streamsize n)
2534 handshake(ssl::stream_base::server); // HTTPS servers read first
2535 if (fUseSSL) return stream.read_some(asio::buffer(s, n));
2536 return stream.next_layer().read_some(asio::buffer(s, n));
2538 std::streamsize write(const char* s, std::streamsize n)
2540 handshake(ssl::stream_base::client); // HTTPS clients write first
2541 if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
2542 return asio::write(stream.next_layer(), asio::buffer(s, n));
2544 bool connect(const std::string& server, const std::string& port)
2546 ip::tcp::resolver resolver(stream.get_io_service());
2547 ip::tcp::resolver::query query(server.c_str(), port.c_str());
2548 ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
2549 ip::tcp::resolver::iterator end;
2550 boost::system::error_code error = asio::error::host_not_found;
2551 while (error && endpoint_iterator != end)
2553 stream.lowest_layer().close();
2554 stream.lowest_layer().connect(*endpoint_iterator++, error);
2562 bool fNeedHandshake;
2567 void ThreadRPCServer(void* parg)
2569 IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
2572 vnThreadsRunning[THREAD_RPCSERVER]++;
2573 ThreadRPCServer2(parg);
2574 vnThreadsRunning[THREAD_RPCSERVER]--;
2576 catch (std::exception& e) {
2577 vnThreadsRunning[THREAD_RPCSERVER]--;
2578 PrintException(&e, "ThreadRPCServer()");
2580 vnThreadsRunning[THREAD_RPCSERVER]--;
2581 PrintException(NULL, "ThreadRPCServer()");
2583 printf("ThreadRPCServer exiting\n");
2586 void ThreadRPCServer2(void* parg)
2588 printf("ThreadRPCServer started\n");
2590 strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
2591 if (mapArgs["-rpcpassword"] == "")
2593 unsigned char rand_pwd[32];
2594 RAND_bytes(rand_pwd, 32);
2595 string strWhatAmI = "To use ppcoind";
2596 if (mapArgs.count("-server"))
2597 strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
2598 else if (mapArgs.count("-daemon"))
2599 strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
2600 ThreadSafeMessageBox(strprintf(
2601 _("%s, you must set a rpcpassword in the configuration file:\n %s\n"
2602 "It is recommended you use the following random password:\n"
2603 "rpcuser=bitcoinrpc\n"
2605 "(you do not need to remember this password)\n"
2606 "If the file does not exist, create it with owner-readable-only file permissions.\n"),
2608 GetConfigFile().string().c_str(),
2609 EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str()),
2610 _("Error"), wxOK | wxMODAL);
2615 bool fUseSSL = GetBoolArg("-rpcssl");
2616 asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
2618 asio::io_service io_service;
2619 ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", RPC_PORT));
2620 ip::tcp::acceptor acceptor(io_service);
2623 acceptor.open(endpoint.protocol());
2624 acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
2625 acceptor.bind(endpoint);
2626 acceptor.listen(socket_base::max_connections);
2628 catch(boost::system::system_error &e)
2630 ThreadSafeMessageBox(strprintf(_("An error occured while setting up the RPC port %i for listening: %s"), endpoint.port(), e.what()),
2631 _("Error"), wxOK | wxMODAL);
2636 ssl::context context(io_service, ssl::context::sslv23);
2639 context.set_options(ssl::context::no_sslv2);
2641 filesystem::path pathCertFile(GetArg("-rpcsslcertificatechainfile", "server.cert"));
2642 if (!pathCertFile.is_complete()) pathCertFile = filesystem::path(GetDataDir()) / pathCertFile;
2643 if (filesystem::exists(pathCertFile)) context.use_certificate_chain_file(pathCertFile.string());
2644 else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", pathCertFile.string().c_str());
2646 filesystem::path pathPKFile(GetArg("-rpcsslprivatekeyfile", "server.pem"));
2647 if (!pathPKFile.is_complete()) pathPKFile = filesystem::path(GetDataDir()) / pathPKFile;
2648 if (filesystem::exists(pathPKFile)) context.use_private_key_file(pathPKFile.string(), ssl::context::pem);
2649 else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pathPKFile.string().c_str());
2651 string strCiphers = GetArg("-rpcsslciphers", "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
2652 SSL_CTX_set_cipher_list(context.impl(), strCiphers.c_str());
2657 // Accept connection
2658 SSLStream sslStream(io_service, context);
2659 SSLIOStreamDevice d(sslStream, fUseSSL);
2660 iostreams::stream<SSLIOStreamDevice> stream(d);
2662 ip::tcp::endpoint peer;
2663 vnThreadsRunning[THREAD_RPCSERVER]--;
2664 acceptor.accept(sslStream.lowest_layer(), peer);
2665 vnThreadsRunning[4]++;
2669 // Restrict callers by IP
2670 if (!ClientAllowed(peer.address().to_string()))
2672 // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
2674 stream << HTTPReply(403, "") << std::flush;
2678 map<string, string> mapHeaders;
2681 boost::thread api_caller(ReadHTTP, boost::ref(stream), boost::ref(mapHeaders), boost::ref(strRequest));
2682 if (!api_caller.timed_join(boost::posix_time::seconds(GetArg("-rpctimeout", 30))))
2685 printf("ThreadRPCServer ReadHTTP timeout\n");
2689 // Check authorization
2690 if (mapHeaders.count("authorization") == 0)
2692 stream << HTTPReply(401, "") << std::flush;
2695 if (!HTTPAuthorized(mapHeaders))
2697 printf("ThreadRPCServer incorrect password attempt from %s\n",peer.address().to_string().c_str());
2698 /* Deter brute-forcing short passwords.
2699 If this results in a DOS the user really
2700 shouldn't have their RPC port exposed.*/
2701 if (mapArgs["-rpcpassword"].size() < 20)
2704 stream << HTTPReply(401, "") << std::flush;
2708 Value id = Value::null;
2713 if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
2714 throw JSONRPCError(-32700, "Parse error");
2715 const Object& request = valRequest.get_obj();
2717 // Parse id now so errors from here on will have the id
2718 id = find_value(request, "id");
2721 Value valMethod = find_value(request, "method");
2722 if (valMethod.type() == null_type)
2723 throw JSONRPCError(-32600, "Missing method");
2724 if (valMethod.type() != str_type)
2725 throw JSONRPCError(-32600, "Method must be a string");
2726 string strMethod = valMethod.get_str();
2727 if (strMethod != "getwork" && strMethod != "getmemorypool")
2728 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
2731 Value valParams = find_value(request, "params");
2733 if (valParams.type() == array_type)
2734 params = valParams.get_array();
2735 else if (valParams.type() == null_type)
2738 throw JSONRPCError(-32600, "Params must be an array");
2741 const CRPCCommand *pcmd = tableRPC[strMethod];
2743 throw JSONRPCError(-32601, "Method not found");
2745 // Observe safe mode
2746 string strWarning = GetWarnings("rpc");
2747 if (strWarning != "" && !GetBoolArg("-disablesafemode") &&
2749 throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
2756 LOCK2(cs_main, pwalletMain->cs_wallet);
2757 result = pcmd->actor(params, false);
2761 string strReply = JSONRPCReply(result, Value::null, id);
2762 stream << HTTPReply(200, strReply) << std::flush;
2764 catch (std::exception& e)
2766 ErrorReply(stream, JSONRPCError(-1, e.what()), id);
2769 catch (Object& objError)
2771 ErrorReply(stream, objError, id);
2773 catch (std::exception& e)
2775 ErrorReply(stream, JSONRPCError(-32700, e.what()), id);
2783 Object CallRPC(const string& strMethod, const Array& params)
2785 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2786 throw runtime_error(strprintf(
2787 _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
2788 "If the file does not exist, create it with owner-readable-only file permissions."),
2789 GetConfigFile().string().c_str()));
2791 // Connect to localhost
2792 bool fUseSSL = GetBoolArg("-rpcssl");
2793 asio::io_service io_service;
2794 ssl::context context(io_service, ssl::context::sslv23);
2795 context.set_options(ssl::context::no_sslv2);
2796 SSLStream sslStream(io_service, context);
2797 SSLIOStreamDevice d(sslStream, fUseSSL);
2798 iostreams::stream<SSLIOStreamDevice> stream(d);
2799 if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", CBigNum(RPC_PORT).ToString().c_str())))
2800 throw runtime_error("couldn't connect to server");
2802 // HTTP basic authentication
2803 string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
2804 map<string, string> mapRequestHeaders;
2805 mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
2808 string strRequest = JSONRPCRequest(strMethod, params, 1);
2809 string strPost = HTTPPost(strRequest, mapRequestHeaders);
2810 stream << strPost << std::flush;
2813 map<string, string> mapHeaders;
2815 int nStatus = ReadHTTP(stream, mapHeaders, strReply);
2817 throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
2818 else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
2819 throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
2820 else if (strReply.empty())
2821 throw runtime_error("no response from server");
2825 if (!read_string(strReply, valReply))
2826 throw runtime_error("couldn't parse reply from server");
2827 const Object& reply = valReply.get_obj();
2829 throw runtime_error("expected reply to have result, error and id properties");
2837 template<typename T>
2838 void ConvertTo(Value& value)
2840 if (value.type() == str_type)
2842 // reinterpret string as unquoted json value
2844 if (!read_string(value.get_str(), value2))
2845 throw runtime_error("type mismatch");
2846 value = value2.get_value<T>();
2850 value = value.get_value<T>();
2854 int CommandLineRPC(int argc, char *argv[])
2861 while (argc > 1 && IsSwitchChar(argv[1][0]))
2869 throw runtime_error("too few parameters");
2870 string strMethod = argv[1];
2872 // Parameters default to strings
2874 for (int i = 2; i < argc; i++)
2875 params.push_back(argv[i]);
2876 int n = params.size();
2879 // Special case non-string parameter types
2881 if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
2882 if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2883 if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
2884 if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]);
2885 if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2886 if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2887 if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2888 if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
2889 if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2890 if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
2891 if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2892 if (strMethod == "getblockhash" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2893 if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]);
2894 if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2895 if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]);
2896 if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2897 if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2898 if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2899 if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2900 if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2901 if (strMethod == "walletpassphrase" && n > 2) ConvertTo<bool>(params[2]);
2902 if (strMethod == "listsinceblock" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2903 if (strMethod == "sendalert" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2904 if (strMethod == "sendalert" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2905 if (strMethod == "sendalert" && n > 4) ConvertTo<boost::int64_t>(params[4]);
2906 if (strMethod == "sendalert" && n > 5) ConvertTo<boost::int64_t>(params[5]);
2907 if (strMethod == "sendalert" && n > 6) ConvertTo<boost::int64_t>(params[6]);
2908 if (strMethod == "sendmany" && n > 1)
2910 string s = params[1].get_str();
2912 if (!read_string(s, v) || v.type() != obj_type)
2913 throw runtime_error("type mismatch");
2914 params[1] = v.get_obj();
2916 if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2917 if (strMethod == "reservebalance" && n > 0) ConvertTo<bool>(params[0]);
2918 if (strMethod == "reservebalance" && n > 1) ConvertTo<double>(params[1]);
2919 if (strMethod == "addmultisigaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2920 if (strMethod == "addmultisigaddress" && n > 1)
2922 string s = params[1].get_str();
2924 if (!read_string(s, v) || v.type() != array_type)
2925 throw runtime_error("type mismatch "+s);
2926 params[1] = v.get_array();
2930 Object reply = CallRPC(strMethod, params);
2933 const Value& result = find_value(reply, "result");
2934 const Value& error = find_value(reply, "error");
2936 if (error.type() != null_type)
2939 strPrint = "error: " + write_string(error, false);
2940 int code = find_value(error.get_obj(), "code").get_int();
2946 if (result.type() == null_type)
2948 else if (result.type() == str_type)
2949 strPrint = result.get_str();
2951 strPrint = write_string(result, true);
2954 catch (std::exception& e)
2956 strPrint = string("error: ") + e.what();
2961 PrintException(NULL, "CommandLineRPC()");
2966 fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
2975 int main(int argc, char *argv[])
2978 // Turn off microsoft heap dump noise
2979 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
2980 _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
2982 setbuf(stdin, NULL);
2983 setbuf(stdout, NULL);
2984 setbuf(stderr, NULL);
2988 if (argc >= 2 && string(argv[1]) == "-server")
2990 printf("server ready\n");
2991 ThreadRPCServer(NULL);
2995 return CommandLineRPC(argc, argv);
2998 catch (std::exception& e) {
2999 PrintException(&e, "main()");
3001 PrintException(NULL, "main()");
3007 const CRPCTable tableRPC;