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 the proof-of-work difficulty as a multiple of the minimum difficulty.");
276 return GetDifficulty();
280 Value getgenerate(const Array& params, bool fHelp)
282 if (fHelp || params.size() != 0)
285 "Returns true or false.");
287 return GetBoolArg("-gen");
291 Value setgenerate(const Array& params, bool fHelp)
293 if (fHelp || params.size() < 1 || params.size() > 2)
295 "setgenerate <generate> [genproclimit]\n"
296 "<generate> is true or false to turn generation on or off.\n"
297 "Generation is limited to [genproclimit] processors, -1 is unlimited.");
299 bool fGenerate = true;
300 if (params.size() > 0)
301 fGenerate = params[0].get_bool();
303 if (params.size() > 1)
305 int nGenProcLimit = params[1].get_int();
306 mapArgs["-genproclimit"] = itostr(nGenProcLimit);
307 if (nGenProcLimit == 0)
310 mapArgs["-gen"] = (fGenerate ? "1" : "0");
312 GenerateBitcoins(fGenerate, pwalletMain);
317 Value gethashespersec(const Array& params, bool fHelp)
319 if (fHelp || params.size() != 0)
322 "Returns a recent hashes per second performance measurement while generating.");
324 if (GetTimeMillis() - nHPSTimerStart > 8000)
325 return (boost::int64_t)0;
326 return (boost::int64_t)dHashesPerSec;
330 Value getinfo(const Array& params, bool fHelp)
332 if (fHelp || params.size() != 0)
335 "Returns an object containing various state info.");
338 obj.push_back(Pair("version", FormatFullVersion()));
339 obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION));
340 obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
341 obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
342 obj.push_back(Pair("newmint", ValueFromAmount(pwalletMain->GetNewMint())));
343 obj.push_back(Pair("stake", ValueFromAmount(pwalletMain->GetStake())));
344 obj.push_back(Pair("blocks", (int)nBestHeight));
345 obj.push_back(Pair("connections", (int)vNodes.size()));
346 obj.push_back(Pair("proxy", (fUseProxy ? addrProxy.ToStringIPPort() : string())));
347 obj.push_back(Pair("ip", addrSeenByPeer.ToStringIP()));
348 obj.push_back(Pair("difficulty", (double)GetDifficulty()));
349 obj.push_back(Pair("testnet", fTestNet));
350 obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));
351 obj.push_back(Pair("keypoolsize", pwalletMain->GetKeyPoolSize()));
352 obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee)));
353 if (pwalletMain->IsCrypted())
354 obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime / 1000));
355 obj.push_back(Pair("errors", GetWarnings("statusbar")));
360 Value getmininginfo(const Array& params, bool fHelp)
362 if (fHelp || params.size() != 0)
365 "Returns an object containing mining-related information.");
368 obj.push_back(Pair("blocks", (int)nBestHeight));
369 obj.push_back(Pair("currentblocksize",(uint64_t)nLastBlockSize));
370 obj.push_back(Pair("currentblocktx",(uint64_t)nLastBlockTx));
371 obj.push_back(Pair("difficulty", (double)GetDifficulty()));
372 obj.push_back(Pair("errors", GetWarnings("statusbar")));
373 obj.push_back(Pair("generate", GetBoolArg("-gen")));
374 obj.push_back(Pair("genproclimit", (int)GetArg("-genproclimit", -1)));
375 obj.push_back(Pair("hashespersec", gethashespersec(params, false)));
376 obj.push_back(Pair("pooledtx", (uint64_t)mempool.size()));
377 obj.push_back(Pair("testnet", fTestNet));
382 Value getnewaddress(const Array& params, bool fHelp)
384 if (fHelp || params.size() > 1)
386 "getnewaddress [account]\n"
387 "Returns a new ppcoin address for receiving payments. "
388 "If [account] is specified (recommended), it is added to the address book "
389 "so payments received with the address will be credited to [account].");
391 // Parse the account first so we don't generate a key if there's an error
393 if (params.size() > 0)
394 strAccount = AccountFromValue(params[0]);
396 if (!pwalletMain->IsLocked())
397 pwalletMain->TopUpKeyPool();
399 // Generate a new key that is added to wallet
400 std::vector<unsigned char> newKey;
401 if (!pwalletMain->GetKeyFromPool(newKey, false))
402 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
403 CBitcoinAddress address(newKey);
405 pwalletMain->SetAddressBookName(address, strAccount);
407 return address.ToString();
411 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
413 CWalletDB walletdb(pwalletMain->strWalletFile);
416 walletdb.ReadAccount(strAccount, account);
418 bool bKeyUsed = false;
420 // Check if the current key has been used
421 if (!account.vchPubKey.empty())
423 CScript scriptPubKey;
424 scriptPubKey.SetBitcoinAddress(account.vchPubKey);
425 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
426 it != pwalletMain->mapWallet.end() && !account.vchPubKey.empty();
429 const CWalletTx& wtx = (*it).second;
430 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
431 if (txout.scriptPubKey == scriptPubKey)
436 // Generate a new key
437 if (account.vchPubKey.empty() || bForceNew || bKeyUsed)
439 if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false))
440 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
442 pwalletMain->SetAddressBookName(CBitcoinAddress(account.vchPubKey), strAccount);
443 walletdb.WriteAccount(strAccount, account);
446 return CBitcoinAddress(account.vchPubKey);
449 Value getaccountaddress(const Array& params, bool fHelp)
451 if (fHelp || params.size() != 1)
453 "getaccountaddress <account>\n"
454 "Returns the current ppcoin address for receiving payments to this account.");
456 // Parse the account first so we don't generate a key if there's an error
457 string strAccount = AccountFromValue(params[0]);
461 ret = GetAccountAddress(strAccount).ToString();
468 Value setaccount(const Array& params, bool fHelp)
470 if (fHelp || params.size() < 1 || params.size() > 2)
472 "setaccount <ppcoinaddress> <account>\n"
473 "Sets the account associated with the given address.");
475 CBitcoinAddress address(params[0].get_str());
476 if (!address.IsValid())
477 throw JSONRPCError(-5, "Invalid ppcoin address");
481 if (params.size() > 1)
482 strAccount = AccountFromValue(params[1]);
484 // Detect when changing the account of an address that is the 'unused current key' of another account:
485 if (pwalletMain->mapAddressBook.count(address))
487 string strOldAccount = pwalletMain->mapAddressBook[address];
488 if (address == GetAccountAddress(strOldAccount))
489 GetAccountAddress(strOldAccount, true);
492 pwalletMain->SetAddressBookName(address, strAccount);
498 Value getaccount(const Array& params, bool fHelp)
500 if (fHelp || params.size() != 1)
502 "getaccount <ppcoinaddress>\n"
503 "Returns the account associated with the given address.");
505 CBitcoinAddress address(params[0].get_str());
506 if (!address.IsValid())
507 throw JSONRPCError(-5, "Invalid ppcoin address");
510 map<CBitcoinAddress, string>::iterator mi = pwalletMain->mapAddressBook.find(address);
511 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
512 strAccount = (*mi).second;
517 Value getaddressesbyaccount(const Array& params, bool fHelp)
519 if (fHelp || params.size() != 1)
521 "getaddressesbyaccount <account>\n"
522 "Returns the list of addresses for the given account.");
524 string strAccount = AccountFromValue(params[0]);
526 // Find all addresses that have the given account
528 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
530 const CBitcoinAddress& address = item.first;
531 const string& strName = item.second;
532 if (strName == strAccount)
533 ret.push_back(address.ToString());
538 Value settxfee(const Array& params, bool fHelp)
540 if (fHelp || params.size() < 1 || params.size() > 1 || AmountFromValue(params[0]) < MIN_TX_FEE)
542 "settxfee <amount>\n"
543 "<amount> is a real and is rounded to 0.01 (cent)\n"
544 "Minimum and default transaction fee per KB is 1 cent");
546 nTransactionFee = AmountFromValue(params[0]);
547 nTransactionFee = (nTransactionFee / CENT) * CENT; // round to cent
551 Value sendtoaddress(const Array& params, bool fHelp)
553 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
555 "sendtoaddress <ppcoinaddress> <amount> [comment] [comment-to]\n"
556 "<amount> is a real and is rounded to the nearest 0.000001\n"
557 "requires wallet passphrase to be set with walletpassphrase first");
558 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
560 "sendtoaddress <ppcoinaddress> <amount> [comment] [comment-to]\n"
561 "<amount> is a real and is rounded to the nearest 0.000001");
563 CBitcoinAddress address(params[0].get_str());
564 if (!address.IsValid())
565 throw JSONRPCError(-5, "Invalid ppcoin address");
568 int64 nAmount = AmountFromValue(params[1]);
572 if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
573 wtx.mapValue["comment"] = params[2].get_str();
574 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
575 wtx.mapValue["to"] = params[3].get_str();
577 if (pwalletMain->IsLocked())
578 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
580 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
582 throw JSONRPCError(-4, strError);
584 return wtx.GetHash().GetHex();
587 Value signmessage(const Array& params, bool fHelp)
589 if (fHelp || params.size() != 2)
591 "signmessage <ppcoinaddress> <message>\n"
592 "Sign a message with the private key of an address");
594 if (pwalletMain->IsLocked())
595 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
597 string strAddress = params[0].get_str();
598 string strMessage = params[1].get_str();
600 CBitcoinAddress addr(strAddress);
602 throw JSONRPCError(-3, "Invalid address");
605 if (!pwalletMain->GetKey(addr, key))
606 throw JSONRPCError(-4, "Private key not available");
608 CDataStream ss(SER_GETHASH, 0);
609 ss << strMessageMagic;
612 vector<unsigned char> vchSig;
613 if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig))
614 throw JSONRPCError(-5, "Sign failed");
616 return EncodeBase64(&vchSig[0], vchSig.size());
619 Value verifymessage(const Array& params, bool fHelp)
621 if (fHelp || params.size() != 3)
623 "verifymessage <ppcoinaddress> <signature> <message>\n"
624 "Verify a signed message");
626 string strAddress = params[0].get_str();
627 string strSign = params[1].get_str();
628 string strMessage = params[2].get_str();
630 CBitcoinAddress addr(strAddress);
632 throw JSONRPCError(-3, "Invalid address");
634 bool fInvalid = false;
635 vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
638 throw JSONRPCError(-5, "Malformed base64 encoding");
640 CDataStream ss(SER_GETHASH, 0);
641 ss << strMessageMagic;
645 if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
648 return (CBitcoinAddress(key.GetPubKey()) == addr);
652 Value getreceivedbyaddress(const Array& params, bool fHelp)
654 if (fHelp || params.size() < 1 || params.size() > 2)
656 "getreceivedbyaddress <ppcoinaddress> [minconf=1]\n"
657 "Returns the total amount received by <ppcoinaddress> in transactions with at least [minconf] confirmations.");
660 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
661 CScript scriptPubKey;
662 if (!address.IsValid())
663 throw JSONRPCError(-5, "Invalid ppcoin address");
664 scriptPubKey.SetBitcoinAddress(address);
665 if (!IsMine(*pwalletMain,scriptPubKey))
668 // Minimum confirmations
670 if (params.size() > 1)
671 nMinDepth = params[1].get_int();
675 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
677 const CWalletTx& wtx = (*it).second;
678 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
681 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
682 if (txout.scriptPubKey == scriptPubKey)
683 if (wtx.GetDepthInMainChain() >= nMinDepth)
684 nAmount += txout.nValue;
687 return ValueFromAmount(nAmount);
691 void GetAccountAddresses(string strAccount, set<CBitcoinAddress>& setAddress)
693 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
695 const CBitcoinAddress& address = item.first;
696 const string& strName = item.second;
697 if (strName == strAccount)
698 setAddress.insert(address);
703 Value getreceivedbyaccount(const Array& params, bool fHelp)
705 if (fHelp || params.size() < 1 || params.size() > 2)
707 "getreceivedbyaccount <account> [minconf=1]\n"
708 "Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.");
710 // Minimum confirmations
712 if (params.size() > 1)
713 nMinDepth = params[1].get_int();
715 // Get the set of pub keys assigned to account
716 string strAccount = AccountFromValue(params[0]);
717 set<CBitcoinAddress> setAddress;
718 GetAccountAddresses(strAccount, setAddress);
722 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
724 const CWalletTx& wtx = (*it).second;
725 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
728 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
730 CBitcoinAddress address;
731 if (ExtractAddress(txout.scriptPubKey, address) && pwalletMain->HaveKey(address) && setAddress.count(address))
732 if (wtx.GetDepthInMainChain() >= nMinDepth)
733 nAmount += txout.nValue;
737 return (double)nAmount / (double)COIN;
741 int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth)
745 // Tally wallet transactions
746 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
748 const CWalletTx& wtx = (*it).second;
752 int64 nGenerated, nReceived, nSent, nFee;
753 wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee);
755 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
756 nBalance += nReceived;
757 nBalance += nGenerated - nSent - nFee;
760 // Tally internal accounting entries
761 nBalance += walletdb.GetAccountCreditDebit(strAccount);
766 int64 GetAccountBalance(const string& strAccount, int nMinDepth)
768 CWalletDB walletdb(pwalletMain->strWalletFile);
769 return GetAccountBalance(walletdb, strAccount, nMinDepth);
773 Value getbalance(const Array& params, bool fHelp)
775 if (fHelp || params.size() > 2)
777 "getbalance [account] [minconf=1]\n"
778 "If [account] is not specified, returns the server's total available balance.\n"
779 "If [account] is specified, returns the balance in the account.");
781 if (params.size() == 0)
782 return ValueFromAmount(pwalletMain->GetBalance());
785 if (params.size() > 1)
786 nMinDepth = params[1].get_int();
788 if (params[0].get_str() == "*") {
789 // Calculate total balance a different way from GetBalance()
790 // (GetBalance() sums up all unspent TxOuts)
791 // getbalance and getbalance '*' should always return the same number.
793 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
795 const CWalletTx& wtx = (*it).second;
799 int64 allGeneratedImmature, allGeneratedMature, allFee;
800 allGeneratedImmature = allGeneratedMature = allFee = 0;
801 string strSentAccount;
802 list<pair<CBitcoinAddress, int64> > listReceived;
803 list<pair<CBitcoinAddress, int64> > listSent;
804 wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
805 if (wtx.GetDepthInMainChain() >= nMinDepth)
807 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listReceived)
808 nBalance += r.second;
810 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listSent)
811 nBalance -= r.second;
813 nBalance += allGeneratedMature;
815 return ValueFromAmount(nBalance);
818 string strAccount = AccountFromValue(params[0]);
820 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
822 return ValueFromAmount(nBalance);
826 Value movecmd(const Array& params, bool fHelp)
828 if (fHelp || params.size() < 3 || params.size() > 5)
830 "move <fromaccount> <toaccount> <amount> [minconf=1] [comment]\n"
831 "Move from one account in your wallet to another.");
833 string strFrom = AccountFromValue(params[0]);
834 string strTo = AccountFromValue(params[1]);
835 int64 nAmount = AmountFromValue(params[2]);
836 if (params.size() > 3)
837 // unused parameter, used to be nMinDepth, keep type-checking it though
838 (void)params[3].get_int();
840 if (params.size() > 4)
841 strComment = params[4].get_str();
843 CWalletDB walletdb(pwalletMain->strWalletFile);
844 if (!walletdb.TxnBegin())
845 throw JSONRPCError(-20, "database error");
847 int64 nNow = GetAdjustedTime();
850 CAccountingEntry debit;
851 debit.strAccount = strFrom;
852 debit.nCreditDebit = -nAmount;
854 debit.strOtherAccount = strTo;
855 debit.strComment = strComment;
856 walletdb.WriteAccountingEntry(debit);
859 CAccountingEntry credit;
860 credit.strAccount = strTo;
861 credit.nCreditDebit = nAmount;
863 credit.strOtherAccount = strFrom;
864 credit.strComment = strComment;
865 walletdb.WriteAccountingEntry(credit);
867 if (!walletdb.TxnCommit())
868 throw JSONRPCError(-20, "database error");
874 Value sendfrom(const Array& params, bool fHelp)
876 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
878 "sendfrom <fromaccount> <toppcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
879 "<amount> is a real and is rounded to the nearest 0.000001\n"
880 "requires wallet passphrase to be set with walletpassphrase first");
881 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
883 "sendfrom <fromaccount> <toppcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
884 "<amount> is a real and is rounded to the nearest 0.000001");
886 string strAccount = AccountFromValue(params[0]);
887 CBitcoinAddress address(params[1].get_str());
888 if (!address.IsValid())
889 throw JSONRPCError(-5, "Invalid ppcoin address");
890 int64 nAmount = AmountFromValue(params[2]);
892 if (params.size() > 3)
893 nMinDepth = params[3].get_int();
896 wtx.strFromAccount = strAccount;
897 if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
898 wtx.mapValue["comment"] = params[4].get_str();
899 if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
900 wtx.mapValue["to"] = params[5].get_str();
902 if (pwalletMain->IsLocked())
903 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
906 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
907 if (nAmount > nBalance)
908 throw JSONRPCError(-6, "Account has insufficient funds");
911 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
913 throw JSONRPCError(-4, strError);
915 return wtx.GetHash().GetHex();
919 Value sendmany(const Array& params, bool fHelp)
921 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
923 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
924 "amounts are double-precision floating point numbers\n"
925 "requires wallet passphrase to be set with walletpassphrase first");
926 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
928 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
929 "amounts are double-precision floating point numbers");
931 string strAccount = AccountFromValue(params[0]);
932 Object sendTo = params[1].get_obj();
934 if (params.size() > 2)
935 nMinDepth = params[2].get_int();
938 wtx.strFromAccount = strAccount;
939 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
940 wtx.mapValue["comment"] = params[3].get_str();
942 set<CBitcoinAddress> setAddress;
943 vector<pair<CScript, int64> > vecSend;
945 int64 totalAmount = 0;
946 BOOST_FOREACH(const Pair& s, sendTo)
948 CBitcoinAddress address(s.name_);
949 if (!address.IsValid())
950 throw JSONRPCError(-5, string("Invalid ppcoin address:")+s.name_);
952 if (setAddress.count(address))
953 throw JSONRPCError(-8, string("Invalid parameter, duplicated address: ")+s.name_);
954 setAddress.insert(address);
956 CScript scriptPubKey;
957 scriptPubKey.SetBitcoinAddress(address);
958 int64 nAmount = AmountFromValue(s.value_);
959 totalAmount += nAmount;
961 vecSend.push_back(make_pair(scriptPubKey, nAmount));
964 if (pwalletMain->IsLocked())
965 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
966 if (fWalletUnlockStakeOnly)
967 throw JSONRPCError(-13, "Error: Wallet unlocked for coinstake only.");
970 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
971 if (totalAmount > nBalance)
972 throw JSONRPCError(-6, "Account has insufficient funds");
975 CReserveKey keyChange(pwalletMain);
976 int64 nFeeRequired = 0;
977 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
980 if (totalAmount + nFeeRequired > pwalletMain->GetBalance())
981 throw JSONRPCError(-6, "Insufficient funds");
982 throw JSONRPCError(-4, "Transaction creation failed");
984 if (!pwalletMain->CommitTransaction(wtx, keyChange))
985 throw JSONRPCError(-4, "Transaction commit failed");
987 return wtx.GetHash().GetHex();
990 Value addmultisigaddress(const Array& params, bool fHelp)
992 if (fHelp || params.size() < 2 || params.size() > 3)
994 string msg = "addmultisigaddress <nrequired> <'[\"key\",\"key\"]'> [account]\n"
995 "Add a nrequired-to-sign multisignature address to the wallet\"\n"
996 "each key is a bitcoin address or hex-encoded public key\n"
997 "If [account] is specified, assign address to [account].";
998 throw runtime_error(msg);
1001 int nRequired = params[0].get_int();
1002 const Array& keys = params[1].get_array();
1004 if (params.size() > 2)
1005 strAccount = AccountFromValue(params[2]);
1007 // Gather public keys
1009 throw runtime_error("a multisignature address must require at least one key to redeem");
1010 if ((int)keys.size() < nRequired)
1011 throw runtime_error(
1012 strprintf("not enough keys supplied "
1013 "(got %d keys, but need at least %d to redeem)", keys.size(), nRequired));
1014 std::vector<CKey> pubkeys;
1015 pubkeys.resize(keys.size());
1016 for (unsigned int i = 0; i < keys.size(); i++)
1018 const std::string& ks = keys[i].get_str();
1020 // Case 1: bitcoin address and we have full public key:
1021 CBitcoinAddress address(ks);
1022 if (address.IsValid())
1024 if (address.IsScript())
1025 throw runtime_error(
1026 strprintf("%s is a pay-to-script address",ks.c_str()));
1027 std::vector<unsigned char> vchPubKey;
1028 if (!pwalletMain->GetPubKey(address, vchPubKey))
1029 throw runtime_error(
1030 strprintf("no full public key for address %s",ks.c_str()));
1031 if (vchPubKey.empty() || !pubkeys[i].SetPubKey(vchPubKey))
1032 throw runtime_error(" Invalid public key: "+ks);
1035 // Case 2: hex public key
1038 vector<unsigned char> vchPubKey = ParseHex(ks);
1039 if (vchPubKey.empty() || !pubkeys[i].SetPubKey(vchPubKey))
1040 throw runtime_error(" Invalid public key: "+ks);
1044 throw runtime_error(" Invalid public key: "+ks);
1048 // Construct using pay-to-script-hash:
1050 inner.SetMultisig(nRequired, pubkeys);
1052 uint160 scriptHash = Hash160(inner);
1053 CScript scriptPubKey;
1054 scriptPubKey.SetPayToScriptHash(inner);
1055 pwalletMain->AddCScript(inner);
1056 CBitcoinAddress address;
1057 address.SetScriptHash160(scriptHash);
1059 pwalletMain->SetAddressBookName(address, strAccount);
1060 return address.ToString();
1071 nConf = std::numeric_limits<int>::max();
1075 Value ListReceived(const Array& params, bool fByAccounts)
1077 // Minimum confirmations
1079 if (params.size() > 0)
1080 nMinDepth = params[0].get_int();
1082 // Whether to include empty accounts
1083 bool fIncludeEmpty = false;
1084 if (params.size() > 1)
1085 fIncludeEmpty = params[1].get_bool();
1088 map<CBitcoinAddress, tallyitem> mapTally;
1089 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1091 const CWalletTx& wtx = (*it).second;
1093 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
1096 int nDepth = wtx.GetDepthInMainChain();
1097 if (nDepth < nMinDepth)
1100 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
1102 CBitcoinAddress address;
1103 if (!ExtractAddress(txout.scriptPubKey, address) || !pwalletMain->HaveKey(address) || !address.IsValid())
1106 tallyitem& item = mapTally[address];
1107 item.nAmount += txout.nValue;
1108 item.nConf = min(item.nConf, nDepth);
1114 map<string, tallyitem> mapAccountTally;
1115 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
1117 const CBitcoinAddress& address = item.first;
1118 const string& strAccount = item.second;
1119 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
1120 if (it == mapTally.end() && !fIncludeEmpty)
1124 int nConf = std::numeric_limits<int>::max();
1125 if (it != mapTally.end())
1127 nAmount = (*it).second.nAmount;
1128 nConf = (*it).second.nConf;
1133 tallyitem& item = mapAccountTally[strAccount];
1134 item.nAmount += nAmount;
1135 item.nConf = min(item.nConf, nConf);
1140 obj.push_back(Pair("address", address.ToString()));
1141 obj.push_back(Pair("account", strAccount));
1142 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1143 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1150 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
1152 int64 nAmount = (*it).second.nAmount;
1153 int nConf = (*it).second.nConf;
1155 obj.push_back(Pair("account", (*it).first));
1156 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1157 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1165 Value listreceivedbyaddress(const Array& params, bool fHelp)
1167 if (fHelp || params.size() > 2)
1168 throw runtime_error(
1169 "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
1170 "[minconf] is the minimum number of confirmations before payments are included.\n"
1171 "[includeempty] whether to include addresses that haven't received any payments.\n"
1172 "Returns an array of objects containing:\n"
1173 " \"address\" : receiving address\n"
1174 " \"account\" : the account of the receiving address\n"
1175 " \"amount\" : total amount received by the address\n"
1176 " \"confirmations\" : number of confirmations of the most recent transaction included");
1178 return ListReceived(params, false);
1181 Value listreceivedbyaccount(const Array& params, bool fHelp)
1183 if (fHelp || params.size() > 2)
1184 throw runtime_error(
1185 "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
1186 "[minconf] is the minimum number of confirmations before payments are included.\n"
1187 "[includeempty] whether to include accounts that haven't received any payments.\n"
1188 "Returns an array of objects containing:\n"
1189 " \"account\" : the account of the receiving addresses\n"
1190 " \"amount\" : total amount received by addresses with this account\n"
1191 " \"confirmations\" : number of confirmations of the most recent transaction included");
1193 return ListReceived(params, true);
1196 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret)
1198 int64 nGeneratedImmature, nGeneratedMature, nFee;
1199 string strSentAccount;
1200 list<pair<CBitcoinAddress, int64> > listReceived;
1201 list<pair<CBitcoinAddress, int64> > listSent;
1203 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1205 bool fAllAccounts = (strAccount == string("*"));
1207 // Generated blocks assigned to account ""
1208 if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == ""))
1211 entry.push_back(Pair("account", string("")));
1212 if (nGeneratedImmature)
1214 entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
1215 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
1219 entry.push_back(Pair("category", "generate"));
1220 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
1223 WalletTxToJSON(wtx, entry);
1224 ret.push_back(entry);
1228 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1230 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1233 entry.push_back(Pair("account", strSentAccount));
1234 entry.push_back(Pair("address", s.first.ToString()));
1235 entry.push_back(Pair("category", "send"));
1236 entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1237 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1239 WalletTxToJSON(wtx, entry);
1240 ret.push_back(entry);
1245 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1247 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1250 if (pwalletMain->mapAddressBook.count(r.first))
1251 account = pwalletMain->mapAddressBook[r.first];
1252 if (fAllAccounts || (account == strAccount))
1255 entry.push_back(Pair("account", account));
1256 entry.push_back(Pair("address", r.first.ToString()));
1257 entry.push_back(Pair("category", "receive"));
1258 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1260 WalletTxToJSON(wtx, entry);
1261 ret.push_back(entry);
1267 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1269 bool fAllAccounts = (strAccount == string("*"));
1271 if (fAllAccounts || acentry.strAccount == strAccount)
1274 entry.push_back(Pair("account", acentry.strAccount));
1275 entry.push_back(Pair("category", "move"));
1276 entry.push_back(Pair("time", (boost::int64_t)acentry.nTime));
1277 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1278 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1279 entry.push_back(Pair("comment", acentry.strComment));
1280 ret.push_back(entry);
1284 Value listtransactions(const Array& params, bool fHelp)
1286 if (fHelp || params.size() > 3)
1287 throw runtime_error(
1288 "listtransactions [account] [count=10] [from=0]\n"
1289 "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1291 string strAccount = "*";
1292 if (params.size() > 0)
1293 strAccount = params[0].get_str();
1295 if (params.size() > 1)
1296 nCount = params[1].get_int();
1298 if (params.size() > 2)
1299 nFrom = params[2].get_int();
1302 throw JSONRPCError(-8, "Negative count");
1304 throw JSONRPCError(-8, "Negative from");
1307 CWalletDB walletdb(pwalletMain->strWalletFile);
1309 // First: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap.
1310 typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
1311 typedef multimap<int64, TxPair > TxItems;
1314 // Note: maintaining indices in the database of (account,time) --> txid and (account, time) --> acentry
1315 // would make this much faster for applications that do this a lot.
1316 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1318 CWalletTx* wtx = &((*it).second);
1319 txByTime.insert(make_pair(wtx->GetTxTime(), TxPair(wtx, (CAccountingEntry*)0)));
1321 list<CAccountingEntry> acentries;
1322 walletdb.ListAccountCreditDebit(strAccount, acentries);
1323 BOOST_FOREACH(CAccountingEntry& entry, acentries)
1325 txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
1328 // iterate backwards until we have nCount items to return:
1329 for (TxItems::reverse_iterator it = txByTime.rbegin(); it != txByTime.rend(); ++it)
1331 CWalletTx *const pwtx = (*it).second.first;
1333 ListTransactions(*pwtx, strAccount, 0, true, ret);
1334 CAccountingEntry *const pacentry = (*it).second.second;
1336 AcentryToJSON(*pacentry, strAccount, ret);
1338 if (ret.size() >= (nCount+nFrom)) break;
1340 // ret is newest to oldest
1342 if (nFrom > (int)ret.size())
1344 if ((nFrom + nCount) > (int)ret.size())
1345 nCount = ret.size() - nFrom;
1346 Array::iterator first = ret.begin();
1347 std::advance(first, nFrom);
1348 Array::iterator last = ret.begin();
1349 std::advance(last, nFrom+nCount);
1351 if (last != ret.end()) ret.erase(last, ret.end());
1352 if (first != ret.begin()) ret.erase(ret.begin(), first);
1354 std::reverse(ret.begin(), ret.end()); // Return oldest to newest
1359 Value listaccounts(const Array& params, bool fHelp)
1361 if (fHelp || params.size() > 1)
1362 throw runtime_error(
1363 "listaccounts [minconf=1]\n"
1364 "Returns Object that has account names as keys, account balances as values.");
1367 if (params.size() > 0)
1368 nMinDepth = params[0].get_int();
1370 map<string, int64> mapAccountBalances;
1371 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& entry, pwalletMain->mapAddressBook) {
1372 if (pwalletMain->HaveKey(entry.first)) // This address belongs to me
1373 mapAccountBalances[entry.second] = 0;
1376 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1378 const CWalletTx& wtx = (*it).second;
1379 int64 nGeneratedImmature, nGeneratedMature, nFee;
1380 string strSentAccount;
1381 list<pair<CBitcoinAddress, int64> > listReceived;
1382 list<pair<CBitcoinAddress, int64> > listSent;
1383 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1384 mapAccountBalances[strSentAccount] -= nFee;
1385 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1386 mapAccountBalances[strSentAccount] -= s.second;
1387 if (wtx.GetDepthInMainChain() >= nMinDepth)
1389 mapAccountBalances[""] += nGeneratedMature;
1390 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1391 if (pwalletMain->mapAddressBook.count(r.first))
1392 mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1394 mapAccountBalances[""] += r.second;
1398 list<CAccountingEntry> acentries;
1399 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1400 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1401 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1404 BOOST_FOREACH(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) {
1405 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1410 Value listsinceblock(const Array& params, bool fHelp)
1413 throw runtime_error(
1414 "listsinceblock [blockhash] [target-confirmations]\n"
1415 "Get all transactions in blocks since block [blockhash], or all transactions if omitted");
1417 CBlockIndex *pindex = NULL;
1418 int target_confirms = 1;
1420 if (params.size() > 0)
1422 uint256 blockId = 0;
1424 blockId.SetHex(params[0].get_str());
1425 pindex = CBlockLocator(blockId).GetBlockIndex();
1428 if (params.size() > 1)
1430 target_confirms = params[1].get_int();
1432 if (target_confirms < 1)
1433 throw JSONRPCError(-8, "Invalid parameter");
1436 int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1;
1440 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1442 CWalletTx tx = (*it).second;
1444 if (depth == -1 || tx.GetDepthInMainChain() < depth)
1445 ListTransactions(tx, "*", 0, true, transactions);
1450 if (target_confirms == 1)
1452 lastblock = hashBestChain;
1456 int target_height = pindexBest->nHeight + 1 - target_confirms;
1459 for (block = pindexBest;
1460 block && block->nHeight > target_height;
1461 block = block->pprev) { }
1463 lastblock = block ? block->GetBlockHash() : 0;
1467 ret.push_back(Pair("transactions", transactions));
1468 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1473 Value gettransaction(const Array& params, bool fHelp)
1475 if (fHelp || params.size() != 1)
1476 throw runtime_error(
1477 "gettransaction <txid>\n"
1478 "Get detailed information about <txid>");
1481 hash.SetHex(params[0].get_str());
1485 if (!pwalletMain->mapWallet.count(hash))
1486 throw JSONRPCError(-5, "Invalid or non-wallet transaction id");
1487 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1489 int64 nCredit = wtx.GetCredit();
1490 int64 nDebit = wtx.GetDebit();
1491 int64 nNet = nCredit - nDebit;
1492 int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
1494 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1496 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1498 WalletTxToJSON(pwalletMain->mapWallet[hash], entry);
1501 ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
1502 entry.push_back(Pair("details", details));
1508 Value backupwallet(const Array& params, bool fHelp)
1510 if (fHelp || params.size() != 1)
1511 throw runtime_error(
1512 "backupwallet <destination>\n"
1513 "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1515 string strDest = params[0].get_str();
1516 BackupWallet(*pwalletMain, strDest);
1522 Value keypoolrefill(const Array& params, bool fHelp)
1524 if (pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1525 throw runtime_error(
1527 "Fills the keypool, requires wallet passphrase to be set.");
1528 if (!pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1529 throw runtime_error(
1531 "Fills the keypool.");
1533 if (pwalletMain->IsLocked())
1534 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
1536 pwalletMain->TopUpKeyPool();
1538 if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100))
1539 throw JSONRPCError(-4, "Error refreshing keypool.");
1545 void ThreadTopUpKeyPool(void* parg)
1547 pwalletMain->TopUpKeyPool();
1550 void ThreadCleanWalletPassphrase(void* parg)
1552 int64 nMyWakeTime = GetTimeMillis() + *((int64*)parg) * 1000;
1554 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1556 if (nWalletUnlockTime == 0)
1558 nWalletUnlockTime = nMyWakeTime;
1562 if (nWalletUnlockTime==0)
1564 int64 nToSleep = nWalletUnlockTime - GetTimeMillis();
1568 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1570 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1574 if (nWalletUnlockTime)
1576 nWalletUnlockTime = 0;
1577 pwalletMain->Lock();
1582 if (nWalletUnlockTime < nMyWakeTime)
1583 nWalletUnlockTime = nMyWakeTime;
1586 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1588 delete (int64*)parg;
1591 Value walletpassphrase(const Array& params, bool fHelp)
1593 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 3))
1594 throw runtime_error(
1595 "walletpassphrase <passphrase> <timeout> [stakeonly]\n"
1596 "Stores the wallet decryption key in memory for <timeout> seconds.\n"
1597 "stakeonly is optional true/false allowing only stake creation.");
1600 if (!pwalletMain->IsCrypted())
1601 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1603 if (!pwalletMain->IsLocked())
1604 throw JSONRPCError(-17, "Error: Wallet is already unlocked, use walletlock first if need to change unlock settings.");
1606 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1607 SecureString strWalletPass;
1608 strWalletPass.reserve(100);
1609 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1610 // Alternately, find a way to make params[0] mlock()'d to begin with.
1611 strWalletPass = params[0].get_str().c_str();
1613 if (strWalletPass.length() > 0)
1615 if (!pwalletMain->Unlock(strWalletPass))
1616 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1619 throw runtime_error(
1620 "walletpassphrase <passphrase> <timeout>\n"
1621 "Stores the wallet decryption key in memory for <timeout> seconds.");
1623 CreateThread(ThreadTopUpKeyPool, NULL);
1624 int64* pnSleepTime = new int64(params[1].get_int64());
1625 CreateThread(ThreadCleanWalletPassphrase, pnSleepTime);
1627 // ppcoin: if user OS account compromised prevent trivial sendmoney commands
1628 if (params.size() > 2)
1629 fWalletUnlockStakeOnly = params[2].get_bool();
1631 fWalletUnlockStakeOnly = false;
1637 Value walletpassphrasechange(const Array& params, bool fHelp)
1639 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1640 throw runtime_error(
1641 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1642 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1645 if (!pwalletMain->IsCrypted())
1646 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1648 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1649 // Alternately, find a way to make params[0] mlock()'d to begin with.
1650 SecureString strOldWalletPass;
1651 strOldWalletPass.reserve(100);
1652 strOldWalletPass = params[0].get_str().c_str();
1654 SecureString strNewWalletPass;
1655 strNewWalletPass.reserve(100);
1656 strNewWalletPass = params[1].get_str().c_str();
1658 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1659 throw runtime_error(
1660 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1661 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1663 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1664 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1670 Value walletlock(const Array& params, bool fHelp)
1672 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1673 throw runtime_error(
1675 "Removes the wallet encryption key from memory, locking the wallet.\n"
1676 "After calling this method, you will need to call walletpassphrase again\n"
1677 "before being able to call any methods which require the wallet to be unlocked.");
1680 if (!pwalletMain->IsCrypted())
1681 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called.");
1684 LOCK(cs_nWalletUnlockTime);
1685 pwalletMain->Lock();
1686 nWalletUnlockTime = 0;
1693 Value encryptwallet(const Array& params, bool fHelp)
1695 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1696 throw runtime_error(
1697 "encryptwallet <passphrase>\n"
1698 "Encrypts the wallet with <passphrase>.");
1701 if (pwalletMain->IsCrypted())
1702 throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
1704 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1705 // Alternately, find a way to make params[0] mlock()'d to begin with.
1706 SecureString strWalletPass;
1707 strWalletPass.reserve(100);
1708 strWalletPass = params[0].get_str().c_str();
1710 if (strWalletPass.length() < 1)
1711 throw runtime_error(
1712 "encryptwallet <passphrase>\n"
1713 "Encrypts the wallet with <passphrase>.");
1715 if (!pwalletMain->EncryptWallet(strWalletPass))
1716 throw JSONRPCError(-16, "Error: Failed to encrypt the wallet.");
1718 // BDB seems to have a bad habit of writing old data into
1719 // slack space in .dat files; that is bad if the old data is
1720 // unencrypted private keys. So:
1722 return "wallet encrypted; ppcoin server stopping, restart to run with encrypted wallet";
1726 Value validateaddress(const Array& params, bool fHelp)
1728 if (fHelp || params.size() != 1)
1729 throw runtime_error(
1730 "validateaddress <ppcoinaddress>\n"
1731 "Return information about <ppcoinaddress>.");
1733 CBitcoinAddress address(params[0].get_str());
1734 bool isValid = address.IsValid();
1737 ret.push_back(Pair("isvalid", isValid));
1740 // Call Hash160ToAddress() so we always return current ADDRESSVERSION
1741 // version of the address:
1742 string currentAddress = address.ToString();
1743 ret.push_back(Pair("address", currentAddress));
1744 if (pwalletMain->HaveKey(address))
1746 ret.push_back(Pair("ismine", true));
1747 std::vector<unsigned char> vchPubKey;
1748 pwalletMain->GetPubKey(address, vchPubKey);
1749 ret.push_back(Pair("pubkey", HexStr(vchPubKey)));
1751 key.SetPubKey(vchPubKey);
1752 ret.push_back(Pair("iscompressed", key.IsCompressed()));
1754 else if (pwalletMain->HaveCScript(address.GetHash160()))
1756 ret.push_back(Pair("isscript", true));
1758 pwalletMain->GetCScript(address.GetHash160(), subscript);
1759 ret.push_back(Pair("ismine", ::IsMine(*pwalletMain, subscript)));
1760 std::vector<CBitcoinAddress> addresses;
1761 txnouttype whichType;
1763 ExtractAddresses(subscript, whichType, addresses, nRequired);
1764 ret.push_back(Pair("script", GetTxnOutputType(whichType)));
1766 BOOST_FOREACH(const CBitcoinAddress& addr, addresses)
1767 a.push_back(addr.ToString());
1768 ret.push_back(Pair("addresses", a));
1769 if (whichType == TX_MULTISIG)
1770 ret.push_back(Pair("sigsrequired", nRequired));
1773 ret.push_back(Pair("ismine", false));
1774 if (pwalletMain->mapAddressBook.count(address))
1775 ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
1780 Value getwork(const Array& params, bool fHelp)
1782 if (fHelp || params.size() > 1)
1783 throw runtime_error(
1785 "If [data] is not specified, returns formatted hash data to work on:\n"
1786 " \"midstate\" : precomputed hash state after hashing the first half of the data (DEPRECATED)\n" // deprecated
1787 " \"data\" : block data\n"
1788 " \"hash1\" : formatted hash buffer for second hash (DEPRECATED)\n" // deprecated
1789 " \"target\" : little endian hash target\n"
1790 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1793 throw JSONRPCError(-9, "PPCoin is not connected!");
1795 if (IsInitialBlockDownload())
1796 throw JSONRPCError(-10, "PPCoin is downloading blocks...");
1798 typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
1799 static mapNewBlock_t mapNewBlock;
1800 static vector<CBlock*> vNewBlock;
1801 static CReserveKey reservekey(pwalletMain);
1803 if (params.size() == 0)
1806 static unsigned int nTransactionsUpdatedLast;
1807 static CBlockIndex* pindexPrev;
1808 static int64 nStart;
1809 static CBlock* pblock;
1810 if (pindexPrev != pindexBest ||
1811 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
1813 if (pindexPrev != pindexBest)
1815 // Deallocate old blocks since they're obsolete now
1816 mapNewBlock.clear();
1817 BOOST_FOREACH(CBlock* pblock, vNewBlock)
1821 nTransactionsUpdatedLast = nTransactionsUpdated;
1822 pindexPrev = pindexBest;
1826 pblock = CreateNewBlock(pwalletMain, true);
1828 throw JSONRPCError(-7, "Out of memory");
1829 vNewBlock.push_back(pblock);
1833 pblock->UpdateTime(pindexPrev);
1836 // Update nExtraNonce
1837 static unsigned int nExtraNonce = 0;
1838 IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
1841 mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
1843 // Prebuild hash buffers
1847 FormatHashBuffers(pblock, pmidstate, pdata, phash1);
1849 uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
1852 result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate)))); // deprecated
1853 result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata))));
1854 result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1)))); // deprecated
1855 result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
1861 vector<unsigned char> vchData = ParseHex(params[0].get_str());
1862 if (vchData.size() != 128)
1863 throw JSONRPCError(-8, "Invalid parameter");
1864 CBlock* pdata = (CBlock*)&vchData[0];
1867 for (int i = 0; i < 128/4; i++)
1868 ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]);
1871 if (!mapNewBlock.count(pdata->hashMerkleRoot))
1873 CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
1875 pblock->nTime = pdata->nTime;
1876 pblock->nNonce = pdata->nNonce;
1877 pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
1878 pblock->hashMerkleRoot = pblock->BuildMerkleTree();
1879 if (!pblock->SignBlock(*pwalletMain))
1880 throw JSONRPCError(-100, "Unable to sign block");
1882 return CheckWork(pblock, *pwalletMain, reservekey);
1887 Value getmemorypool(const Array& params, bool fHelp)
1889 if (fHelp || params.size() > 1)
1890 throw runtime_error(
1891 "getmemorypool [data]\n"
1892 "If [data] is not specified, returns data needed to construct a block to work on:\n"
1893 " \"version\" : block version\n"
1894 " \"previousblockhash\" : hash of current highest block\n"
1895 " \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
1896 " \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
1897 " \"coinbaseflags\" : data that should be included in coinbase so support for new features can be judged\n"
1898 " \"time\" : timestamp appropriate for next block\n"
1899 " \"mintime\" : minimum timestamp appropriate for next block\n"
1900 " \"curtime\" : current timestamp\n"
1901 " \"bits\" : compressed target of next block\n"
1902 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1904 if (params.size() == 0)
1907 throw JSONRPCError(-9, "PPCoin is not connected!");
1909 if (IsInitialBlockDownload())
1910 throw JSONRPCError(-10, "PPCoin is downloading blocks...");
1912 static CReserveKey reservekey(pwalletMain);
1915 static unsigned int nTransactionsUpdatedLast;
1916 static CBlockIndex* pindexPrev;
1917 static int64 nStart;
1918 static CBlock* pblock;
1919 if (pindexPrev != pindexBest ||
1920 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5))
1922 nTransactionsUpdatedLast = nTransactionsUpdated;
1923 pindexPrev = pindexBest;
1929 pblock = CreateNewBlock(pwalletMain);
1931 throw JSONRPCError(-7, "Out of memory");
1935 pblock->UpdateTime(pindexPrev);
1939 BOOST_FOREACH(CTransaction tx, pblock->vtx) {
1940 if(tx.IsCoinBase() || tx.IsCoinStake())
1943 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
1946 transactions.push_back(HexStr(ssTx.begin(), ssTx.end()));
1950 result.push_back(Pair("version", pblock->nVersion));
1951 result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
1952 result.push_back(Pair("transactions", transactions));
1953 result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
1954 result.push_back(Pair("coinbaseflags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end())));
1955 result.push_back(Pair("time", (int64_t)pblock->nTime));
1956 result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1));
1957 result.push_back(Pair("curtime", (int64_t)GetAdjustedTime()));
1958 result.push_back(Pair("bits", HexBits(pblock->nBits)));
1965 CDataStream ssBlock(ParseHex(params[0].get_str()), SER_NETWORK, PROTOCOL_VERSION);
1969 return ProcessBlock(NULL, &pblock);
1973 Value getblockhash(const Array& params, bool fHelp)
1975 if (fHelp || params.size() != 1)
1976 throw runtime_error(
1977 "getblockhash <index>\n"
1978 "Returns hash of block in best-block-chain at <index>.");
1980 int nHeight = params[0].get_int();
1981 if (nHeight < 0 || nHeight > nBestHeight)
1982 throw runtime_error("Block number out of range.");
1985 CBlockIndex* pblockindex = mapBlockIndex[hashBestChain];
1986 while (pblockindex->nHeight > nHeight)
1987 pblockindex = pblockindex->pprev;
1988 return pblockindex->phashBlock->GetHex();
1991 Value getblock(const Array& params, bool fHelp)
1993 if (fHelp || params.size() != 1)
1994 throw runtime_error(
1996 "Returns details of a block with given block-hash.");
1998 std::string strHash = params[0].get_str();
1999 uint256 hash(strHash);
2001 if (mapBlockIndex.count(hash) == 0)
2002 throw JSONRPCError(-5, "Block not found");
2005 CBlockIndex* pblockindex = mapBlockIndex[hash];
2006 block.ReadFromDisk(pblockindex, true);
2008 return blockToJSON(block, pblockindex);
2012 // ppcoin: get information of sync-checkpoint
2013 Value getcheckpoint(const Array& params, bool fHelp)
2015 if (fHelp || params.size() != 0)
2016 throw runtime_error(
2018 "Show info of synchronized checkpoint.\n");
2021 CBlockIndex* pindexCheckpoint;
2023 result.push_back(Pair("synccheckpoint", Checkpoints::hashSyncCheckpoint.ToString().c_str()));
2024 pindexCheckpoint = mapBlockIndex[Checkpoints::hashSyncCheckpoint];
2025 result.push_back(Pair("height", pindexCheckpoint->nHeight));
2026 result.push_back(Pair("timestamp", DateTimeStrFormat(pindexCheckpoint->GetBlockTime()).c_str()));
2027 if (mapArgs.count("-checkpointkey"))
2028 result.push_back(Pair("checkpointmaster", true));
2034 // ppcoin: reserve balance from being staked for network protection
2035 Value reservebalance(const Array& params, bool fHelp)
2037 if (fHelp || params.size() > 2)
2038 throw runtime_error(
2039 "reservebalance [<reserve> [amount]]\n"
2040 "<reserve> is true or false to turn balance reserve on or off.\n"
2041 "<amount> is a real and rounded to cent.\n"
2042 "Set reserve amount not participating in network protection.\n"
2043 "If no parameters provided current setting is printed.\n");
2045 if (params.size() > 0)
2047 bool fReserve = params[0].get_bool();
2050 if (params.size() == 1)
2051 throw runtime_error("must provide amount to reserve balance.\n");
2052 int64 nAmount = AmountFromValue(params[1]);
2053 nAmount = (nAmount / CENT) * CENT; // round to cent
2055 throw runtime_error("amount cannot be negative.\n");
2056 mapArgs["-reservebalance"] = FormatMoney(nAmount).c_str();
2060 if (params.size() > 1)
2061 throw runtime_error("cannot specify amount to turn off reserve.\n");
2062 mapArgs["-reservebalance"] = "0";
2067 int64 nReserveBalance = 0;
2068 if (mapArgs.count("-reservebalance") && !ParseMoney(mapArgs["-reservebalance"], nReserveBalance))
2069 throw runtime_error("invalid reserve balance amount\n");
2070 result.push_back(Pair("reserve", (nReserveBalance > 0)));
2071 result.push_back(Pair("amount", ValueFromAmount(nReserveBalance)));
2076 // ppcoin: check wallet integrity
2077 Value checkwallet(const Array& params, bool fHelp)
2079 if (fHelp || params.size() > 0)
2080 throw runtime_error(
2082 "Check wallet for integrity.\n");
2085 int64 nBalanceInQuestion;
2086 if (!pwalletMain->CheckSpentCoins(nMismatchSpent, nBalanceInQuestion))
2089 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
2090 result.push_back(Pair("amount in question", ValueFromAmount(nBalanceInQuestion)));
2097 // ppcoin: repair wallet
2098 Value repairwallet(const Array& params, bool fHelp)
2100 if (fHelp || params.size() > 0)
2101 throw runtime_error(
2103 "Repair wallet if checkwallet reports any problem.\n");
2106 int64 nBalanceInQuestion;
2107 pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion);
2109 if (nMismatchSpent == 0)
2111 result.push_back(Pair("wallet check passed", true));
2115 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
2116 result.push_back(Pair("amount affected by repair", ValueFromAmount(nBalanceInQuestion)));
2121 // ppcoin: make a public-private key pair
2122 Value makekeypair(const Array& params, bool fHelp)
2124 if (fHelp || params.size() > 1)
2125 throw runtime_error(
2126 "makekeypair [prefix]\n"
2127 "Make a public/private key pair.\n"
2128 "[prefix] is optional preferred prefix for the public key.\n");
2130 string strPrefix = "";
2131 if (params.size() > 0)
2132 strPrefix = params[0].get_str();
2138 key.MakeNewKey(false);
2140 } while (nCount < 10000 && strPrefix != HexStr(key.GetPubKey()).substr(0, strPrefix.size()));
2142 if (strPrefix != HexStr(key.GetPubKey()).substr(0, strPrefix.size()))
2145 CPrivKey vchPrivKey = key.GetPrivKey();
2147 result.push_back(Pair("PrivateKey", HexStr<CPrivKey::iterator>(vchPrivKey.begin(), vchPrivKey.end())));
2148 result.push_back(Pair("PublicKey", HexStr(key.GetPubKey())));
2152 extern CCriticalSection cs_mapAlerts;
2153 extern map<uint256, CAlert> mapAlerts;
2155 // ppcoin: send alert.
2156 // There is a known deadlock situation with ThreadMessageHandler
2157 // ThreadMessageHandler: holds cs_vSend and acquiring cs_main in SendMessages()
2158 // ThreadRPCServer: holds cs_main and acquiring cs_vSend in alert.RelayTo()/PushMessage()/BeginMessage()
2159 Value sendalert(const Array& params, bool fHelp)
2161 if (fHelp || params.size() < 5)
2162 throw runtime_error(
2163 "sendalert <message> <privatekey> <minver> <maxver> <id> [cancelupto]\n"
2164 "<message> is the alert text message\n"
2165 "<privatekey> is hex string of alert master private key\n"
2166 "<minver> is the minimum applicable client version\n"
2167 "<maxver> is the maximum applicable client version\n"
2168 "<id> is the alert id\n"
2169 "[cancelupto] cancels all alert id's up to this number\n"
2170 "Returns true or false.");
2175 alert.strStatusBar = params[0].get_str();
2176 alert.nMinVer = params[2].get_int();
2177 alert.nMaxVer = params[3].get_int();
2178 alert.nID = params[4].get_int();
2179 if (params.size() > 5)
2180 alert.nCancel = params[5].get_int();
2181 alert.nVersion = PROTOCOL_VERSION;
2182 alert.nRelayUntil = GetAdjustedTime() + 365*24*60*60;
2183 alert.nExpiration = GetAdjustedTime() + 365*24*60*60;
2184 alert.nPriority = 1;
2186 CDataStream sMsg(SER_NETWORK, PROTOCOL_VERSION);
2187 sMsg << (CUnsignedAlert)alert;
2188 alert.vchMsg = vector<unsigned char>(sMsg.begin(), sMsg.end());
2190 vector<unsigned char> vchPrivKey = ParseHex(params[1].get_str());
2191 key.SetPrivKey(CPrivKey(vchPrivKey.begin(), vchPrivKey.end())); // if key is not correct openssl may crash
2192 if (!key.Sign(Hash(alert.vchMsg.begin(), alert.vchMsg.end()), alert.vchSig))
2193 throw runtime_error(
2194 "Unable to sign alert, check private key?\n");
2195 if(!alert.ProcessAlert())
2196 throw runtime_error(
2197 "Failed to process alert.\n");
2201 BOOST_FOREACH(CNode* pnode, vNodes)
2202 alert.RelayTo(pnode);
2206 result.push_back(Pair("strStatusBar", alert.strStatusBar));
2207 result.push_back(Pair("nVersion", alert.nVersion));
2208 result.push_back(Pair("nMinVer", alert.nMinVer));
2209 result.push_back(Pair("nMaxVer", alert.nMaxVer));
2210 result.push_back(Pair("nID", alert.nID));
2211 if (alert.nCancel > 0)
2212 result.push_back(Pair("nCancel", alert.nCancel));
2223 static const CRPCCommand vRPCCommands[] =
2224 { // name function safe mode?
2225 // ------------------------ ----------------------- ----------
2226 { "help", &help, true },
2227 { "stop", &stop, true },
2228 { "getblockcount", &getblockcount, true },
2229 { "getblocknumber", &getblocknumber, true },
2230 { "getconnectioncount", &getconnectioncount, true },
2231 { "getdifficulty", &getdifficulty, true },
2232 { "getgenerate", &getgenerate, true },
2233 { "setgenerate", &setgenerate, true },
2234 { "gethashespersec", &gethashespersec, true },
2235 { "getinfo", &getinfo, true },
2236 { "getmininginfo", &getmininginfo, true },
2237 { "getnewaddress", &getnewaddress, true },
2238 { "getaccountaddress", &getaccountaddress, true },
2239 { "setaccount", &setaccount, true },
2240 { "getaccount", &getaccount, false },
2241 { "getaddressesbyaccount", &getaddressesbyaccount, true },
2242 { "sendtoaddress", &sendtoaddress, false },
2243 { "getreceivedbyaddress", &getreceivedbyaddress, false },
2244 { "getreceivedbyaccount", &getreceivedbyaccount, false },
2245 { "listreceivedbyaddress", &listreceivedbyaddress, false },
2246 { "listreceivedbyaccount", &listreceivedbyaccount, false },
2247 { "backupwallet", &backupwallet, true },
2248 { "keypoolrefill", &keypoolrefill, true },
2249 { "walletpassphrase", &walletpassphrase, true },
2250 { "walletpassphrasechange", &walletpassphrasechange, false },
2251 { "walletlock", &walletlock, true },
2252 { "encryptwallet", &encryptwallet, false },
2253 { "validateaddress", &validateaddress, true },
2254 { "getbalance", &getbalance, false },
2255 { "move", &movecmd, false },
2256 { "sendfrom", &sendfrom, false },
2257 { "sendmany", &sendmany, false },
2258 { "addmultisigaddress", &addmultisigaddress, false },
2259 { "getblock", &getblock, false },
2260 { "getblockhash", &getblockhash, false },
2261 { "gettransaction", &gettransaction, false },
2262 { "listtransactions", &listtransactions, false },
2263 { "signmessage", &signmessage, false },
2264 { "verifymessage", &verifymessage, false },
2265 { "getwork", &getwork, true },
2266 { "listaccounts", &listaccounts, false },
2267 { "settxfee", &settxfee, false },
2268 { "getmemorypool", &getmemorypool, true },
2269 { "listsinceblock", &listsinceblock, false },
2270 { "dumpprivkey", &dumpprivkey, false },
2271 { "importprivkey", &importprivkey, false },
2272 { "getcheckpoint", &getcheckpoint, true },
2273 { "reservebalance", &reservebalance, false},
2274 { "checkwallet", &checkwallet, false},
2275 { "repairwallet", &repairwallet, false},
2276 { "makekeypair", &makekeypair, false},
2277 { "sendalert", &sendalert, false},
2280 CRPCTable::CRPCTable()
2283 for (vcidx = 0; vcidx < (sizeof(vRPCCommands) / sizeof(vRPCCommands[0])); vcidx++)
2285 const CRPCCommand *pcmd;
2287 pcmd = &vRPCCommands[vcidx];
2288 mapCommands[pcmd->name] = pcmd;
2292 const CRPCCommand *CRPCTable::operator[](string name) const
2294 map<string, const CRPCCommand*>::const_iterator it = mapCommands.find(name);
2295 if (it == mapCommands.end())
2297 return (*it).second;
2303 // This ain't Apache. We're just using HTTP header for the length field
2304 // and to be compatible with other JSON-RPC implementations.
2307 string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
2310 s << "POST / HTTP/1.1\r\n"
2311 << "User-Agent: ppcoin-json-rpc/" << FormatFullVersion() << "\r\n"
2312 << "Host: 127.0.0.1\r\n"
2313 << "Content-Type: application/json\r\n"
2314 << "Content-Length: " << strMsg.size() << "\r\n"
2315 << "Connection: close\r\n"
2316 << "Accept: application/json\r\n";
2317 BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
2318 s << item.first << ": " << item.second << "\r\n";
2319 s << "\r\n" << strMsg;
2324 string rfc1123Time()
2329 struct tm* now_gmt = gmtime(&now);
2330 string locale(setlocale(LC_TIME, NULL));
2331 setlocale(LC_TIME, "C"); // we want posix (aka "C") weekday/month strings
2332 strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt);
2333 setlocale(LC_TIME, locale.c_str());
2334 return string(buffer);
2337 static string HTTPReply(int nStatus, const string& strMsg)
2340 return strprintf("HTTP/1.0 401 Authorization Required\r\n"
2342 "Server: ppcoin-json-rpc/%s\r\n"
2343 "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
2344 "Content-Type: text/html\r\n"
2345 "Content-Length: 296\r\n"
2347 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
2348 "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
2351 "<TITLE>Error</TITLE>\r\n"
2352 "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
2354 "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
2355 "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
2356 const char *cStatus;
2357 if (nStatus == 200) cStatus = "OK";
2358 else if (nStatus == 400) cStatus = "Bad Request";
2359 else if (nStatus == 403) cStatus = "Forbidden";
2360 else if (nStatus == 404) cStatus = "Not Found";
2361 else if (nStatus == 500) cStatus = "Internal Server Error";
2364 "HTTP/1.1 %d %s\r\n"
2366 "Connection: close\r\n"
2367 "Content-Length: %d\r\n"
2368 "Content-Type: application/json\r\n"
2369 "Server: ppcoin-json-rpc/%s\r\n"
2374 rfc1123Time().c_str(),
2376 FormatFullVersion().c_str(),
2380 int ReadHTTPStatus(std::basic_istream<char>& stream)
2383 getline(stream, str);
2384 vector<string> vWords;
2385 boost::split(vWords, str, boost::is_any_of(" "));
2386 if (vWords.size() < 2)
2388 return atoi(vWords[1].c_str());
2391 int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
2397 std::getline(stream, str);
2398 if (str.empty() || str == "\r")
2400 string::size_type nColon = str.find(":");
2401 if (nColon != string::npos)
2403 string strHeader = str.substr(0, nColon);
2404 boost::trim(strHeader);
2405 boost::to_lower(strHeader);
2406 string strValue = str.substr(nColon+1);
2407 boost::trim(strValue);
2408 mapHeadersRet[strHeader] = strValue;
2409 if (strHeader == "content-length")
2410 nLen = atoi(strValue.c_str());
2416 int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
2418 mapHeadersRet.clear();
2422 int nStatus = ReadHTTPStatus(stream);
2425 int nLen = ReadHTTPHeader(stream, mapHeadersRet);
2426 if (nLen < 0 || nLen > (int)MAX_SIZE)
2432 vector<char> vch(nLen);
2433 stream.read(&vch[0], nLen);
2434 strMessageRet = string(vch.begin(), vch.end());
2440 bool HTTPAuthorized(map<string, string>& mapHeaders)
2442 string strAuth = mapHeaders["authorization"];
2443 if (strAuth.substr(0,6) != "Basic ")
2445 string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
2446 string strUserPass = DecodeBase64(strUserPass64);
2447 return strUserPass == strRPCUserColonPass;
2451 // JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
2452 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
2453 // unspecified (HTTP errors and contents of 'error').
2455 // 1.0 spec: http://json-rpc.org/wiki/specification
2456 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
2457 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
2460 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
2463 request.push_back(Pair("method", strMethod));
2464 request.push_back(Pair("params", params));
2465 request.push_back(Pair("id", id));
2466 return write_string(Value(request), false) + "\n";
2469 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
2472 if (error.type() != null_type)
2473 reply.push_back(Pair("result", Value::null));
2475 reply.push_back(Pair("result", result));
2476 reply.push_back(Pair("error", error));
2477 reply.push_back(Pair("id", id));
2478 return write_string(Value(reply), false) + "\n";
2481 void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
2483 // Send error reply from json-rpc error object
2485 int code = find_value(objError, "code").get_int();
2486 if (code == -32600) nStatus = 400;
2487 else if (code == -32601) nStatus = 404;
2488 string strReply = JSONRPCReply(Value::null, objError, id);
2489 stream << HTTPReply(nStatus, strReply) << std::flush;
2492 bool ClientAllowed(const string& strAddress)
2494 if (strAddress == asio::ip::address_v4::loopback().to_string())
2496 const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
2497 BOOST_FOREACH(string strAllow, vAllow)
2498 if (WildcardMatch(strAddress, strAllow))
2504 // IOStream device that speaks SSL but can also speak non-SSL
2506 class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
2508 SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
2510 fUseSSL = fUseSSLIn;
2511 fNeedHandshake = fUseSSLIn;
2514 void handshake(ssl::stream_base::handshake_type role)
2516 if (!fNeedHandshake) return;
2517 fNeedHandshake = false;
2518 stream.handshake(role);
2520 std::streamsize read(char* s, std::streamsize n)
2522 handshake(ssl::stream_base::server); // HTTPS servers read first
2523 if (fUseSSL) return stream.read_some(asio::buffer(s, n));
2524 return stream.next_layer().read_some(asio::buffer(s, n));
2526 std::streamsize write(const char* s, std::streamsize n)
2528 handshake(ssl::stream_base::client); // HTTPS clients write first
2529 if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
2530 return asio::write(stream.next_layer(), asio::buffer(s, n));
2532 bool connect(const std::string& server, const std::string& port)
2534 ip::tcp::resolver resolver(stream.get_io_service());
2535 ip::tcp::resolver::query query(server.c_str(), port.c_str());
2536 ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
2537 ip::tcp::resolver::iterator end;
2538 boost::system::error_code error = asio::error::host_not_found;
2539 while (error && endpoint_iterator != end)
2541 stream.lowest_layer().close();
2542 stream.lowest_layer().connect(*endpoint_iterator++, error);
2550 bool fNeedHandshake;
2555 void ThreadRPCServer(void* parg)
2557 IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
2560 vnThreadsRunning[THREAD_RPCSERVER]++;
2561 ThreadRPCServer2(parg);
2562 vnThreadsRunning[THREAD_RPCSERVER]--;
2564 catch (std::exception& e) {
2565 vnThreadsRunning[THREAD_RPCSERVER]--;
2566 PrintException(&e, "ThreadRPCServer()");
2568 vnThreadsRunning[THREAD_RPCSERVER]--;
2569 PrintException(NULL, "ThreadRPCServer()");
2571 printf("ThreadRPCServer exiting\n");
2574 void ThreadRPCServer2(void* parg)
2576 printf("ThreadRPCServer started\n");
2578 strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
2579 if (mapArgs["-rpcpassword"] == "")
2581 unsigned char rand_pwd[32];
2582 RAND_bytes(rand_pwd, 32);
2583 string strWhatAmI = "To use ppcoind";
2584 if (mapArgs.count("-server"))
2585 strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
2586 else if (mapArgs.count("-daemon"))
2587 strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
2588 ThreadSafeMessageBox(strprintf(
2589 _("%s, you must set a rpcpassword in the configuration file:\n %s\n"
2590 "It is recommended you use the following random password:\n"
2591 "rpcuser=bitcoinrpc\n"
2593 "(you do not need to remember this password)\n"
2594 "If the file does not exist, create it with owner-readable-only file permissions.\n"),
2596 GetConfigFile().string().c_str(),
2597 EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str()),
2598 _("Error"), wxOK | wxMODAL);
2603 bool fUseSSL = GetBoolArg("-rpcssl");
2604 asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
2606 asio::io_service io_service;
2607 ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", RPC_PORT));
2608 ip::tcp::acceptor acceptor(io_service);
2611 acceptor.open(endpoint.protocol());
2612 acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
2613 acceptor.bind(endpoint);
2614 acceptor.listen(socket_base::max_connections);
2616 catch(boost::system::system_error &e)
2618 ThreadSafeMessageBox(strprintf(_("An error occured while setting up the RPC port %i for listening: %s"), endpoint.port(), e.what()),
2619 _("Error"), wxOK | wxMODAL);
2624 ssl::context context(io_service, ssl::context::sslv23);
2627 context.set_options(ssl::context::no_sslv2);
2629 filesystem::path pathCertFile(GetArg("-rpcsslcertificatechainfile", "server.cert"));
2630 if (!pathCertFile.is_complete()) pathCertFile = filesystem::path(GetDataDir()) / pathCertFile;
2631 if (filesystem::exists(pathCertFile)) context.use_certificate_chain_file(pathCertFile.string());
2632 else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", pathCertFile.string().c_str());
2634 filesystem::path pathPKFile(GetArg("-rpcsslprivatekeyfile", "server.pem"));
2635 if (!pathPKFile.is_complete()) pathPKFile = filesystem::path(GetDataDir()) / pathPKFile;
2636 if (filesystem::exists(pathPKFile)) context.use_private_key_file(pathPKFile.string(), ssl::context::pem);
2637 else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pathPKFile.string().c_str());
2639 string strCiphers = GetArg("-rpcsslciphers", "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
2640 SSL_CTX_set_cipher_list(context.impl(), strCiphers.c_str());
2645 // Accept connection
2646 SSLStream sslStream(io_service, context);
2647 SSLIOStreamDevice d(sslStream, fUseSSL);
2648 iostreams::stream<SSLIOStreamDevice> stream(d);
2650 ip::tcp::endpoint peer;
2651 vnThreadsRunning[THREAD_RPCSERVER]--;
2652 acceptor.accept(sslStream.lowest_layer(), peer);
2653 vnThreadsRunning[4]++;
2657 // Restrict callers by IP
2658 if (!ClientAllowed(peer.address().to_string()))
2660 // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
2662 stream << HTTPReply(403, "") << std::flush;
2666 map<string, string> mapHeaders;
2669 boost::thread api_caller(ReadHTTP, boost::ref(stream), boost::ref(mapHeaders), boost::ref(strRequest));
2670 if (!api_caller.timed_join(boost::posix_time::seconds(GetArg("-rpctimeout", 30))))
2673 printf("ThreadRPCServer ReadHTTP timeout\n");
2677 // Check authorization
2678 if (mapHeaders.count("authorization") == 0)
2680 stream << HTTPReply(401, "") << std::flush;
2683 if (!HTTPAuthorized(mapHeaders))
2685 printf("ThreadRPCServer incorrect password attempt from %s\n",peer.address().to_string().c_str());
2686 /* Deter brute-forcing short passwords.
2687 If this results in a DOS the user really
2688 shouldn't have their RPC port exposed.*/
2689 if (mapArgs["-rpcpassword"].size() < 20)
2692 stream << HTTPReply(401, "") << std::flush;
2696 Value id = Value::null;
2701 if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
2702 throw JSONRPCError(-32700, "Parse error");
2703 const Object& request = valRequest.get_obj();
2705 // Parse id now so errors from here on will have the id
2706 id = find_value(request, "id");
2709 Value valMethod = find_value(request, "method");
2710 if (valMethod.type() == null_type)
2711 throw JSONRPCError(-32600, "Missing method");
2712 if (valMethod.type() != str_type)
2713 throw JSONRPCError(-32600, "Method must be a string");
2714 string strMethod = valMethod.get_str();
2715 if (strMethod != "getwork" && strMethod != "getmemorypool")
2716 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
2719 Value valParams = find_value(request, "params");
2721 if (valParams.type() == array_type)
2722 params = valParams.get_array();
2723 else if (valParams.type() == null_type)
2726 throw JSONRPCError(-32600, "Params must be an array");
2729 const CRPCCommand *pcmd = tableRPC[strMethod];
2731 throw JSONRPCError(-32601, "Method not found");
2733 // Observe safe mode
2734 string strWarning = GetWarnings("rpc");
2735 if (strWarning != "" && !GetBoolArg("-disablesafemode") &&
2737 throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
2744 LOCK2(cs_main, pwalletMain->cs_wallet);
2745 result = pcmd->actor(params, false);
2749 string strReply = JSONRPCReply(result, Value::null, id);
2750 stream << HTTPReply(200, strReply) << std::flush;
2752 catch (std::exception& e)
2754 ErrorReply(stream, JSONRPCError(-1, e.what()), id);
2757 catch (Object& objError)
2759 ErrorReply(stream, objError, id);
2761 catch (std::exception& e)
2763 ErrorReply(stream, JSONRPCError(-32700, e.what()), id);
2771 Object CallRPC(const string& strMethod, const Array& params)
2773 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2774 throw runtime_error(strprintf(
2775 _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
2776 "If the file does not exist, create it with owner-readable-only file permissions."),
2777 GetConfigFile().string().c_str()));
2779 // Connect to localhost
2780 bool fUseSSL = GetBoolArg("-rpcssl");
2781 asio::io_service io_service;
2782 ssl::context context(io_service, ssl::context::sslv23);
2783 context.set_options(ssl::context::no_sslv2);
2784 SSLStream sslStream(io_service, context);
2785 SSLIOStreamDevice d(sslStream, fUseSSL);
2786 iostreams::stream<SSLIOStreamDevice> stream(d);
2787 if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", CBigNum(RPC_PORT).ToString().c_str())))
2788 throw runtime_error("couldn't connect to server");
2790 // HTTP basic authentication
2791 string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
2792 map<string, string> mapRequestHeaders;
2793 mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
2796 string strRequest = JSONRPCRequest(strMethod, params, 1);
2797 string strPost = HTTPPost(strRequest, mapRequestHeaders);
2798 stream << strPost << std::flush;
2801 map<string, string> mapHeaders;
2803 int nStatus = ReadHTTP(stream, mapHeaders, strReply);
2805 throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
2806 else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
2807 throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
2808 else if (strReply.empty())
2809 throw runtime_error("no response from server");
2813 if (!read_string(strReply, valReply))
2814 throw runtime_error("couldn't parse reply from server");
2815 const Object& reply = valReply.get_obj();
2817 throw runtime_error("expected reply to have result, error and id properties");
2825 template<typename T>
2826 void ConvertTo(Value& value)
2828 if (value.type() == str_type)
2830 // reinterpret string as unquoted json value
2832 if (!read_string(value.get_str(), value2))
2833 throw runtime_error("type mismatch");
2834 value = value2.get_value<T>();
2838 value = value.get_value<T>();
2842 int CommandLineRPC(int argc, char *argv[])
2849 while (argc > 1 && IsSwitchChar(argv[1][0]))
2857 throw runtime_error("too few parameters");
2858 string strMethod = argv[1];
2860 // Parameters default to strings
2862 for (int i = 2; i < argc; i++)
2863 params.push_back(argv[i]);
2864 int n = params.size();
2867 // Special case non-string parameter types
2869 if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
2870 if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2871 if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
2872 if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]);
2873 if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2874 if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2875 if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2876 if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
2877 if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2878 if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
2879 if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2880 if (strMethod == "getblockhash" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2881 if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]);
2882 if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2883 if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]);
2884 if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2885 if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2886 if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2887 if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2888 if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2889 if (strMethod == "walletpassphrase" && n > 2) ConvertTo<bool>(params[2]);
2890 if (strMethod == "listsinceblock" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2891 if (strMethod == "sendalert" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2892 if (strMethod == "sendalert" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2893 if (strMethod == "sendalert" && n > 4) ConvertTo<boost::int64_t>(params[4]);
2894 if (strMethod == "sendalert" && n > 5) ConvertTo<boost::int64_t>(params[5]);
2895 if (strMethod == "sendmany" && n > 1)
2897 string s = params[1].get_str();
2899 if (!read_string(s, v) || v.type() != obj_type)
2900 throw runtime_error("type mismatch");
2901 params[1] = v.get_obj();
2903 if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2904 if (strMethod == "reservebalance" && n > 0) ConvertTo<bool>(params[0]);
2905 if (strMethod == "reservebalance" && n > 1) ConvertTo<double>(params[1]);
2906 if (strMethod == "addmultisigaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2907 if (strMethod == "addmultisigaddress" && n > 1)
2909 string s = params[1].get_str();
2911 if (!read_string(s, v) || v.type() != array_type)
2912 throw runtime_error("type mismatch "+s);
2913 params[1] = v.get_array();
2917 Object reply = CallRPC(strMethod, params);
2920 const Value& result = find_value(reply, "result");
2921 const Value& error = find_value(reply, "error");
2923 if (error.type() != null_type)
2926 strPrint = "error: " + write_string(error, false);
2927 int code = find_value(error.get_obj(), "code").get_int();
2933 if (result.type() == null_type)
2935 else if (result.type() == str_type)
2936 strPrint = result.get_str();
2938 strPrint = write_string(result, true);
2941 catch (std::exception& e)
2943 strPrint = string("error: ") + e.what();
2948 PrintException(NULL, "CommandLineRPC()");
2953 fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
2962 int main(int argc, char *argv[])
2965 // Turn off microsoft heap dump noise
2966 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
2967 _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
2969 setbuf(stdin, NULL);
2970 setbuf(stdout, NULL);
2971 setbuf(stderr, NULL);
2975 if (argc >= 2 && string(argv[1]) == "-server")
2977 printf("server ready\n");
2978 ThreadRPCServer(NULL);
2982 return CommandLineRPC(argc, argv);
2985 catch (std::exception& e) {
2986 PrintException(&e, "main()");
2988 PrintException(NULL, "main()");
2994 const CRPCTable tableRPC;