1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2012 The Bitcoin developers
3 // Copyright (c) 2011-2012 The PPCoin developers
4 // Distributed under the MIT/X11 software license, see the accompanying
5 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
13 #include "checkpoints.h"
14 #include "ui_interface.h"
15 #include "bitcoinrpc.h"
18 #include <boost/asio.hpp>
19 #include <boost/filesystem.hpp>
20 #include <boost/iostreams/concepts.hpp>
21 #include <boost/iostreams/stream.hpp>
22 #include <boost/algorithm/string.hpp>
23 #include <boost/lexical_cast.hpp>
24 #include <boost/asio/ssl.hpp>
25 #include <boost/filesystem/fstream.hpp>
26 typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> SSLStream;
28 #define printf OutputDebugStringF
29 // MinGW 3.4.5 gets "fatal error: had to relocate PCH" if the json headers are
30 // precompiled in headers.h. The problem might be when the pch file goes over
31 // a certain size around 145MB. If we need access to json_spirit outside this
32 // file, we could use the compiled json_spirit option.
35 using namespace boost;
36 using namespace boost::asio;
37 using namespace json_spirit;
39 void ThreadRPCServer2(void* parg);
41 static std::string strRPCUserColonPass;
43 static int64 nWalletUnlockTime;
44 static CCriticalSection cs_nWalletUnlockTime;
46 extern Value dumpprivkey(const Array& params, bool fHelp);
47 extern Value importprivkey(const Array& params, bool fHelp);
49 Object JSONRPCError(int code, const string& message)
52 error.push_back(Pair("code", code));
53 error.push_back(Pair("message", message));
57 double GetDifficulty(const CBlockIndex* blockindex = NULL)
59 // Floating point number that is a multiple of the minimum difficulty,
60 // minimum difficulty = 1.0.
61 if (blockindex == NULL)
63 if (pindexBest == NULL)
66 blockindex = GetLastBlockIndex(pindexBest, false);
69 int nShift = (blockindex->nBits >> 24) & 0xff;
72 (double)0x0000ffff / (double)(blockindex->nBits & 0x00ffffff);
89 int64 AmountFromValue(const Value& value)
91 double dAmount = value.get_real();
92 if (dAmount <= 0.0 || dAmount > MAX_MONEY)
93 throw JSONRPCError(-3, "Invalid amount");
94 int64 nAmount = roundint64(dAmount * COIN);
95 if (!MoneyRange(nAmount))
96 throw JSONRPCError(-3, "Invalid amount");
100 Value ValueFromAmount(int64 amount)
102 return (double)amount / (double)COIN;
106 HexBits(unsigned int nBits)
112 uBits.nBits = htonl((int32_t)nBits);
113 return HexStr(BEGIN(uBits.cBits), END(uBits.cBits));
116 void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
118 int confirms = wtx.GetDepthInMainChain();
119 entry.push_back(Pair("confirmations", confirms));
122 entry.push_back(Pair("blockhash", wtx.hashBlock.GetHex()));
123 entry.push_back(Pair("blockindex", wtx.nIndex));
125 entry.push_back(Pair("txid", wtx.GetHash().GetHex()));
126 entry.push_back(Pair("time", (boost::int64_t)wtx.GetTxTime()));
127 BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
128 entry.push_back(Pair(item.first, item.second));
131 string AccountFromValue(const Value& value)
133 string strAccount = value.get_str();
134 if (strAccount == "*")
135 throw JSONRPCError(-11, "Invalid account name");
139 Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex)
142 result.push_back(Pair("hash", block.GetHash().GetHex()));
143 result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION)));
144 result.push_back(Pair("height", blockindex->nHeight));
145 result.push_back(Pair("version", block.nVersion));
146 result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex()));
147 result.push_back(Pair("time", (boost::int64_t)block.GetBlockTime()));
148 result.push_back(Pair("nonce", (boost::uint64_t)block.nNonce));
149 result.push_back(Pair("bits", HexBits(block.nBits)));
150 result.push_back(Pair("difficulty", GetDifficulty(blockindex)));
152 BOOST_FOREACH (const CTransaction&tx, block.vtx)
153 txhashes.push_back(tx.GetHash().GetHex());
154 result.push_back(Pair("tx", txhashes));
156 if (blockindex->pprev)
157 result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex()));
158 if (blockindex->pnext)
159 result.push_back(Pair("nextblockhash", blockindex->pnext->GetBlockHash().GetHex()));
166 /// Note: This interface may still be subject to change.
169 string CRPCTable::help(string strCommand) const
172 set<rpcfn_type> setDone;
173 for (map<string, const CRPCCommand*>::const_iterator mi = mapCommands.begin(); mi != mapCommands.end(); ++mi)
175 const CRPCCommand *pcmd = mi->second;
176 string strMethod = mi->first;
177 // We already filter duplicates, but these deprecated screw up the sort order
178 if (strMethod == "getamountreceived" ||
179 strMethod == "getallreceived" ||
180 strMethod == "getblocknumber" || // deprecated
181 (strMethod.find("label") != string::npos))
183 if (strCommand != "" && strMethod != strCommand)
188 rpcfn_type pfn = pcmd->actor;
189 if (setDone.insert(pfn).second)
190 (*pfn)(params, true);
192 catch (std::exception& e)
194 // Help text is returned in an exception
195 string strHelp = string(e.what());
196 if (strCommand == "")
197 if (strHelp.find('\n') != string::npos)
198 strHelp = strHelp.substr(0, strHelp.find('\n'));
199 strRet += strHelp + "\n";
203 strRet = strprintf("help: unknown command: %s\n", strCommand.c_str());
204 strRet = strRet.substr(0,strRet.size()-1);
208 Value help(const Array& params, bool fHelp)
210 if (fHelp || params.size() > 1)
213 "List commands, or get help for a command.");
216 if (params.size() > 0)
217 strCommand = params[0].get_str();
219 return tableRPC.help(strCommand);
223 Value stop(const Array& params, bool fHelp)
225 if (fHelp || params.size() != 0)
228 "Stop ppcoin server.");
229 // Shutdown will take long enough that the response should get back
231 return "ppcoin server stopping";
235 Value getblockcount(const Array& params, bool fHelp)
237 if (fHelp || params.size() != 0)
240 "Returns the number of blocks in the longest block chain.");
247 Value getblocknumber(const Array& params, bool fHelp)
249 if (fHelp || params.size() != 0)
252 "Deprecated. Use getblockcount.");
258 Value getconnectioncount(const Array& params, bool fHelp)
260 if (fHelp || params.size() != 0)
262 "getconnectioncount\n"
263 "Returns the number of connections to other nodes.");
265 return (int)vNodes.size();
269 Value getdifficulty(const Array& params, bool fHelp)
271 if (fHelp || params.size() != 0)
274 "Returns difficulty as a multiple of the minimum difficulty.");
277 obj.push_back(Pair("proof-of-work", GetDifficulty()));
278 obj.push_back(Pair("proof-of-stake", GetDifficulty(GetLastBlockIndex(pindexBest, true))));
283 Value getgenerate(const Array& params, bool fHelp)
285 if (fHelp || params.size() != 0)
288 "Returns true or false.");
290 return GetBoolArg("-gen");
294 Value setgenerate(const Array& params, bool fHelp)
296 if (fHelp || params.size() < 1 || params.size() > 2)
298 "setgenerate <generate> [genproclimit]\n"
299 "<generate> is true or false to turn generation on or off.\n"
300 "Generation is limited to [genproclimit] processors, -1 is unlimited.");
302 bool fGenerate = true;
303 if (params.size() > 0)
304 fGenerate = params[0].get_bool();
306 if (params.size() > 1)
308 int nGenProcLimit = params[1].get_int();
309 mapArgs["-genproclimit"] = itostr(nGenProcLimit);
310 if (nGenProcLimit == 0)
313 mapArgs["-gen"] = (fGenerate ? "1" : "0");
315 GenerateBitcoins(fGenerate, pwalletMain);
320 Value gethashespersec(const Array& params, bool fHelp)
322 if (fHelp || params.size() != 0)
325 "Returns a recent hashes per second performance measurement while generating.");
327 if (GetTimeMillis() - nHPSTimerStart > 8000)
328 return (boost::int64_t)0;
329 return (boost::int64_t)dHashesPerSec;
333 Value getinfo(const Array& params, bool fHelp)
335 if (fHelp || params.size() != 0)
338 "Returns an object containing various state info.");
341 obj.push_back(Pair("version", FormatFullVersion()));
342 obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION));
343 obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
344 obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
345 obj.push_back(Pair("newmint", ValueFromAmount(pwalletMain->GetNewMint())));
346 obj.push_back(Pair("stake", ValueFromAmount(pwalletMain->GetStake())));
347 obj.push_back(Pair("blocks", (int)nBestHeight));
348 obj.push_back(Pair("connections", (int)vNodes.size()));
349 obj.push_back(Pair("proxy", (fUseProxy ? addrProxy.ToStringIPPort() : string())));
350 obj.push_back(Pair("ip", addrSeenByPeer.ToStringIP()));
351 obj.push_back(Pair("difficulty", (double)GetDifficulty()));
352 obj.push_back(Pair("testnet", fTestNet));
353 obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));
354 obj.push_back(Pair("keypoolsize", pwalletMain->GetKeyPoolSize()));
355 obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee)));
356 if (pwalletMain->IsCrypted())
357 obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime / 1000));
358 obj.push_back(Pair("errors", GetWarnings("statusbar")));
363 Value getmininginfo(const Array& params, bool fHelp)
365 if (fHelp || params.size() != 0)
368 "Returns an object containing mining-related information.");
371 obj.push_back(Pair("blocks", (int)nBestHeight));
372 obj.push_back(Pair("currentblocksize",(uint64_t)nLastBlockSize));
373 obj.push_back(Pair("currentblocktx",(uint64_t)nLastBlockTx));
374 obj.push_back(Pair("difficulty", (double)GetDifficulty()));
375 obj.push_back(Pair("errors", GetWarnings("statusbar")));
376 obj.push_back(Pair("generate", GetBoolArg("-gen")));
377 obj.push_back(Pair("genproclimit", (int)GetArg("-genproclimit", -1)));
378 obj.push_back(Pair("hashespersec", gethashespersec(params, false)));
379 obj.push_back(Pair("pooledtx", (uint64_t)mempool.size()));
380 obj.push_back(Pair("testnet", fTestNet));
385 Value getnewaddress(const Array& params, bool fHelp)
387 if (fHelp || params.size() > 1)
389 "getnewaddress [account]\n"
390 "Returns a new ppcoin address for receiving payments. "
391 "If [account] is specified (recommended), it is added to the address book "
392 "so payments received with the address will be credited to [account].");
394 // Parse the account first so we don't generate a key if there's an error
396 if (params.size() > 0)
397 strAccount = AccountFromValue(params[0]);
399 if (!pwalletMain->IsLocked())
400 pwalletMain->TopUpKeyPool();
402 // Generate a new key that is added to wallet
403 std::vector<unsigned char> newKey;
404 if (!pwalletMain->GetKeyFromPool(newKey, false))
405 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
406 CBitcoinAddress address(newKey);
408 pwalletMain->SetAddressBookName(address, strAccount);
410 return address.ToString();
414 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
416 CWalletDB walletdb(pwalletMain->strWalletFile);
419 walletdb.ReadAccount(strAccount, account);
421 bool bKeyUsed = false;
423 // Check if the current key has been used
424 if (!account.vchPubKey.empty())
426 CScript scriptPubKey;
427 scriptPubKey.SetBitcoinAddress(account.vchPubKey);
428 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
429 it != pwalletMain->mapWallet.end() && !account.vchPubKey.empty();
432 const CWalletTx& wtx = (*it).second;
433 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
434 if (txout.scriptPubKey == scriptPubKey)
439 // Generate a new key
440 if (account.vchPubKey.empty() || bForceNew || bKeyUsed)
442 if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false))
443 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
445 pwalletMain->SetAddressBookName(CBitcoinAddress(account.vchPubKey), strAccount);
446 walletdb.WriteAccount(strAccount, account);
449 return CBitcoinAddress(account.vchPubKey);
452 Value getaccountaddress(const Array& params, bool fHelp)
454 if (fHelp || params.size() != 1)
456 "getaccountaddress <account>\n"
457 "Returns the current ppcoin address for receiving payments to this account.");
459 // Parse the account first so we don't generate a key if there's an error
460 string strAccount = AccountFromValue(params[0]);
464 ret = GetAccountAddress(strAccount).ToString();
471 Value setaccount(const Array& params, bool fHelp)
473 if (fHelp || params.size() < 1 || params.size() > 2)
475 "setaccount <ppcoinaddress> <account>\n"
476 "Sets the account associated with the given address.");
478 CBitcoinAddress address(params[0].get_str());
479 if (!address.IsValid())
480 throw JSONRPCError(-5, "Invalid ppcoin address");
484 if (params.size() > 1)
485 strAccount = AccountFromValue(params[1]);
487 // Detect when changing the account of an address that is the 'unused current key' of another account:
488 if (pwalletMain->mapAddressBook.count(address))
490 string strOldAccount = pwalletMain->mapAddressBook[address];
491 if (address == GetAccountAddress(strOldAccount))
492 GetAccountAddress(strOldAccount, true);
495 pwalletMain->SetAddressBookName(address, strAccount);
501 Value getaccount(const Array& params, bool fHelp)
503 if (fHelp || params.size() != 1)
505 "getaccount <ppcoinaddress>\n"
506 "Returns the account associated with the given address.");
508 CBitcoinAddress address(params[0].get_str());
509 if (!address.IsValid())
510 throw JSONRPCError(-5, "Invalid ppcoin address");
513 map<CBitcoinAddress, string>::iterator mi = pwalletMain->mapAddressBook.find(address);
514 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
515 strAccount = (*mi).second;
520 Value getaddressesbyaccount(const Array& params, bool fHelp)
522 if (fHelp || params.size() != 1)
524 "getaddressesbyaccount <account>\n"
525 "Returns the list of addresses for the given account.");
527 string strAccount = AccountFromValue(params[0]);
529 // Find all addresses that have the given account
531 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
533 const CBitcoinAddress& address = item.first;
534 const string& strName = item.second;
535 if (strName == strAccount)
536 ret.push_back(address.ToString());
541 Value settxfee(const Array& params, bool fHelp)
543 if (fHelp || params.size() < 1 || params.size() > 1 || AmountFromValue(params[0]) < MIN_TX_FEE)
545 "settxfee <amount>\n"
546 "<amount> is a real and is rounded to 0.01 (cent)\n"
547 "Minimum and default transaction fee per KB is 1 cent");
549 nTransactionFee = AmountFromValue(params[0]);
550 nTransactionFee = (nTransactionFee / CENT) * CENT; // round to cent
554 Value sendtoaddress(const Array& params, bool fHelp)
556 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
558 "sendtoaddress <ppcoinaddress> <amount> [comment] [comment-to]\n"
559 "<amount> is a real and is rounded to the nearest 0.000001\n"
560 "requires wallet passphrase to be set with walletpassphrase first");
561 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
563 "sendtoaddress <ppcoinaddress> <amount> [comment] [comment-to]\n"
564 "<amount> is a real and is rounded to the nearest 0.000001");
566 CBitcoinAddress address(params[0].get_str());
567 if (!address.IsValid())
568 throw JSONRPCError(-5, "Invalid ppcoin address");
571 int64 nAmount = AmountFromValue(params[1]);
575 if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
576 wtx.mapValue["comment"] = params[2].get_str();
577 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
578 wtx.mapValue["to"] = params[3].get_str();
580 if (pwalletMain->IsLocked())
581 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
583 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
585 throw JSONRPCError(-4, strError);
587 return wtx.GetHash().GetHex();
590 Value signmessage(const Array& params, bool fHelp)
592 if (fHelp || params.size() != 2)
594 "signmessage <ppcoinaddress> <message>\n"
595 "Sign a message with the private key of an address");
597 if (pwalletMain->IsLocked())
598 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
600 string strAddress = params[0].get_str();
601 string strMessage = params[1].get_str();
603 CBitcoinAddress addr(strAddress);
605 throw JSONRPCError(-3, "Invalid address");
608 if (!pwalletMain->GetKey(addr, key))
609 throw JSONRPCError(-4, "Private key not available");
611 CDataStream ss(SER_GETHASH, 0);
612 ss << strMessageMagic;
615 vector<unsigned char> vchSig;
616 if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig))
617 throw JSONRPCError(-5, "Sign failed");
619 return EncodeBase64(&vchSig[0], vchSig.size());
622 Value verifymessage(const Array& params, bool fHelp)
624 if (fHelp || params.size() != 3)
626 "verifymessage <ppcoinaddress> <signature> <message>\n"
627 "Verify a signed message");
629 string strAddress = params[0].get_str();
630 string strSign = params[1].get_str();
631 string strMessage = params[2].get_str();
633 CBitcoinAddress addr(strAddress);
635 throw JSONRPCError(-3, "Invalid address");
637 bool fInvalid = false;
638 vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
641 throw JSONRPCError(-5, "Malformed base64 encoding");
643 CDataStream ss(SER_GETHASH, 0);
644 ss << strMessageMagic;
648 if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
651 return (CBitcoinAddress(key.GetPubKey()) == addr);
655 Value getreceivedbyaddress(const Array& params, bool fHelp)
657 if (fHelp || params.size() < 1 || params.size() > 2)
659 "getreceivedbyaddress <ppcoinaddress> [minconf=1]\n"
660 "Returns the total amount received by <ppcoinaddress> in transactions with at least [minconf] confirmations.");
663 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
664 CScript scriptPubKey;
665 if (!address.IsValid())
666 throw JSONRPCError(-5, "Invalid ppcoin address");
667 scriptPubKey.SetBitcoinAddress(address);
668 if (!IsMine(*pwalletMain,scriptPubKey))
671 // Minimum confirmations
673 if (params.size() > 1)
674 nMinDepth = params[1].get_int();
678 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
680 const CWalletTx& wtx = (*it).second;
681 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
684 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
685 if (txout.scriptPubKey == scriptPubKey)
686 if (wtx.GetDepthInMainChain() >= nMinDepth)
687 nAmount += txout.nValue;
690 return ValueFromAmount(nAmount);
694 void GetAccountAddresses(string strAccount, set<CBitcoinAddress>& setAddress)
696 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
698 const CBitcoinAddress& address = item.first;
699 const string& strName = item.second;
700 if (strName == strAccount)
701 setAddress.insert(address);
706 Value getreceivedbyaccount(const Array& params, bool fHelp)
708 if (fHelp || params.size() < 1 || params.size() > 2)
710 "getreceivedbyaccount <account> [minconf=1]\n"
711 "Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.");
713 // Minimum confirmations
715 if (params.size() > 1)
716 nMinDepth = params[1].get_int();
718 // Get the set of pub keys assigned to account
719 string strAccount = AccountFromValue(params[0]);
720 set<CBitcoinAddress> setAddress;
721 GetAccountAddresses(strAccount, setAddress);
725 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
727 const CWalletTx& wtx = (*it).second;
728 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
731 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
733 CBitcoinAddress address;
734 if (ExtractAddress(txout.scriptPubKey, address) && pwalletMain->HaveKey(address) && setAddress.count(address))
735 if (wtx.GetDepthInMainChain() >= nMinDepth)
736 nAmount += txout.nValue;
740 return (double)nAmount / (double)COIN;
744 int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth)
748 // Tally wallet transactions
749 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
751 const CWalletTx& wtx = (*it).second;
755 int64 nGenerated, nReceived, nSent, nFee;
756 wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee);
758 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
759 nBalance += nReceived;
760 nBalance += nGenerated - nSent - nFee;
763 // Tally internal accounting entries
764 nBalance += walletdb.GetAccountCreditDebit(strAccount);
769 int64 GetAccountBalance(const string& strAccount, int nMinDepth)
771 CWalletDB walletdb(pwalletMain->strWalletFile);
772 return GetAccountBalance(walletdb, strAccount, nMinDepth);
776 Value getbalance(const Array& params, bool fHelp)
778 if (fHelp || params.size() > 2)
780 "getbalance [account] [minconf=1]\n"
781 "If [account] is not specified, returns the server's total available balance.\n"
782 "If [account] is specified, returns the balance in the account.");
784 if (params.size() == 0)
785 return ValueFromAmount(pwalletMain->GetBalance());
788 if (params.size() > 1)
789 nMinDepth = params[1].get_int();
791 if (params[0].get_str() == "*") {
792 // Calculate total balance a different way from GetBalance()
793 // (GetBalance() sums up all unspent TxOuts)
794 // getbalance and getbalance '*' should always return the same number.
796 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
798 const CWalletTx& wtx = (*it).second;
802 int64 allGeneratedImmature, allGeneratedMature, allFee;
803 allGeneratedImmature = allGeneratedMature = allFee = 0;
804 string strSentAccount;
805 list<pair<CBitcoinAddress, int64> > listReceived;
806 list<pair<CBitcoinAddress, int64> > listSent;
807 wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
808 if (wtx.GetDepthInMainChain() >= nMinDepth)
810 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listReceived)
811 nBalance += r.second;
813 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listSent)
814 nBalance -= r.second;
816 nBalance += allGeneratedMature;
818 return ValueFromAmount(nBalance);
821 string strAccount = AccountFromValue(params[0]);
823 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
825 return ValueFromAmount(nBalance);
829 Value movecmd(const Array& params, bool fHelp)
831 if (fHelp || params.size() < 3 || params.size() > 5)
833 "move <fromaccount> <toaccount> <amount> [minconf=1] [comment]\n"
834 "Move from one account in your wallet to another.");
836 string strFrom = AccountFromValue(params[0]);
837 string strTo = AccountFromValue(params[1]);
838 int64 nAmount = AmountFromValue(params[2]);
839 if (params.size() > 3)
840 // unused parameter, used to be nMinDepth, keep type-checking it though
841 (void)params[3].get_int();
843 if (params.size() > 4)
844 strComment = params[4].get_str();
846 CWalletDB walletdb(pwalletMain->strWalletFile);
847 if (!walletdb.TxnBegin())
848 throw JSONRPCError(-20, "database error");
850 int64 nNow = GetAdjustedTime();
853 CAccountingEntry debit;
854 debit.strAccount = strFrom;
855 debit.nCreditDebit = -nAmount;
857 debit.strOtherAccount = strTo;
858 debit.strComment = strComment;
859 walletdb.WriteAccountingEntry(debit);
862 CAccountingEntry credit;
863 credit.strAccount = strTo;
864 credit.nCreditDebit = nAmount;
866 credit.strOtherAccount = strFrom;
867 credit.strComment = strComment;
868 walletdb.WriteAccountingEntry(credit);
870 if (!walletdb.TxnCommit())
871 throw JSONRPCError(-20, "database error");
877 Value sendfrom(const Array& params, bool fHelp)
879 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
881 "sendfrom <fromaccount> <toppcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
882 "<amount> is a real and is rounded to the nearest 0.000001\n"
883 "requires wallet passphrase to be set with walletpassphrase first");
884 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
886 "sendfrom <fromaccount> <toppcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
887 "<amount> is a real and is rounded to the nearest 0.000001");
889 string strAccount = AccountFromValue(params[0]);
890 CBitcoinAddress address(params[1].get_str());
891 if (!address.IsValid())
892 throw JSONRPCError(-5, "Invalid ppcoin address");
893 int64 nAmount = AmountFromValue(params[2]);
895 if (params.size() > 3)
896 nMinDepth = params[3].get_int();
899 wtx.strFromAccount = strAccount;
900 if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
901 wtx.mapValue["comment"] = params[4].get_str();
902 if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
903 wtx.mapValue["to"] = params[5].get_str();
905 if (pwalletMain->IsLocked())
906 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
909 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
910 if (nAmount > nBalance)
911 throw JSONRPCError(-6, "Account has insufficient funds");
914 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
916 throw JSONRPCError(-4, strError);
918 return wtx.GetHash().GetHex();
922 Value sendmany(const Array& params, bool fHelp)
924 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
926 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
927 "amounts are double-precision floating point numbers\n"
928 "requires wallet passphrase to be set with walletpassphrase first");
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");
934 string strAccount = AccountFromValue(params[0]);
935 Object sendTo = params[1].get_obj();
937 if (params.size() > 2)
938 nMinDepth = params[2].get_int();
941 wtx.strFromAccount = strAccount;
942 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
943 wtx.mapValue["comment"] = params[3].get_str();
945 set<CBitcoinAddress> setAddress;
946 vector<pair<CScript, int64> > vecSend;
948 int64 totalAmount = 0;
949 BOOST_FOREACH(const Pair& s, sendTo)
951 CBitcoinAddress address(s.name_);
952 if (!address.IsValid())
953 throw JSONRPCError(-5, string("Invalid ppcoin address:")+s.name_);
955 if (setAddress.count(address))
956 throw JSONRPCError(-8, string("Invalid parameter, duplicated address: ")+s.name_);
957 setAddress.insert(address);
959 CScript scriptPubKey;
960 scriptPubKey.SetBitcoinAddress(address);
961 int64 nAmount = AmountFromValue(s.value_);
962 totalAmount += nAmount;
964 vecSend.push_back(make_pair(scriptPubKey, nAmount));
967 if (pwalletMain->IsLocked())
968 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
969 if (fWalletUnlockStakeOnly)
970 throw JSONRPCError(-13, "Error: Wallet unlocked for coinstake only.");
973 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
974 if (totalAmount > nBalance)
975 throw JSONRPCError(-6, "Account has insufficient funds");
978 CReserveKey keyChange(pwalletMain);
979 int64 nFeeRequired = 0;
980 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
983 if (totalAmount + nFeeRequired > pwalletMain->GetBalance())
984 throw JSONRPCError(-6, "Insufficient funds");
985 throw JSONRPCError(-4, "Transaction creation failed");
987 if (!pwalletMain->CommitTransaction(wtx, keyChange))
988 throw JSONRPCError(-4, "Transaction commit failed");
990 return wtx.GetHash().GetHex();
993 Value addmultisigaddress(const Array& params, bool fHelp)
995 if (fHelp || params.size() < 2 || params.size() > 3)
997 string msg = "addmultisigaddress <nrequired> <'[\"key\",\"key\"]'> [account]\n"
998 "Add a nrequired-to-sign multisignature address to the wallet\"\n"
999 "each key is a bitcoin address or hex-encoded public key\n"
1000 "If [account] is specified, assign address to [account].";
1001 throw runtime_error(msg);
1004 int nRequired = params[0].get_int();
1005 const Array& keys = params[1].get_array();
1007 if (params.size() > 2)
1008 strAccount = AccountFromValue(params[2]);
1010 // Gather public keys
1012 throw runtime_error("a multisignature address must require at least one key to redeem");
1013 if ((int)keys.size() < nRequired)
1014 throw runtime_error(
1015 strprintf("not enough keys supplied "
1016 "(got %d keys, but need at least %d to redeem)", keys.size(), nRequired));
1017 std::vector<CKey> pubkeys;
1018 pubkeys.resize(keys.size());
1019 for (unsigned int i = 0; i < keys.size(); i++)
1021 const std::string& ks = keys[i].get_str();
1023 // Case 1: bitcoin address and we have full public key:
1024 CBitcoinAddress address(ks);
1025 if (address.IsValid())
1027 if (address.IsScript())
1028 throw runtime_error(
1029 strprintf("%s is a pay-to-script address",ks.c_str()));
1030 std::vector<unsigned char> vchPubKey;
1031 if (!pwalletMain->GetPubKey(address, vchPubKey))
1032 throw runtime_error(
1033 strprintf("no full public key for address %s",ks.c_str()));
1034 if (vchPubKey.empty() || !pubkeys[i].SetPubKey(vchPubKey))
1035 throw runtime_error(" Invalid public key: "+ks);
1038 // Case 2: hex public key
1041 vector<unsigned char> vchPubKey = ParseHex(ks);
1042 if (vchPubKey.empty() || !pubkeys[i].SetPubKey(vchPubKey))
1043 throw runtime_error(" Invalid public key: "+ks);
1047 throw runtime_error(" Invalid public key: "+ks);
1051 // Construct using pay-to-script-hash:
1053 inner.SetMultisig(nRequired, pubkeys);
1055 uint160 scriptHash = Hash160(inner);
1056 CScript scriptPubKey;
1057 scriptPubKey.SetPayToScriptHash(inner);
1058 pwalletMain->AddCScript(inner);
1059 CBitcoinAddress address;
1060 address.SetScriptHash160(scriptHash);
1062 pwalletMain->SetAddressBookName(address, strAccount);
1063 return address.ToString();
1074 nConf = std::numeric_limits<int>::max();
1078 Value ListReceived(const Array& params, bool fByAccounts)
1080 // Minimum confirmations
1082 if (params.size() > 0)
1083 nMinDepth = params[0].get_int();
1085 // Whether to include empty accounts
1086 bool fIncludeEmpty = false;
1087 if (params.size() > 1)
1088 fIncludeEmpty = params[1].get_bool();
1091 map<CBitcoinAddress, tallyitem> mapTally;
1092 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1094 const CWalletTx& wtx = (*it).second;
1096 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
1099 int nDepth = wtx.GetDepthInMainChain();
1100 if (nDepth < nMinDepth)
1103 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
1105 CBitcoinAddress address;
1106 if (!ExtractAddress(txout.scriptPubKey, address) || !pwalletMain->HaveKey(address) || !address.IsValid())
1109 tallyitem& item = mapTally[address];
1110 item.nAmount += txout.nValue;
1111 item.nConf = min(item.nConf, nDepth);
1117 map<string, tallyitem> mapAccountTally;
1118 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
1120 const CBitcoinAddress& address = item.first;
1121 const string& strAccount = item.second;
1122 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
1123 if (it == mapTally.end() && !fIncludeEmpty)
1127 int nConf = std::numeric_limits<int>::max();
1128 if (it != mapTally.end())
1130 nAmount = (*it).second.nAmount;
1131 nConf = (*it).second.nConf;
1136 tallyitem& item = mapAccountTally[strAccount];
1137 item.nAmount += nAmount;
1138 item.nConf = min(item.nConf, nConf);
1143 obj.push_back(Pair("address", address.ToString()));
1144 obj.push_back(Pair("account", strAccount));
1145 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1146 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1153 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
1155 int64 nAmount = (*it).second.nAmount;
1156 int nConf = (*it).second.nConf;
1158 obj.push_back(Pair("account", (*it).first));
1159 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1160 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1168 Value listreceivedbyaddress(const Array& params, bool fHelp)
1170 if (fHelp || params.size() > 2)
1171 throw runtime_error(
1172 "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
1173 "[minconf] is the minimum number of confirmations before payments are included.\n"
1174 "[includeempty] whether to include addresses that haven't received any payments.\n"
1175 "Returns an array of objects containing:\n"
1176 " \"address\" : receiving address\n"
1177 " \"account\" : the account of the receiving address\n"
1178 " \"amount\" : total amount received by the address\n"
1179 " \"confirmations\" : number of confirmations of the most recent transaction included");
1181 return ListReceived(params, false);
1184 Value listreceivedbyaccount(const Array& params, bool fHelp)
1186 if (fHelp || params.size() > 2)
1187 throw runtime_error(
1188 "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
1189 "[minconf] is the minimum number of confirmations before payments are included.\n"
1190 "[includeempty] whether to include accounts that haven't received any payments.\n"
1191 "Returns an array of objects containing:\n"
1192 " \"account\" : the account of the receiving addresses\n"
1193 " \"amount\" : total amount received by addresses with this account\n"
1194 " \"confirmations\" : number of confirmations of the most recent transaction included");
1196 return ListReceived(params, true);
1199 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret)
1201 int64 nGeneratedImmature, nGeneratedMature, nFee;
1202 string strSentAccount;
1203 list<pair<CBitcoinAddress, int64> > listReceived;
1204 list<pair<CBitcoinAddress, int64> > listSent;
1206 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1208 bool fAllAccounts = (strAccount == string("*"));
1210 // Generated blocks assigned to account ""
1211 if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == ""))
1214 entry.push_back(Pair("account", string("")));
1215 if (nGeneratedImmature)
1217 entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
1218 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
1222 entry.push_back(Pair("category", "generate"));
1223 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
1226 WalletTxToJSON(wtx, entry);
1227 ret.push_back(entry);
1231 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1233 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1236 entry.push_back(Pair("account", strSentAccount));
1237 entry.push_back(Pair("address", s.first.ToString()));
1238 entry.push_back(Pair("category", "send"));
1239 entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1240 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1242 WalletTxToJSON(wtx, entry);
1243 ret.push_back(entry);
1248 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1250 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1253 if (pwalletMain->mapAddressBook.count(r.first))
1254 account = pwalletMain->mapAddressBook[r.first];
1255 if (fAllAccounts || (account == strAccount))
1258 entry.push_back(Pair("account", account));
1259 entry.push_back(Pair("address", r.first.ToString()));
1260 entry.push_back(Pair("category", "receive"));
1261 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1263 WalletTxToJSON(wtx, entry);
1264 ret.push_back(entry);
1270 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1272 bool fAllAccounts = (strAccount == string("*"));
1274 if (fAllAccounts || acentry.strAccount == strAccount)
1277 entry.push_back(Pair("account", acentry.strAccount));
1278 entry.push_back(Pair("category", "move"));
1279 entry.push_back(Pair("time", (boost::int64_t)acentry.nTime));
1280 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1281 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1282 entry.push_back(Pair("comment", acentry.strComment));
1283 ret.push_back(entry);
1287 Value listtransactions(const Array& params, bool fHelp)
1289 if (fHelp || params.size() > 3)
1290 throw runtime_error(
1291 "listtransactions [account] [count=10] [from=0]\n"
1292 "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1294 string strAccount = "*";
1295 if (params.size() > 0)
1296 strAccount = params[0].get_str();
1298 if (params.size() > 1)
1299 nCount = params[1].get_int();
1301 if (params.size() > 2)
1302 nFrom = params[2].get_int();
1305 throw JSONRPCError(-8, "Negative count");
1307 throw JSONRPCError(-8, "Negative from");
1310 CWalletDB walletdb(pwalletMain->strWalletFile);
1312 // First: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap.
1313 typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
1314 typedef multimap<int64, TxPair > TxItems;
1317 // Note: maintaining indices in the database of (account,time) --> txid and (account, time) --> acentry
1318 // would make this much faster for applications that do this a lot.
1319 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1321 CWalletTx* wtx = &((*it).second);
1322 txByTime.insert(make_pair(wtx->GetTxTime(), TxPair(wtx, (CAccountingEntry*)0)));
1324 list<CAccountingEntry> acentries;
1325 walletdb.ListAccountCreditDebit(strAccount, acentries);
1326 BOOST_FOREACH(CAccountingEntry& entry, acentries)
1328 txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
1331 // iterate backwards until we have nCount items to return:
1332 for (TxItems::reverse_iterator it = txByTime.rbegin(); it != txByTime.rend(); ++it)
1334 CWalletTx *const pwtx = (*it).second.first;
1336 ListTransactions(*pwtx, strAccount, 0, true, ret);
1337 CAccountingEntry *const pacentry = (*it).second.second;
1339 AcentryToJSON(*pacentry, strAccount, ret);
1341 if (ret.size() >= (nCount+nFrom)) break;
1343 // ret is newest to oldest
1345 if (nFrom > (int)ret.size())
1347 if ((nFrom + nCount) > (int)ret.size())
1348 nCount = ret.size() - nFrom;
1349 Array::iterator first = ret.begin();
1350 std::advance(first, nFrom);
1351 Array::iterator last = ret.begin();
1352 std::advance(last, nFrom+nCount);
1354 if (last != ret.end()) ret.erase(last, ret.end());
1355 if (first != ret.begin()) ret.erase(ret.begin(), first);
1357 std::reverse(ret.begin(), ret.end()); // Return oldest to newest
1362 Value listaccounts(const Array& params, bool fHelp)
1364 if (fHelp || params.size() > 1)
1365 throw runtime_error(
1366 "listaccounts [minconf=1]\n"
1367 "Returns Object that has account names as keys, account balances as values.");
1370 if (params.size() > 0)
1371 nMinDepth = params[0].get_int();
1373 map<string, int64> mapAccountBalances;
1374 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& entry, pwalletMain->mapAddressBook) {
1375 if (pwalletMain->HaveKey(entry.first)) // This address belongs to me
1376 mapAccountBalances[entry.second] = 0;
1379 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1381 const CWalletTx& wtx = (*it).second;
1382 int64 nGeneratedImmature, nGeneratedMature, nFee;
1383 string strSentAccount;
1384 list<pair<CBitcoinAddress, int64> > listReceived;
1385 list<pair<CBitcoinAddress, int64> > listSent;
1386 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1387 mapAccountBalances[strSentAccount] -= nFee;
1388 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1389 mapAccountBalances[strSentAccount] -= s.second;
1390 if (wtx.GetDepthInMainChain() >= nMinDepth)
1392 mapAccountBalances[""] += nGeneratedMature;
1393 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1394 if (pwalletMain->mapAddressBook.count(r.first))
1395 mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1397 mapAccountBalances[""] += r.second;
1401 list<CAccountingEntry> acentries;
1402 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1403 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1404 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1407 BOOST_FOREACH(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) {
1408 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1413 Value listsinceblock(const Array& params, bool fHelp)
1416 throw runtime_error(
1417 "listsinceblock [blockhash] [target-confirmations]\n"
1418 "Get all transactions in blocks since block [blockhash], or all transactions if omitted");
1420 CBlockIndex *pindex = NULL;
1421 int target_confirms = 1;
1423 if (params.size() > 0)
1425 uint256 blockId = 0;
1427 blockId.SetHex(params[0].get_str());
1428 pindex = CBlockLocator(blockId).GetBlockIndex();
1431 if (params.size() > 1)
1433 target_confirms = params[1].get_int();
1435 if (target_confirms < 1)
1436 throw JSONRPCError(-8, "Invalid parameter");
1439 int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1;
1443 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1445 CWalletTx tx = (*it).second;
1447 if (depth == -1 || tx.GetDepthInMainChain() < depth)
1448 ListTransactions(tx, "*", 0, true, transactions);
1453 if (target_confirms == 1)
1455 lastblock = hashBestChain;
1459 int target_height = pindexBest->nHeight + 1 - target_confirms;
1462 for (block = pindexBest;
1463 block && block->nHeight > target_height;
1464 block = block->pprev) { }
1466 lastblock = block ? block->GetBlockHash() : 0;
1470 ret.push_back(Pair("transactions", transactions));
1471 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1476 Value gettransaction(const Array& params, bool fHelp)
1478 if (fHelp || params.size() != 1)
1479 throw runtime_error(
1480 "gettransaction <txid>\n"
1481 "Get detailed information about <txid>");
1484 hash.SetHex(params[0].get_str());
1488 if (!pwalletMain->mapWallet.count(hash))
1489 throw JSONRPCError(-5, "Invalid or non-wallet transaction id");
1490 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1492 int64 nCredit = wtx.GetCredit();
1493 int64 nDebit = wtx.GetDebit();
1494 int64 nNet = nCredit - nDebit;
1495 int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
1497 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1499 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1501 WalletTxToJSON(pwalletMain->mapWallet[hash], entry);
1504 ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
1505 entry.push_back(Pair("details", details));
1511 Value backupwallet(const Array& params, bool fHelp)
1513 if (fHelp || params.size() != 1)
1514 throw runtime_error(
1515 "backupwallet <destination>\n"
1516 "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1518 string strDest = params[0].get_str();
1519 BackupWallet(*pwalletMain, strDest);
1525 Value keypoolrefill(const Array& params, bool fHelp)
1527 if (pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1528 throw runtime_error(
1530 "Fills the keypool, requires wallet passphrase to be set.");
1531 if (!pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1532 throw runtime_error(
1534 "Fills the keypool.");
1536 if (pwalletMain->IsLocked())
1537 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
1539 pwalletMain->TopUpKeyPool();
1541 if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100))
1542 throw JSONRPCError(-4, "Error refreshing keypool.");
1548 void ThreadTopUpKeyPool(void* parg)
1550 pwalletMain->TopUpKeyPool();
1553 void ThreadCleanWalletPassphrase(void* parg)
1555 int64 nMyWakeTime = GetTimeMillis() + *((int64*)parg) * 1000;
1557 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1559 if (nWalletUnlockTime == 0)
1561 nWalletUnlockTime = nMyWakeTime;
1565 if (nWalletUnlockTime==0)
1567 int64 nToSleep = nWalletUnlockTime - GetTimeMillis();
1571 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1573 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1577 if (nWalletUnlockTime)
1579 nWalletUnlockTime = 0;
1580 pwalletMain->Lock();
1585 if (nWalletUnlockTime < nMyWakeTime)
1586 nWalletUnlockTime = nMyWakeTime;
1589 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1591 delete (int64*)parg;
1594 Value walletpassphrase(const Array& params, bool fHelp)
1596 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 3))
1597 throw runtime_error(
1598 "walletpassphrase <passphrase> <timeout> [stakeonly]\n"
1599 "Stores the wallet decryption key in memory for <timeout> seconds.\n"
1600 "stakeonly is optional true/false allowing only stake creation.");
1603 if (!pwalletMain->IsCrypted())
1604 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1606 if (!pwalletMain->IsLocked())
1607 throw JSONRPCError(-17, "Error: Wallet is already unlocked, use walletlock first if need to change unlock settings.");
1609 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1610 SecureString strWalletPass;
1611 strWalletPass.reserve(100);
1612 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1613 // Alternately, find a way to make params[0] mlock()'d to begin with.
1614 strWalletPass = params[0].get_str().c_str();
1616 if (strWalletPass.length() > 0)
1618 if (!pwalletMain->Unlock(strWalletPass))
1619 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1622 throw runtime_error(
1623 "walletpassphrase <passphrase> <timeout>\n"
1624 "Stores the wallet decryption key in memory for <timeout> seconds.");
1626 CreateThread(ThreadTopUpKeyPool, NULL);
1627 int64* pnSleepTime = new int64(params[1].get_int64());
1628 CreateThread(ThreadCleanWalletPassphrase, pnSleepTime);
1630 // ppcoin: if user OS account compromised prevent trivial sendmoney commands
1631 if (params.size() > 2)
1632 fWalletUnlockStakeOnly = params[2].get_bool();
1634 fWalletUnlockStakeOnly = false;
1640 Value walletpassphrasechange(const Array& params, bool fHelp)
1642 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1643 throw runtime_error(
1644 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1645 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1648 if (!pwalletMain->IsCrypted())
1649 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1651 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1652 // Alternately, find a way to make params[0] mlock()'d to begin with.
1653 SecureString strOldWalletPass;
1654 strOldWalletPass.reserve(100);
1655 strOldWalletPass = params[0].get_str().c_str();
1657 SecureString strNewWalletPass;
1658 strNewWalletPass.reserve(100);
1659 strNewWalletPass = params[1].get_str().c_str();
1661 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1662 throw runtime_error(
1663 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1664 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1666 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1667 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1673 Value walletlock(const Array& params, bool fHelp)
1675 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1676 throw runtime_error(
1678 "Removes the wallet encryption key from memory, locking the wallet.\n"
1679 "After calling this method, you will need to call walletpassphrase again\n"
1680 "before being able to call any methods which require the wallet to be unlocked.");
1683 if (!pwalletMain->IsCrypted())
1684 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called.");
1687 LOCK(cs_nWalletUnlockTime);
1688 pwalletMain->Lock();
1689 nWalletUnlockTime = 0;
1696 Value encryptwallet(const Array& params, bool fHelp)
1698 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1699 throw runtime_error(
1700 "encryptwallet <passphrase>\n"
1701 "Encrypts the wallet with <passphrase>.");
1704 if (pwalletMain->IsCrypted())
1705 throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
1707 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1708 // Alternately, find a way to make params[0] mlock()'d to begin with.
1709 SecureString strWalletPass;
1710 strWalletPass.reserve(100);
1711 strWalletPass = params[0].get_str().c_str();
1713 if (strWalletPass.length() < 1)
1714 throw runtime_error(
1715 "encryptwallet <passphrase>\n"
1716 "Encrypts the wallet with <passphrase>.");
1718 if (!pwalletMain->EncryptWallet(strWalletPass))
1719 throw JSONRPCError(-16, "Error: Failed to encrypt the wallet.");
1721 // BDB seems to have a bad habit of writing old data into
1722 // slack space in .dat files; that is bad if the old data is
1723 // unencrypted private keys. So:
1725 return "wallet encrypted; ppcoin server stopping, restart to run with encrypted wallet";
1729 Value validateaddress(const Array& params, bool fHelp)
1731 if (fHelp || params.size() != 1)
1732 throw runtime_error(
1733 "validateaddress <ppcoinaddress>\n"
1734 "Return information about <ppcoinaddress>.");
1736 CBitcoinAddress address(params[0].get_str());
1737 bool isValid = address.IsValid();
1740 ret.push_back(Pair("isvalid", isValid));
1743 // Call Hash160ToAddress() so we always return current ADDRESSVERSION
1744 // version of the address:
1745 string currentAddress = address.ToString();
1746 ret.push_back(Pair("address", currentAddress));
1747 if (pwalletMain->HaveKey(address))
1749 ret.push_back(Pair("ismine", true));
1750 std::vector<unsigned char> vchPubKey;
1751 pwalletMain->GetPubKey(address, vchPubKey);
1752 ret.push_back(Pair("pubkey", HexStr(vchPubKey)));
1754 key.SetPubKey(vchPubKey);
1755 ret.push_back(Pair("iscompressed", key.IsCompressed()));
1757 else if (pwalletMain->HaveCScript(address.GetHash160()))
1759 ret.push_back(Pair("isscript", true));
1761 pwalletMain->GetCScript(address.GetHash160(), subscript);
1762 ret.push_back(Pair("ismine", ::IsMine(*pwalletMain, subscript)));
1763 std::vector<CBitcoinAddress> addresses;
1764 txnouttype whichType;
1766 ExtractAddresses(subscript, whichType, addresses, nRequired);
1767 ret.push_back(Pair("script", GetTxnOutputType(whichType)));
1769 BOOST_FOREACH(const CBitcoinAddress& addr, addresses)
1770 a.push_back(addr.ToString());
1771 ret.push_back(Pair("addresses", a));
1772 if (whichType == TX_MULTISIG)
1773 ret.push_back(Pair("sigsrequired", nRequired));
1776 ret.push_back(Pair("ismine", false));
1777 if (pwalletMain->mapAddressBook.count(address))
1778 ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
1783 Value getwork(const Array& params, bool fHelp)
1785 if (fHelp || params.size() > 1)
1786 throw runtime_error(
1788 "If [data] is not specified, returns formatted hash data to work on:\n"
1789 " \"midstate\" : precomputed hash state after hashing the first half of the data (DEPRECATED)\n" // deprecated
1790 " \"data\" : block data\n"
1791 " \"hash1\" : formatted hash buffer for second hash (DEPRECATED)\n" // deprecated
1792 " \"target\" : little endian hash target\n"
1793 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1796 throw JSONRPCError(-9, "PPCoin is not connected!");
1798 if (IsInitialBlockDownload())
1799 throw JSONRPCError(-10, "PPCoin is downloading blocks...");
1801 typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
1802 static mapNewBlock_t mapNewBlock;
1803 static vector<CBlock*> vNewBlock;
1804 static CReserveKey reservekey(pwalletMain);
1806 if (params.size() == 0)
1809 static unsigned int nTransactionsUpdatedLast;
1810 static CBlockIndex* pindexPrev;
1811 static int64 nStart;
1812 static CBlock* pblock;
1813 if (pindexPrev != pindexBest ||
1814 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
1816 if (pindexPrev != pindexBest)
1818 // Deallocate old blocks since they're obsolete now
1819 mapNewBlock.clear();
1820 BOOST_FOREACH(CBlock* pblock, vNewBlock)
1824 nTransactionsUpdatedLast = nTransactionsUpdated;
1825 pindexPrev = pindexBest;
1829 pblock = CreateNewBlock(pwalletMain, true);
1831 throw JSONRPCError(-7, "Out of memory");
1832 vNewBlock.push_back(pblock);
1836 pblock->UpdateTime(pindexPrev);
1839 // Update nExtraNonce
1840 static unsigned int nExtraNonce = 0;
1841 IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
1844 mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
1846 // Prebuild hash buffers
1850 FormatHashBuffers(pblock, pmidstate, pdata, phash1);
1852 uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
1855 result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate)))); // deprecated
1856 result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata))));
1857 result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1)))); // deprecated
1858 result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
1864 vector<unsigned char> vchData = ParseHex(params[0].get_str());
1865 if (vchData.size() != 128)
1866 throw JSONRPCError(-8, "Invalid parameter");
1867 CBlock* pdata = (CBlock*)&vchData[0];
1870 for (int i = 0; i < 128/4; i++)
1871 ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]);
1874 if (!mapNewBlock.count(pdata->hashMerkleRoot))
1876 CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
1878 pblock->nTime = pdata->nTime;
1879 pblock->nNonce = pdata->nNonce;
1880 pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
1881 pblock->hashMerkleRoot = pblock->BuildMerkleTree();
1882 if (!pblock->SignBlock(*pwalletMain))
1883 throw JSONRPCError(-100, "Unable to sign block");
1885 return CheckWork(pblock, *pwalletMain, reservekey);
1890 Value getmemorypool(const Array& params, bool fHelp)
1892 if (fHelp || params.size() > 1)
1893 throw runtime_error(
1894 "getmemorypool [data]\n"
1895 "If [data] is not specified, returns data needed to construct a block to work on:\n"
1896 " \"version\" : block version\n"
1897 " \"previousblockhash\" : hash of current highest block\n"
1898 " \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
1899 " \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
1900 " \"coinbaseflags\" : data that should be included in coinbase so support for new features can be judged\n"
1901 " \"time\" : timestamp appropriate for next block\n"
1902 " \"mintime\" : minimum timestamp appropriate for next block\n"
1903 " \"curtime\" : current timestamp\n"
1904 " \"bits\" : compressed target of next block\n"
1905 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1907 if (params.size() == 0)
1910 throw JSONRPCError(-9, "PPCoin is not connected!");
1912 if (IsInitialBlockDownload())
1913 throw JSONRPCError(-10, "PPCoin is downloading blocks...");
1915 static CReserveKey reservekey(pwalletMain);
1918 static unsigned int nTransactionsUpdatedLast;
1919 static CBlockIndex* pindexPrev;
1920 static int64 nStart;
1921 static CBlock* pblock;
1922 if (pindexPrev != pindexBest ||
1923 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5))
1925 nTransactionsUpdatedLast = nTransactionsUpdated;
1926 pindexPrev = pindexBest;
1932 pblock = CreateNewBlock(pwalletMain);
1934 throw JSONRPCError(-7, "Out of memory");
1938 pblock->UpdateTime(pindexPrev);
1942 BOOST_FOREACH(CTransaction tx, pblock->vtx) {
1943 if(tx.IsCoinBase() || tx.IsCoinStake())
1946 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
1949 transactions.push_back(HexStr(ssTx.begin(), ssTx.end()));
1953 result.push_back(Pair("version", pblock->nVersion));
1954 result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
1955 result.push_back(Pair("transactions", transactions));
1956 result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
1957 result.push_back(Pair("coinbaseflags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end())));
1958 result.push_back(Pair("time", (int64_t)pblock->nTime));
1959 result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1));
1960 result.push_back(Pair("curtime", (int64_t)GetAdjustedTime()));
1961 result.push_back(Pair("bits", HexBits(pblock->nBits)));
1968 CDataStream ssBlock(ParseHex(params[0].get_str()), SER_NETWORK, PROTOCOL_VERSION);
1972 return ProcessBlock(NULL, &pblock);
1976 Value getblockhash(const Array& params, bool fHelp)
1978 if (fHelp || params.size() != 1)
1979 throw runtime_error(
1980 "getblockhash <index>\n"
1981 "Returns hash of block in best-block-chain at <index>.");
1983 int nHeight = params[0].get_int();
1984 if (nHeight < 0 || nHeight > nBestHeight)
1985 throw runtime_error("Block number out of range.");
1988 CBlockIndex* pblockindex = mapBlockIndex[hashBestChain];
1989 while (pblockindex->nHeight > nHeight)
1990 pblockindex = pblockindex->pprev;
1991 return pblockindex->phashBlock->GetHex();
1994 Value getblock(const Array& params, bool fHelp)
1996 if (fHelp || params.size() != 1)
1997 throw runtime_error(
1999 "Returns details of a block with given block-hash.");
2001 std::string strHash = params[0].get_str();
2002 uint256 hash(strHash);
2004 if (mapBlockIndex.count(hash) == 0)
2005 throw JSONRPCError(-5, "Block not found");
2008 CBlockIndex* pblockindex = mapBlockIndex[hash];
2009 block.ReadFromDisk(pblockindex, true);
2011 return blockToJSON(block, pblockindex);
2015 // ppcoin: get information of sync-checkpoint
2016 Value getcheckpoint(const Array& params, bool fHelp)
2018 if (fHelp || params.size() != 0)
2019 throw runtime_error(
2021 "Show info of synchronized checkpoint.\n");
2024 CBlockIndex* pindexCheckpoint;
2026 result.push_back(Pair("synccheckpoint", Checkpoints::hashSyncCheckpoint.ToString().c_str()));
2027 pindexCheckpoint = mapBlockIndex[Checkpoints::hashSyncCheckpoint];
2028 result.push_back(Pair("height", pindexCheckpoint->nHeight));
2029 result.push_back(Pair("timestamp", DateTimeStrFormat(pindexCheckpoint->GetBlockTime()).c_str()));
2030 if (mapArgs.count("-checkpointkey"))
2031 result.push_back(Pair("checkpointmaster", true));
2037 // ppcoin: reserve balance from being staked for network protection
2038 Value reservebalance(const Array& params, bool fHelp)
2040 if (fHelp || params.size() > 2)
2041 throw runtime_error(
2042 "reservebalance [<reserve> [amount]]\n"
2043 "<reserve> is true or false to turn balance reserve on or off.\n"
2044 "<amount> is a real and rounded to cent.\n"
2045 "Set reserve amount not participating in network protection.\n"
2046 "If no parameters provided current setting is printed.\n");
2048 if (params.size() > 0)
2050 bool fReserve = params[0].get_bool();
2053 if (params.size() == 1)
2054 throw runtime_error("must provide amount to reserve balance.\n");
2055 int64 nAmount = AmountFromValue(params[1]);
2056 nAmount = (nAmount / CENT) * CENT; // round to cent
2058 throw runtime_error("amount cannot be negative.\n");
2059 mapArgs["-reservebalance"] = FormatMoney(nAmount).c_str();
2063 if (params.size() > 1)
2064 throw runtime_error("cannot specify amount to turn off reserve.\n");
2065 mapArgs["-reservebalance"] = "0";
2070 int64 nReserveBalance = 0;
2071 if (mapArgs.count("-reservebalance") && !ParseMoney(mapArgs["-reservebalance"], nReserveBalance))
2072 throw runtime_error("invalid reserve balance amount\n");
2073 result.push_back(Pair("reserve", (nReserveBalance > 0)));
2074 result.push_back(Pair("amount", ValueFromAmount(nReserveBalance)));
2079 // ppcoin: check wallet integrity
2080 Value checkwallet(const Array& params, bool fHelp)
2082 if (fHelp || params.size() > 0)
2083 throw runtime_error(
2085 "Check wallet for integrity.\n");
2088 int64 nBalanceInQuestion;
2089 if (!pwalletMain->CheckSpentCoins(nMismatchSpent, nBalanceInQuestion))
2092 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
2093 result.push_back(Pair("amount in question", ValueFromAmount(nBalanceInQuestion)));
2100 // ppcoin: repair wallet
2101 Value repairwallet(const Array& params, bool fHelp)
2103 if (fHelp || params.size() > 0)
2104 throw runtime_error(
2106 "Repair wallet if checkwallet reports any problem.\n");
2109 int64 nBalanceInQuestion;
2110 pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion);
2112 if (nMismatchSpent == 0)
2114 result.push_back(Pair("wallet check passed", true));
2118 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
2119 result.push_back(Pair("amount affected by repair", ValueFromAmount(nBalanceInQuestion)));
2124 // ppcoin: make a public-private key pair
2125 Value makekeypair(const Array& params, bool fHelp)
2127 if (fHelp || params.size() > 1)
2128 throw runtime_error(
2129 "makekeypair [prefix]\n"
2130 "Make a public/private key pair.\n"
2131 "[prefix] is optional preferred prefix for the public key.\n");
2133 string strPrefix = "";
2134 if (params.size() > 0)
2135 strPrefix = params[0].get_str();
2141 key.MakeNewKey(false);
2143 } while (nCount < 10000 && strPrefix != HexStr(key.GetPubKey()).substr(0, strPrefix.size()));
2145 if (strPrefix != HexStr(key.GetPubKey()).substr(0, strPrefix.size()))
2148 CPrivKey vchPrivKey = key.GetPrivKey();
2150 result.push_back(Pair("PrivateKey", HexStr<CPrivKey::iterator>(vchPrivKey.begin(), vchPrivKey.end())));
2151 result.push_back(Pair("PublicKey", HexStr(key.GetPubKey())));
2155 extern CCriticalSection cs_mapAlerts;
2156 extern map<uint256, CAlert> mapAlerts;
2158 // ppcoin: send alert.
2159 // There is a known deadlock situation with ThreadMessageHandler
2160 // ThreadMessageHandler: holds cs_vSend and acquiring cs_main in SendMessages()
2161 // ThreadRPCServer: holds cs_main and acquiring cs_vSend in alert.RelayTo()/PushMessage()/BeginMessage()
2162 Value sendalert(const Array& params, bool fHelp)
2164 if (fHelp || params.size() < 6)
2165 throw runtime_error(
2166 "sendalert <message> <privatekey> <minver> <maxver> <priority> <id> [cancelupto]\n"
2167 "<message> is the alert text message\n"
2168 "<privatekey> is hex string of alert master private key\n"
2169 "<minver> is the minimum applicable internal client version\n"
2170 "<maxver> is the maximum applicable internal client version\n"
2171 "<priority> is integer priority number\n"
2172 "<id> is the alert id\n"
2173 "[cancelupto] cancels all alert id's up to this number\n"
2174 "Returns true or false.");
2179 alert.strStatusBar = params[0].get_str();
2180 alert.nMinVer = params[2].get_int();
2181 alert.nMaxVer = params[3].get_int();
2182 alert.nPriority = params[4].get_int();
2183 alert.nID = params[5].get_int();
2184 if (params.size() > 6)
2185 alert.nCancel = params[6].get_int();
2186 alert.nVersion = PROTOCOL_VERSION;
2187 alert.nRelayUntil = GetAdjustedTime() + 365*24*60*60;
2188 alert.nExpiration = GetAdjustedTime() + 365*24*60*60;
2190 CDataStream sMsg(SER_NETWORK, PROTOCOL_VERSION);
2191 sMsg << (CUnsignedAlert)alert;
2192 alert.vchMsg = vector<unsigned char>(sMsg.begin(), sMsg.end());
2194 vector<unsigned char> vchPrivKey = ParseHex(params[1].get_str());
2195 key.SetPrivKey(CPrivKey(vchPrivKey.begin(), vchPrivKey.end())); // if key is not correct openssl may crash
2196 if (!key.Sign(Hash(alert.vchMsg.begin(), alert.vchMsg.end()), alert.vchSig))
2197 throw runtime_error(
2198 "Unable to sign alert, check private key?\n");
2199 if(!alert.ProcessAlert())
2200 throw runtime_error(
2201 "Failed to process alert.\n");
2205 BOOST_FOREACH(CNode* pnode, vNodes)
2206 alert.RelayTo(pnode);
2210 result.push_back(Pair("strStatusBar", alert.strStatusBar));
2211 result.push_back(Pair("nVersion", alert.nVersion));
2212 result.push_back(Pair("nMinVer", alert.nMinVer));
2213 result.push_back(Pair("nMaxVer", alert.nMaxVer));
2214 result.push_back(Pair("nPriority", alert.nPriority));
2215 result.push_back(Pair("nID", alert.nID));
2216 if (alert.nCancel > 0)
2217 result.push_back(Pair("nCancel", alert.nCancel));
2228 static const CRPCCommand vRPCCommands[] =
2229 { // name function safe mode?
2230 // ------------------------ ----------------------- ----------
2231 { "help", &help, true },
2232 { "stop", &stop, true },
2233 { "getblockcount", &getblockcount, true },
2234 { "getblocknumber", &getblocknumber, true },
2235 { "getconnectioncount", &getconnectioncount, true },
2236 { "getdifficulty", &getdifficulty, true },
2237 { "getgenerate", &getgenerate, true },
2238 { "setgenerate", &setgenerate, true },
2239 { "gethashespersec", &gethashespersec, true },
2240 { "getinfo", &getinfo, true },
2241 { "getmininginfo", &getmininginfo, true },
2242 { "getnewaddress", &getnewaddress, true },
2243 { "getaccountaddress", &getaccountaddress, true },
2244 { "setaccount", &setaccount, true },
2245 { "getaccount", &getaccount, false },
2246 { "getaddressesbyaccount", &getaddressesbyaccount, true },
2247 { "sendtoaddress", &sendtoaddress, false },
2248 { "getreceivedbyaddress", &getreceivedbyaddress, false },
2249 { "getreceivedbyaccount", &getreceivedbyaccount, false },
2250 { "listreceivedbyaddress", &listreceivedbyaddress, false },
2251 { "listreceivedbyaccount", &listreceivedbyaccount, false },
2252 { "backupwallet", &backupwallet, true },
2253 { "keypoolrefill", &keypoolrefill, true },
2254 { "walletpassphrase", &walletpassphrase, true },
2255 { "walletpassphrasechange", &walletpassphrasechange, false },
2256 { "walletlock", &walletlock, true },
2257 { "encryptwallet", &encryptwallet, false },
2258 { "validateaddress", &validateaddress, true },
2259 { "getbalance", &getbalance, false },
2260 { "move", &movecmd, false },
2261 { "sendfrom", &sendfrom, false },
2262 { "sendmany", &sendmany, false },
2263 { "addmultisigaddress", &addmultisigaddress, false },
2264 { "getblock", &getblock, false },
2265 { "getblockhash", &getblockhash, false },
2266 { "gettransaction", &gettransaction, false },
2267 { "listtransactions", &listtransactions, false },
2268 { "signmessage", &signmessage, false },
2269 { "verifymessage", &verifymessage, false },
2270 { "getwork", &getwork, true },
2271 { "listaccounts", &listaccounts, false },
2272 { "settxfee", &settxfee, false },
2273 { "getmemorypool", &getmemorypool, true },
2274 { "listsinceblock", &listsinceblock, false },
2275 { "dumpprivkey", &dumpprivkey, false },
2276 { "importprivkey", &importprivkey, false },
2277 { "getcheckpoint", &getcheckpoint, true },
2278 { "reservebalance", &reservebalance, false},
2279 { "checkwallet", &checkwallet, false},
2280 { "repairwallet", &repairwallet, false},
2281 { "makekeypair", &makekeypair, false},
2282 { "sendalert", &sendalert, false},
2285 CRPCTable::CRPCTable()
2288 for (vcidx = 0; vcidx < (sizeof(vRPCCommands) / sizeof(vRPCCommands[0])); vcidx++)
2290 const CRPCCommand *pcmd;
2292 pcmd = &vRPCCommands[vcidx];
2293 mapCommands[pcmd->name] = pcmd;
2297 const CRPCCommand *CRPCTable::operator[](string name) const
2299 map<string, const CRPCCommand*>::const_iterator it = mapCommands.find(name);
2300 if (it == mapCommands.end())
2302 return (*it).second;
2308 // This ain't Apache. We're just using HTTP header for the length field
2309 // and to be compatible with other JSON-RPC implementations.
2312 string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
2315 s << "POST / HTTP/1.1\r\n"
2316 << "User-Agent: ppcoin-json-rpc/" << FormatFullVersion() << "\r\n"
2317 << "Host: 127.0.0.1\r\n"
2318 << "Content-Type: application/json\r\n"
2319 << "Content-Length: " << strMsg.size() << "\r\n"
2320 << "Connection: close\r\n"
2321 << "Accept: application/json\r\n";
2322 BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
2323 s << item.first << ": " << item.second << "\r\n";
2324 s << "\r\n" << strMsg;
2329 string rfc1123Time()
2334 struct tm* now_gmt = gmtime(&now);
2335 string locale(setlocale(LC_TIME, NULL));
2336 setlocale(LC_TIME, "C"); // we want posix (aka "C") weekday/month strings
2337 strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt);
2338 setlocale(LC_TIME, locale.c_str());
2339 return string(buffer);
2342 static string HTTPReply(int nStatus, const string& strMsg)
2345 return strprintf("HTTP/1.0 401 Authorization Required\r\n"
2347 "Server: ppcoin-json-rpc/%s\r\n"
2348 "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
2349 "Content-Type: text/html\r\n"
2350 "Content-Length: 296\r\n"
2352 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
2353 "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
2356 "<TITLE>Error</TITLE>\r\n"
2357 "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
2359 "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
2360 "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
2361 const char *cStatus;
2362 if (nStatus == 200) cStatus = "OK";
2363 else if (nStatus == 400) cStatus = "Bad Request";
2364 else if (nStatus == 403) cStatus = "Forbidden";
2365 else if (nStatus == 404) cStatus = "Not Found";
2366 else if (nStatus == 500) cStatus = "Internal Server Error";
2369 "HTTP/1.1 %d %s\r\n"
2371 "Connection: close\r\n"
2372 "Content-Length: %d\r\n"
2373 "Content-Type: application/json\r\n"
2374 "Server: ppcoin-json-rpc/%s\r\n"
2379 rfc1123Time().c_str(),
2381 FormatFullVersion().c_str(),
2385 int ReadHTTPStatus(std::basic_istream<char>& stream)
2388 getline(stream, str);
2389 vector<string> vWords;
2390 boost::split(vWords, str, boost::is_any_of(" "));
2391 if (vWords.size() < 2)
2393 return atoi(vWords[1].c_str());
2396 int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
2402 std::getline(stream, str);
2403 if (str.empty() || str == "\r")
2405 string::size_type nColon = str.find(":");
2406 if (nColon != string::npos)
2408 string strHeader = str.substr(0, nColon);
2409 boost::trim(strHeader);
2410 boost::to_lower(strHeader);
2411 string strValue = str.substr(nColon+1);
2412 boost::trim(strValue);
2413 mapHeadersRet[strHeader] = strValue;
2414 if (strHeader == "content-length")
2415 nLen = atoi(strValue.c_str());
2421 int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
2423 mapHeadersRet.clear();
2427 int nStatus = ReadHTTPStatus(stream);
2430 int nLen = ReadHTTPHeader(stream, mapHeadersRet);
2431 if (nLen < 0 || nLen > (int)MAX_SIZE)
2437 vector<char> vch(nLen);
2438 stream.read(&vch[0], nLen);
2439 strMessageRet = string(vch.begin(), vch.end());
2445 bool HTTPAuthorized(map<string, string>& mapHeaders)
2447 string strAuth = mapHeaders["authorization"];
2448 if (strAuth.substr(0,6) != "Basic ")
2450 string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
2451 string strUserPass = DecodeBase64(strUserPass64);
2452 return strUserPass == strRPCUserColonPass;
2456 // JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
2457 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
2458 // unspecified (HTTP errors and contents of 'error').
2460 // 1.0 spec: http://json-rpc.org/wiki/specification
2461 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
2462 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
2465 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
2468 request.push_back(Pair("method", strMethod));
2469 request.push_back(Pair("params", params));
2470 request.push_back(Pair("id", id));
2471 return write_string(Value(request), false) + "\n";
2474 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
2477 if (error.type() != null_type)
2478 reply.push_back(Pair("result", Value::null));
2480 reply.push_back(Pair("result", result));
2481 reply.push_back(Pair("error", error));
2482 reply.push_back(Pair("id", id));
2483 return write_string(Value(reply), false) + "\n";
2486 void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
2488 // Send error reply from json-rpc error object
2490 int code = find_value(objError, "code").get_int();
2491 if (code == -32600) nStatus = 400;
2492 else if (code == -32601) nStatus = 404;
2493 string strReply = JSONRPCReply(Value::null, objError, id);
2494 stream << HTTPReply(nStatus, strReply) << std::flush;
2497 bool ClientAllowed(const string& strAddress)
2499 if (strAddress == asio::ip::address_v4::loopback().to_string())
2501 const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
2502 BOOST_FOREACH(string strAllow, vAllow)
2503 if (WildcardMatch(strAddress, strAllow))
2509 // IOStream device that speaks SSL but can also speak non-SSL
2511 class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
2513 SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
2515 fUseSSL = fUseSSLIn;
2516 fNeedHandshake = fUseSSLIn;
2519 void handshake(ssl::stream_base::handshake_type role)
2521 if (!fNeedHandshake) return;
2522 fNeedHandshake = false;
2523 stream.handshake(role);
2525 std::streamsize read(char* s, std::streamsize n)
2527 handshake(ssl::stream_base::server); // HTTPS servers read first
2528 if (fUseSSL) return stream.read_some(asio::buffer(s, n));
2529 return stream.next_layer().read_some(asio::buffer(s, n));
2531 std::streamsize write(const char* s, std::streamsize n)
2533 handshake(ssl::stream_base::client); // HTTPS clients write first
2534 if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
2535 return asio::write(stream.next_layer(), asio::buffer(s, n));
2537 bool connect(const std::string& server, const std::string& port)
2539 ip::tcp::resolver resolver(stream.get_io_service());
2540 ip::tcp::resolver::query query(server.c_str(), port.c_str());
2541 ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
2542 ip::tcp::resolver::iterator end;
2543 boost::system::error_code error = asio::error::host_not_found;
2544 while (error && endpoint_iterator != end)
2546 stream.lowest_layer().close();
2547 stream.lowest_layer().connect(*endpoint_iterator++, error);
2555 bool fNeedHandshake;
2560 void ThreadRPCServer(void* parg)
2562 IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
2565 vnThreadsRunning[THREAD_RPCSERVER]++;
2566 ThreadRPCServer2(parg);
2567 vnThreadsRunning[THREAD_RPCSERVER]--;
2569 catch (std::exception& e) {
2570 vnThreadsRunning[THREAD_RPCSERVER]--;
2571 PrintException(&e, "ThreadRPCServer()");
2573 vnThreadsRunning[THREAD_RPCSERVER]--;
2574 PrintException(NULL, "ThreadRPCServer()");
2576 printf("ThreadRPCServer exiting\n");
2579 void ThreadRPCServer2(void* parg)
2581 printf("ThreadRPCServer started\n");
2583 strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
2584 if (mapArgs["-rpcpassword"] == "")
2586 unsigned char rand_pwd[32];
2587 RAND_bytes(rand_pwd, 32);
2588 string strWhatAmI = "To use ppcoind";
2589 if (mapArgs.count("-server"))
2590 strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
2591 else if (mapArgs.count("-daemon"))
2592 strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
2593 ThreadSafeMessageBox(strprintf(
2594 _("%s, you must set a rpcpassword in the configuration file:\n %s\n"
2595 "It is recommended you use the following random password:\n"
2596 "rpcuser=bitcoinrpc\n"
2598 "(you do not need to remember this password)\n"
2599 "If the file does not exist, create it with owner-readable-only file permissions.\n"),
2601 GetConfigFile().string().c_str(),
2602 EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str()),
2603 _("Error"), wxOK | wxMODAL);
2608 bool fUseSSL = GetBoolArg("-rpcssl");
2609 asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
2611 asio::io_service io_service;
2612 ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", RPC_PORT));
2613 ip::tcp::acceptor acceptor(io_service);
2616 acceptor.open(endpoint.protocol());
2617 acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
2618 acceptor.bind(endpoint);
2619 acceptor.listen(socket_base::max_connections);
2621 catch(boost::system::system_error &e)
2623 ThreadSafeMessageBox(strprintf(_("An error occured while setting up the RPC port %i for listening: %s"), endpoint.port(), e.what()),
2624 _("Error"), wxOK | wxMODAL);
2629 ssl::context context(io_service, ssl::context::sslv23);
2632 context.set_options(ssl::context::no_sslv2);
2634 filesystem::path pathCertFile(GetArg("-rpcsslcertificatechainfile", "server.cert"));
2635 if (!pathCertFile.is_complete()) pathCertFile = filesystem::path(GetDataDir()) / pathCertFile;
2636 if (filesystem::exists(pathCertFile)) context.use_certificate_chain_file(pathCertFile.string());
2637 else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", pathCertFile.string().c_str());
2639 filesystem::path pathPKFile(GetArg("-rpcsslprivatekeyfile", "server.pem"));
2640 if (!pathPKFile.is_complete()) pathPKFile = filesystem::path(GetDataDir()) / pathPKFile;
2641 if (filesystem::exists(pathPKFile)) context.use_private_key_file(pathPKFile.string(), ssl::context::pem);
2642 else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pathPKFile.string().c_str());
2644 string strCiphers = GetArg("-rpcsslciphers", "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
2645 SSL_CTX_set_cipher_list(context.impl(), strCiphers.c_str());
2650 // Accept connection
2651 SSLStream sslStream(io_service, context);
2652 SSLIOStreamDevice d(sslStream, fUseSSL);
2653 iostreams::stream<SSLIOStreamDevice> stream(d);
2655 ip::tcp::endpoint peer;
2656 vnThreadsRunning[THREAD_RPCSERVER]--;
2657 acceptor.accept(sslStream.lowest_layer(), peer);
2658 vnThreadsRunning[4]++;
2662 // Restrict callers by IP
2663 if (!ClientAllowed(peer.address().to_string()))
2665 // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
2667 stream << HTTPReply(403, "") << std::flush;
2671 map<string, string> mapHeaders;
2674 boost::thread api_caller(ReadHTTP, boost::ref(stream), boost::ref(mapHeaders), boost::ref(strRequest));
2675 if (!api_caller.timed_join(boost::posix_time::seconds(GetArg("-rpctimeout", 30))))
2678 printf("ThreadRPCServer ReadHTTP timeout\n");
2682 // Check authorization
2683 if (mapHeaders.count("authorization") == 0)
2685 stream << HTTPReply(401, "") << std::flush;
2688 if (!HTTPAuthorized(mapHeaders))
2690 printf("ThreadRPCServer incorrect password attempt from %s\n",peer.address().to_string().c_str());
2691 /* Deter brute-forcing short passwords.
2692 If this results in a DOS the user really
2693 shouldn't have their RPC port exposed.*/
2694 if (mapArgs["-rpcpassword"].size() < 20)
2697 stream << HTTPReply(401, "") << std::flush;
2701 Value id = Value::null;
2706 if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
2707 throw JSONRPCError(-32700, "Parse error");
2708 const Object& request = valRequest.get_obj();
2710 // Parse id now so errors from here on will have the id
2711 id = find_value(request, "id");
2714 Value valMethod = find_value(request, "method");
2715 if (valMethod.type() == null_type)
2716 throw JSONRPCError(-32600, "Missing method");
2717 if (valMethod.type() != str_type)
2718 throw JSONRPCError(-32600, "Method must be a string");
2719 string strMethod = valMethod.get_str();
2720 if (strMethod != "getwork" && strMethod != "getmemorypool")
2721 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
2724 Value valParams = find_value(request, "params");
2726 if (valParams.type() == array_type)
2727 params = valParams.get_array();
2728 else if (valParams.type() == null_type)
2731 throw JSONRPCError(-32600, "Params must be an array");
2734 const CRPCCommand *pcmd = tableRPC[strMethod];
2736 throw JSONRPCError(-32601, "Method not found");
2738 // Observe safe mode
2739 string strWarning = GetWarnings("rpc");
2740 if (strWarning != "" && !GetBoolArg("-disablesafemode") &&
2742 throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
2749 LOCK2(cs_main, pwalletMain->cs_wallet);
2750 result = pcmd->actor(params, false);
2754 string strReply = JSONRPCReply(result, Value::null, id);
2755 stream << HTTPReply(200, strReply) << std::flush;
2757 catch (std::exception& e)
2759 ErrorReply(stream, JSONRPCError(-1, e.what()), id);
2762 catch (Object& objError)
2764 ErrorReply(stream, objError, id);
2766 catch (std::exception& e)
2768 ErrorReply(stream, JSONRPCError(-32700, e.what()), id);
2776 Object CallRPC(const string& strMethod, const Array& params)
2778 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2779 throw runtime_error(strprintf(
2780 _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
2781 "If the file does not exist, create it with owner-readable-only file permissions."),
2782 GetConfigFile().string().c_str()));
2784 // Connect to localhost
2785 bool fUseSSL = GetBoolArg("-rpcssl");
2786 asio::io_service io_service;
2787 ssl::context context(io_service, ssl::context::sslv23);
2788 context.set_options(ssl::context::no_sslv2);
2789 SSLStream sslStream(io_service, context);
2790 SSLIOStreamDevice d(sslStream, fUseSSL);
2791 iostreams::stream<SSLIOStreamDevice> stream(d);
2792 if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", CBigNum(RPC_PORT).ToString().c_str())))
2793 throw runtime_error("couldn't connect to server");
2795 // HTTP basic authentication
2796 string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
2797 map<string, string> mapRequestHeaders;
2798 mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
2801 string strRequest = JSONRPCRequest(strMethod, params, 1);
2802 string strPost = HTTPPost(strRequest, mapRequestHeaders);
2803 stream << strPost << std::flush;
2806 map<string, string> mapHeaders;
2808 int nStatus = ReadHTTP(stream, mapHeaders, strReply);
2810 throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
2811 else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
2812 throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
2813 else if (strReply.empty())
2814 throw runtime_error("no response from server");
2818 if (!read_string(strReply, valReply))
2819 throw runtime_error("couldn't parse reply from server");
2820 const Object& reply = valReply.get_obj();
2822 throw runtime_error("expected reply to have result, error and id properties");
2830 template<typename T>
2831 void ConvertTo(Value& value)
2833 if (value.type() == str_type)
2835 // reinterpret string as unquoted json value
2837 if (!read_string(value.get_str(), value2))
2838 throw runtime_error("type mismatch");
2839 value = value2.get_value<T>();
2843 value = value.get_value<T>();
2847 int CommandLineRPC(int argc, char *argv[])
2854 while (argc > 1 && IsSwitchChar(argv[1][0]))
2862 throw runtime_error("too few parameters");
2863 string strMethod = argv[1];
2865 // Parameters default to strings
2867 for (int i = 2; i < argc; i++)
2868 params.push_back(argv[i]);
2869 int n = params.size();
2872 // Special case non-string parameter types
2874 if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
2875 if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2876 if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
2877 if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]);
2878 if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2879 if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2880 if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2881 if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
2882 if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2883 if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
2884 if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2885 if (strMethod == "getblockhash" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2886 if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]);
2887 if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2888 if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]);
2889 if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2890 if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2891 if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2892 if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2893 if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2894 if (strMethod == "walletpassphrase" && n > 2) ConvertTo<bool>(params[2]);
2895 if (strMethod == "listsinceblock" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2896 if (strMethod == "sendalert" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2897 if (strMethod == "sendalert" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2898 if (strMethod == "sendalert" && n > 4) ConvertTo<boost::int64_t>(params[4]);
2899 if (strMethod == "sendalert" && n > 5) ConvertTo<boost::int64_t>(params[5]);
2900 if (strMethod == "sendalert" && n > 6) ConvertTo<boost::int64_t>(params[6]);
2901 if (strMethod == "sendmany" && n > 1)
2903 string s = params[1].get_str();
2905 if (!read_string(s, v) || v.type() != obj_type)
2906 throw runtime_error("type mismatch");
2907 params[1] = v.get_obj();
2909 if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2910 if (strMethod == "reservebalance" && n > 0) ConvertTo<bool>(params[0]);
2911 if (strMethod == "reservebalance" && n > 1) ConvertTo<double>(params[1]);
2912 if (strMethod == "addmultisigaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2913 if (strMethod == "addmultisigaddress" && n > 1)
2915 string s = params[1].get_str();
2917 if (!read_string(s, v) || v.type() != array_type)
2918 throw runtime_error("type mismatch "+s);
2919 params[1] = v.get_array();
2923 Object reply = CallRPC(strMethod, params);
2926 const Value& result = find_value(reply, "result");
2927 const Value& error = find_value(reply, "error");
2929 if (error.type() != null_type)
2932 strPrint = "error: " + write_string(error, false);
2933 int code = find_value(error.get_obj(), "code").get_int();
2939 if (result.type() == null_type)
2941 else if (result.type() == str_type)
2942 strPrint = result.get_str();
2944 strPrint = write_string(result, true);
2947 catch (std::exception& e)
2949 strPrint = string("error: ") + e.what();
2954 PrintException(NULL, "CommandLineRPC()");
2959 fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
2968 int main(int argc, char *argv[])
2971 // Turn off microsoft heap dump noise
2972 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
2973 _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
2975 setbuf(stdin, NULL);
2976 setbuf(stdout, NULL);
2977 setbuf(stderr, NULL);
2981 if (argc >= 2 && string(argv[1]) == "-server")
2983 printf("server ready\n");
2984 ThreadRPCServer(NULL);
2988 return CommandLineRPC(argc, argv);
2991 catch (std::exception& e) {
2992 PrintException(&e, "main()");
2994 PrintException(NULL, "main()");
3000 const CRPCTable tableRPC;