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("%x %H:%M:%S", pindexCheckpoint->GetBlockTime()).c_str()));
2032 // ppcoin: reserve balance from being staked for network protection
2033 Value reservebalance(const Array& params, bool fHelp)
2035 if (fHelp || params.size() > 2)
2036 throw runtime_error(
2037 "reservebalance [<reserve> [amount]]\n"
2038 "<reserve> is true or false to turn balance reserve on or off.\n"
2039 "<amount> is a real and rounded to cent.\n"
2040 "Set reserve amount not participating in network protection.\n"
2041 "If no parameters provided current setting is printed.\n");
2043 if (params.size() > 0)
2045 bool fReserve = params[0].get_bool();
2048 if (params.size() == 1)
2049 throw runtime_error("must provide amount to reserve balance.\n");
2050 int64 nAmount = AmountFromValue(params[1]);
2051 nAmount = (nAmount / CENT) * CENT; // round to cent
2053 throw runtime_error("amount cannot be negative.\n");
2054 // TODO: handle persistence of nBalanceReserve
2055 // settings removed since bitcoin 0.6
2056 // WriteSetting("nBalanceReserve", nBalanceReserve = nAmount);
2057 nBalanceReserve = nAmount;
2061 if (params.size() > 1)
2062 throw runtime_error("cannot specify amount to turn off reserve.\n");
2063 // TODO: handle persistence of nBalanceReserve
2064 // settings removed since bitcoin 0.6
2065 // WriteSetting("nBalanceReserve", nBalanceReserve = 0);
2066 nBalanceReserve = 0;
2071 result.push_back(Pair("reserve", (nBalanceReserve > 0)));
2072 result.push_back(Pair("amount", ValueFromAmount(nBalanceReserve)));
2077 // ppcoin: check wallet integrity
2078 Value checkwallet(const Array& params, bool fHelp)
2080 if (fHelp || params.size() > 0)
2081 throw runtime_error(
2083 "Check wallet for integrity.\n");
2086 int64 nBalanceInQuestion;
2087 if (!pwalletMain->CheckSpentCoins(nMismatchSpent, nBalanceInQuestion))
2090 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
2091 result.push_back(Pair("amount in question", ValueFromAmount(nBalanceInQuestion)));
2098 // ppcoin: repair wallet
2099 Value repairwallet(const Array& params, bool fHelp)
2101 if (fHelp || params.size() > 0)
2102 throw runtime_error(
2104 "Repair wallet if checkwallet reports any problem.\n");
2107 int64 nBalanceInQuestion;
2108 pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion);
2110 if (nMismatchSpent == 0)
2112 result.push_back(Pair("wallet check passed", true));
2116 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
2117 result.push_back(Pair("amount affected by repair", ValueFromAmount(nBalanceInQuestion)));
2122 // ppcoin: make a public-private key pair
2123 Value makekeypair(const Array& params, bool fHelp)
2125 if (fHelp || params.size() > 1)
2126 throw runtime_error(
2127 "makekeypair [prefix]\n"
2128 "Make a public/private key pair.\n"
2129 "[prefix] is optional preferred prefix for the public key.\n");
2131 string strPrefix = "";
2132 if (params.size() > 0)
2133 strPrefix = params[0].get_str();
2139 key.MakeNewKey(false);
2141 } while (nCount < 10000 && strPrefix != HexStr(key.GetPubKey()).substr(0, strPrefix.size()));
2143 if (strPrefix != HexStr(key.GetPubKey()).substr(0, strPrefix.size()))
2146 CPrivKey vchPrivKey = key.GetPrivKey();
2148 result.push_back(Pair("PrivateKey", HexStr<CPrivKey::iterator>(vchPrivKey.begin(), vchPrivKey.end())));
2149 result.push_back(Pair("PublicKey", HexStr(key.GetPubKey())));
2153 extern CCriticalSection cs_mapAlerts;
2154 extern map<uint256, CAlert> mapAlerts;
2156 // ppcoin: send alert.
2157 // There is a known deadlock situation with ThreadMessageHandler
2158 // ThreadMessageHandler: holds cs_vSend and acquiring cs_main in SendMessages()
2159 // ThreadRPCServer: holds cs_main and acquiring cs_vSend in alert.RelayTo()/PushMessage()/BeginMessage()
2160 Value sendalert(const Array& params, bool fHelp)
2162 if (fHelp || params.size() < 5)
2163 throw runtime_error(
2164 "sendalert <message> <privatekey> <minver> <maxver> <id> [cancelupto]\n"
2165 "<message> is the alert text message\n"
2166 "<privatekey> is hex string of alert master private key\n"
2167 "<minver> is the minimum applicable client version\n"
2168 "<maxver> is the maximum applicable client version\n"
2169 "<id> is the alert id\n"
2170 "[cancelupto] cancels all alert id's up to this number\n"
2171 "Returns true or false.");
2176 alert.strStatusBar = params[0].get_str();
2177 alert.nMinVer = params[2].get_int();
2178 alert.nMaxVer = params[3].get_int();
2179 alert.nID = params[4].get_int();
2180 if (params.size() > 5)
2181 alert.nCancel = params[5].get_int();
2182 alert.nVersion = PROTOCOL_VERSION;
2183 alert.nRelayUntil = GetAdjustedTime() + 365*24*60*60;
2184 alert.nExpiration = GetAdjustedTime() + 365*24*60*60;
2185 alert.nPriority = 1;
2187 CDataStream sMsg(SER_NETWORK, PROTOCOL_VERSION);
2188 sMsg << (CUnsignedAlert)alert;
2189 alert.vchMsg = vector<unsigned char>(sMsg.begin(), sMsg.end());
2191 vector<unsigned char> vchPrivKey = ParseHex(params[1].get_str());
2192 key.SetPrivKey(CPrivKey(vchPrivKey.begin(), vchPrivKey.end())); // if key is not correct openssl may crash
2193 if (!key.Sign(Hash(alert.vchMsg.begin(), alert.vchMsg.end()), alert.vchSig))
2194 throw runtime_error(
2195 "Unable to sign alert, check private key?\n");
2196 if(!alert.ProcessAlert())
2197 throw runtime_error(
2198 "Failed to process alert.\n");
2202 BOOST_FOREACH(CNode* pnode, vNodes)
2203 alert.RelayTo(pnode);
2207 result.push_back(Pair("strStatusBar", alert.strStatusBar));
2208 result.push_back(Pair("nVersion", alert.nVersion));
2209 result.push_back(Pair("nMinVer", alert.nMinVer));
2210 result.push_back(Pair("nMaxVer", alert.nMaxVer));
2211 result.push_back(Pair("nID", alert.nID));
2212 if (alert.nCancel > 0)
2213 result.push_back(Pair("nCancel", alert.nCancel));
2217 // ppcoin: send checkpoint
2218 Value sendcheckpoint(const Array& params, bool fHelp)
2220 if (fHelp || params.size() > 2 || params.size() < 1 )
2221 throw runtime_error(
2222 "sendcheckpoint <privatekey> [checkpointhash]\n"
2223 "<privatekey> is hex string of checkpoint master private key\n"
2224 "<checkpointhash> is the hash of checkpoint block\n");
2226 CSyncCheckpoint checkpoint;
2229 // TODO: omit checkpointhash parameter
2230 if (params.size() > 1)
2232 checkpoint.hashCheckpoint = uint256(params[1].get_str());
2233 if (!mapBlockIndex.count(checkpoint.hashCheckpoint))
2234 throw runtime_error(
2235 "Provided checkpoint block is not on main chain\n");
2239 checkpoint.hashCheckpoint = Checkpoints::AutoSelectSyncCheckpoint();
2240 if (checkpoint.hashCheckpoint == Checkpoints::hashSyncCheckpoint)
2241 throw runtime_error(
2242 "Unable to select a more recent sync-checkpoint");
2245 CDataStream sMsg(SER_NETWORK, PROTOCOL_VERSION);
2246 sMsg << (CUnsignedSyncCheckpoint)checkpoint;
2247 checkpoint.vchMsg = vector<unsigned char>(sMsg.begin(), sMsg.end());
2249 vector<unsigned char> vchPrivKey = ParseHex(params[0].get_str());
2250 key.SetPrivKey(CPrivKey(vchPrivKey.begin(), vchPrivKey.end())); // if key is not correct openssl may crash
2251 if (!key.Sign(Hash(checkpoint.vchMsg.begin(), checkpoint.vchMsg.end()), checkpoint.vchSig))
2252 throw runtime_error(
2253 "Unable to sign checkpoint, check private key?\n");
2255 if(!checkpoint.ProcessSyncCheckpoint(NULL))
2256 throw runtime_error(
2257 "Failed to process checkpoint.\n");
2261 BOOST_FOREACH(CNode* pnode, vNodes)
2262 checkpoint.RelayTo(pnode);
2266 result.push_back(Pair("checkpoint", Checkpoints::hashSyncCheckpoint.ToString().c_str()));
2267 result.push_back(Pair("height", mapBlockIndex[Checkpoints::hashSyncCheckpoint]->nHeight));
2268 result.push_back(Pair("timestamp", DateTimeStrFormat("%x %H:%M:%S", mapBlockIndex[Checkpoints::hashSyncCheckpoint]->GetBlockTime()).c_str()));
2278 static const CRPCCommand vRPCCommands[] =
2279 { // name function safe mode?
2280 // ------------------------ ----------------------- ----------
2281 { "help", &help, true },
2282 { "stop", &stop, true },
2283 { "getblockcount", &getblockcount, true },
2284 { "getblocknumber", &getblocknumber, true },
2285 { "getconnectioncount", &getconnectioncount, true },
2286 { "getdifficulty", &getdifficulty, true },
2287 { "getgenerate", &getgenerate, true },
2288 { "setgenerate", &setgenerate, true },
2289 { "gethashespersec", &gethashespersec, true },
2290 { "getinfo", &getinfo, true },
2291 { "getmininginfo", &getmininginfo, true },
2292 { "getnewaddress", &getnewaddress, true },
2293 { "getaccountaddress", &getaccountaddress, true },
2294 { "setaccount", &setaccount, true },
2295 { "getaccount", &getaccount, false },
2296 { "getaddressesbyaccount", &getaddressesbyaccount, true },
2297 { "sendtoaddress", &sendtoaddress, false },
2298 { "getreceivedbyaddress", &getreceivedbyaddress, false },
2299 { "getreceivedbyaccount", &getreceivedbyaccount, false },
2300 { "listreceivedbyaddress", &listreceivedbyaddress, false },
2301 { "listreceivedbyaccount", &listreceivedbyaccount, false },
2302 { "backupwallet", &backupwallet, true },
2303 { "keypoolrefill", &keypoolrefill, true },
2304 { "walletpassphrase", &walletpassphrase, true },
2305 { "walletpassphrasechange", &walletpassphrasechange, false },
2306 { "walletlock", &walletlock, true },
2307 { "encryptwallet", &encryptwallet, false },
2308 { "validateaddress", &validateaddress, true },
2309 { "getbalance", &getbalance, false },
2310 { "move", &movecmd, false },
2311 { "sendfrom", &sendfrom, false },
2312 { "sendmany", &sendmany, false },
2313 { "addmultisigaddress", &addmultisigaddress, false },
2314 { "getblock", &getblock, false },
2315 { "getblockhash", &getblockhash, false },
2316 { "gettransaction", &gettransaction, false },
2317 { "listtransactions", &listtransactions, false },
2318 { "signmessage", &signmessage, false },
2319 { "verifymessage", &verifymessage, false },
2320 { "getwork", &getwork, true },
2321 { "listaccounts", &listaccounts, false },
2322 { "settxfee", &settxfee, false },
2323 { "getmemorypool", &getmemorypool, true },
2324 { "listsinceblock", &listsinceblock, false },
2325 { "dumpprivkey", &dumpprivkey, false },
2326 { "importprivkey", &importprivkey, false },
2327 { "getcheckpoint", &getcheckpoint, true },
2328 { "reservebalance", &reservebalance, false},
2329 { "checkwallet", &checkwallet, false},
2330 { "repairwallet", &repairwallet, false},
2331 { "makekeypair", &makekeypair, false},
2332 { "sendalert", &sendalert, false},
2333 { "sendcheckpoint", &sendcheckpoint, false},
2336 CRPCTable::CRPCTable()
2339 for (vcidx = 0; vcidx < (sizeof(vRPCCommands) / sizeof(vRPCCommands[0])); vcidx++)
2341 const CRPCCommand *pcmd;
2343 pcmd = &vRPCCommands[vcidx];
2344 mapCommands[pcmd->name] = pcmd;
2348 const CRPCCommand *CRPCTable::operator[](string name) const
2350 map<string, const CRPCCommand*>::const_iterator it = mapCommands.find(name);
2351 if (it == mapCommands.end())
2353 return (*it).second;
2359 // This ain't Apache. We're just using HTTP header for the length field
2360 // and to be compatible with other JSON-RPC implementations.
2363 string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
2366 s << "POST / HTTP/1.1\r\n"
2367 << "User-Agent: ppcoin-json-rpc/" << FormatFullVersion() << "\r\n"
2368 << "Host: 127.0.0.1\r\n"
2369 << "Content-Type: application/json\r\n"
2370 << "Content-Length: " << strMsg.size() << "\r\n"
2371 << "Connection: close\r\n"
2372 << "Accept: application/json\r\n";
2373 BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
2374 s << item.first << ": " << item.second << "\r\n";
2375 s << "\r\n" << strMsg;
2380 string rfc1123Time()
2385 struct tm* now_gmt = gmtime(&now);
2386 string locale(setlocale(LC_TIME, NULL));
2387 setlocale(LC_TIME, "C"); // we want posix (aka "C") weekday/month strings
2388 strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt);
2389 setlocale(LC_TIME, locale.c_str());
2390 return string(buffer);
2393 static string HTTPReply(int nStatus, const string& strMsg)
2396 return strprintf("HTTP/1.0 401 Authorization Required\r\n"
2398 "Server: ppcoin-json-rpc/%s\r\n"
2399 "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
2400 "Content-Type: text/html\r\n"
2401 "Content-Length: 296\r\n"
2403 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
2404 "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
2407 "<TITLE>Error</TITLE>\r\n"
2408 "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
2410 "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
2411 "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
2412 const char *cStatus;
2413 if (nStatus == 200) cStatus = "OK";
2414 else if (nStatus == 400) cStatus = "Bad Request";
2415 else if (nStatus == 403) cStatus = "Forbidden";
2416 else if (nStatus == 404) cStatus = "Not Found";
2417 else if (nStatus == 500) cStatus = "Internal Server Error";
2420 "HTTP/1.1 %d %s\r\n"
2422 "Connection: close\r\n"
2423 "Content-Length: %d\r\n"
2424 "Content-Type: application/json\r\n"
2425 "Server: ppcoin-json-rpc/%s\r\n"
2430 rfc1123Time().c_str(),
2432 FormatFullVersion().c_str(),
2436 int ReadHTTPStatus(std::basic_istream<char>& stream)
2439 getline(stream, str);
2440 vector<string> vWords;
2441 boost::split(vWords, str, boost::is_any_of(" "));
2442 if (vWords.size() < 2)
2444 return atoi(vWords[1].c_str());
2447 int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
2453 std::getline(stream, str);
2454 if (str.empty() || str == "\r")
2456 string::size_type nColon = str.find(":");
2457 if (nColon != string::npos)
2459 string strHeader = str.substr(0, nColon);
2460 boost::trim(strHeader);
2461 boost::to_lower(strHeader);
2462 string strValue = str.substr(nColon+1);
2463 boost::trim(strValue);
2464 mapHeadersRet[strHeader] = strValue;
2465 if (strHeader == "content-length")
2466 nLen = atoi(strValue.c_str());
2472 int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
2474 mapHeadersRet.clear();
2478 int nStatus = ReadHTTPStatus(stream);
2481 int nLen = ReadHTTPHeader(stream, mapHeadersRet);
2482 if (nLen < 0 || nLen > (int)MAX_SIZE)
2488 vector<char> vch(nLen);
2489 stream.read(&vch[0], nLen);
2490 strMessageRet = string(vch.begin(), vch.end());
2496 bool HTTPAuthorized(map<string, string>& mapHeaders)
2498 string strAuth = mapHeaders["authorization"];
2499 if (strAuth.substr(0,6) != "Basic ")
2501 string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
2502 string strUserPass = DecodeBase64(strUserPass64);
2503 return strUserPass == strRPCUserColonPass;
2507 // JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
2508 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
2509 // unspecified (HTTP errors and contents of 'error').
2511 // 1.0 spec: http://json-rpc.org/wiki/specification
2512 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
2513 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
2516 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
2519 request.push_back(Pair("method", strMethod));
2520 request.push_back(Pair("params", params));
2521 request.push_back(Pair("id", id));
2522 return write_string(Value(request), false) + "\n";
2525 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
2528 if (error.type() != null_type)
2529 reply.push_back(Pair("result", Value::null));
2531 reply.push_back(Pair("result", result));
2532 reply.push_back(Pair("error", error));
2533 reply.push_back(Pair("id", id));
2534 return write_string(Value(reply), false) + "\n";
2537 void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
2539 // Send error reply from json-rpc error object
2541 int code = find_value(objError, "code").get_int();
2542 if (code == -32600) nStatus = 400;
2543 else if (code == -32601) nStatus = 404;
2544 string strReply = JSONRPCReply(Value::null, objError, id);
2545 stream << HTTPReply(nStatus, strReply) << std::flush;
2548 bool ClientAllowed(const string& strAddress)
2550 if (strAddress == asio::ip::address_v4::loopback().to_string())
2552 const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
2553 BOOST_FOREACH(string strAllow, vAllow)
2554 if (WildcardMatch(strAddress, strAllow))
2560 // IOStream device that speaks SSL but can also speak non-SSL
2562 class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
2564 SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
2566 fUseSSL = fUseSSLIn;
2567 fNeedHandshake = fUseSSLIn;
2570 void handshake(ssl::stream_base::handshake_type role)
2572 if (!fNeedHandshake) return;
2573 fNeedHandshake = false;
2574 stream.handshake(role);
2576 std::streamsize read(char* s, std::streamsize n)
2578 handshake(ssl::stream_base::server); // HTTPS servers read first
2579 if (fUseSSL) return stream.read_some(asio::buffer(s, n));
2580 return stream.next_layer().read_some(asio::buffer(s, n));
2582 std::streamsize write(const char* s, std::streamsize n)
2584 handshake(ssl::stream_base::client); // HTTPS clients write first
2585 if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
2586 return asio::write(stream.next_layer(), asio::buffer(s, n));
2588 bool connect(const std::string& server, const std::string& port)
2590 ip::tcp::resolver resolver(stream.get_io_service());
2591 ip::tcp::resolver::query query(server.c_str(), port.c_str());
2592 ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
2593 ip::tcp::resolver::iterator end;
2594 boost::system::error_code error = asio::error::host_not_found;
2595 while (error && endpoint_iterator != end)
2597 stream.lowest_layer().close();
2598 stream.lowest_layer().connect(*endpoint_iterator++, error);
2606 bool fNeedHandshake;
2611 void ThreadRPCServer(void* parg)
2613 IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
2616 vnThreadsRunning[THREAD_RPCSERVER]++;
2617 ThreadRPCServer2(parg);
2618 vnThreadsRunning[THREAD_RPCSERVER]--;
2620 catch (std::exception& e) {
2621 vnThreadsRunning[THREAD_RPCSERVER]--;
2622 PrintException(&e, "ThreadRPCServer()");
2624 vnThreadsRunning[THREAD_RPCSERVER]--;
2625 PrintException(NULL, "ThreadRPCServer()");
2627 printf("ThreadRPCServer exiting\n");
2630 void ThreadRPCServer2(void* parg)
2632 printf("ThreadRPCServer started\n");
2634 strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
2635 if (mapArgs["-rpcpassword"] == "")
2637 unsigned char rand_pwd[32];
2638 RAND_bytes(rand_pwd, 32);
2639 string strWhatAmI = "To use ppcoind";
2640 if (mapArgs.count("-server"))
2641 strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
2642 else if (mapArgs.count("-daemon"))
2643 strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
2644 ThreadSafeMessageBox(strprintf(
2645 _("%s, you must set a rpcpassword in the configuration file:\n %s\n"
2646 "It is recommended you use the following random password:\n"
2647 "rpcuser=bitcoinrpc\n"
2649 "(you do not need to remember this password)\n"
2650 "If the file does not exist, create it with owner-readable-only file permissions.\n"),
2652 GetConfigFile().string().c_str(),
2653 EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str()),
2654 _("Error"), wxOK | wxMODAL);
2659 bool fUseSSL = GetBoolArg("-rpcssl");
2660 asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
2662 asio::io_service io_service;
2663 ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", RPC_PORT));
2664 ip::tcp::acceptor acceptor(io_service);
2667 acceptor.open(endpoint.protocol());
2668 acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
2669 acceptor.bind(endpoint);
2670 acceptor.listen(socket_base::max_connections);
2672 catch(boost::system::system_error &e)
2674 ThreadSafeMessageBox(strprintf(_("An error occured while setting up the RPC port %i for listening: %s"), endpoint.port(), e.what()),
2675 _("Error"), wxOK | wxMODAL);
2680 ssl::context context(io_service, ssl::context::sslv23);
2683 context.set_options(ssl::context::no_sslv2);
2685 filesystem::path pathCertFile(GetArg("-rpcsslcertificatechainfile", "server.cert"));
2686 if (!pathCertFile.is_complete()) pathCertFile = filesystem::path(GetDataDir()) / pathCertFile;
2687 if (filesystem::exists(pathCertFile)) context.use_certificate_chain_file(pathCertFile.string());
2688 else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", pathCertFile.string().c_str());
2690 filesystem::path pathPKFile(GetArg("-rpcsslprivatekeyfile", "server.pem"));
2691 if (!pathPKFile.is_complete()) pathPKFile = filesystem::path(GetDataDir()) / pathPKFile;
2692 if (filesystem::exists(pathPKFile)) context.use_private_key_file(pathPKFile.string(), ssl::context::pem);
2693 else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pathPKFile.string().c_str());
2695 string strCiphers = GetArg("-rpcsslciphers", "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
2696 SSL_CTX_set_cipher_list(context.impl(), strCiphers.c_str());
2701 // Accept connection
2702 SSLStream sslStream(io_service, context);
2703 SSLIOStreamDevice d(sslStream, fUseSSL);
2704 iostreams::stream<SSLIOStreamDevice> stream(d);
2706 ip::tcp::endpoint peer;
2707 vnThreadsRunning[THREAD_RPCSERVER]--;
2708 acceptor.accept(sslStream.lowest_layer(), peer);
2709 vnThreadsRunning[4]++;
2713 // Restrict callers by IP
2714 if (!ClientAllowed(peer.address().to_string()))
2716 // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
2718 stream << HTTPReply(403, "") << std::flush;
2722 map<string, string> mapHeaders;
2725 boost::thread api_caller(ReadHTTP, boost::ref(stream), boost::ref(mapHeaders), boost::ref(strRequest));
2726 if (!api_caller.timed_join(boost::posix_time::seconds(GetArg("-rpctimeout", 30))))
2729 printf("ThreadRPCServer ReadHTTP timeout\n");
2733 // Check authorization
2734 if (mapHeaders.count("authorization") == 0)
2736 stream << HTTPReply(401, "") << std::flush;
2739 if (!HTTPAuthorized(mapHeaders))
2741 printf("ThreadRPCServer incorrect password attempt from %s\n",peer.address().to_string().c_str());
2742 /* Deter brute-forcing short passwords.
2743 If this results in a DOS the user really
2744 shouldn't have their RPC port exposed.*/
2745 if (mapArgs["-rpcpassword"].size() < 20)
2748 stream << HTTPReply(401, "") << std::flush;
2752 Value id = Value::null;
2757 if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
2758 throw JSONRPCError(-32700, "Parse error");
2759 const Object& request = valRequest.get_obj();
2761 // Parse id now so errors from here on will have the id
2762 id = find_value(request, "id");
2765 Value valMethod = find_value(request, "method");
2766 if (valMethod.type() == null_type)
2767 throw JSONRPCError(-32600, "Missing method");
2768 if (valMethod.type() != str_type)
2769 throw JSONRPCError(-32600, "Method must be a string");
2770 string strMethod = valMethod.get_str();
2771 if (strMethod != "getwork" && strMethod != "getmemorypool")
2772 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
2775 Value valParams = find_value(request, "params");
2777 if (valParams.type() == array_type)
2778 params = valParams.get_array();
2779 else if (valParams.type() == null_type)
2782 throw JSONRPCError(-32600, "Params must be an array");
2785 const CRPCCommand *pcmd = tableRPC[strMethod];
2787 throw JSONRPCError(-32601, "Method not found");
2789 // Observe safe mode
2790 string strWarning = GetWarnings("rpc");
2791 if (strWarning != "" && !GetBoolArg("-disablesafemode") &&
2793 throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
2800 LOCK2(cs_main, pwalletMain->cs_wallet);
2801 result = pcmd->actor(params, false);
2805 string strReply = JSONRPCReply(result, Value::null, id);
2806 stream << HTTPReply(200, strReply) << std::flush;
2808 catch (std::exception& e)
2810 ErrorReply(stream, JSONRPCError(-1, e.what()), id);
2813 catch (Object& objError)
2815 ErrorReply(stream, objError, id);
2817 catch (std::exception& e)
2819 ErrorReply(stream, JSONRPCError(-32700, e.what()), id);
2827 Object CallRPC(const string& strMethod, const Array& params)
2829 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2830 throw runtime_error(strprintf(
2831 _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
2832 "If the file does not exist, create it with owner-readable-only file permissions."),
2833 GetConfigFile().string().c_str()));
2835 // Connect to localhost
2836 bool fUseSSL = GetBoolArg("-rpcssl");
2837 asio::io_service io_service;
2838 ssl::context context(io_service, ssl::context::sslv23);
2839 context.set_options(ssl::context::no_sslv2);
2840 SSLStream sslStream(io_service, context);
2841 SSLIOStreamDevice d(sslStream, fUseSSL);
2842 iostreams::stream<SSLIOStreamDevice> stream(d);
2843 if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", CBigNum(RPC_PORT).ToString().c_str())))
2844 throw runtime_error("couldn't connect to server");
2846 // HTTP basic authentication
2847 string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
2848 map<string, string> mapRequestHeaders;
2849 mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
2852 string strRequest = JSONRPCRequest(strMethod, params, 1);
2853 string strPost = HTTPPost(strRequest, mapRequestHeaders);
2854 stream << strPost << std::flush;
2857 map<string, string> mapHeaders;
2859 int nStatus = ReadHTTP(stream, mapHeaders, strReply);
2861 throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
2862 else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
2863 throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
2864 else if (strReply.empty())
2865 throw runtime_error("no response from server");
2869 if (!read_string(strReply, valReply))
2870 throw runtime_error("couldn't parse reply from server");
2871 const Object& reply = valReply.get_obj();
2873 throw runtime_error("expected reply to have result, error and id properties");
2881 template<typename T>
2882 void ConvertTo(Value& value)
2884 if (value.type() == str_type)
2886 // reinterpret string as unquoted json value
2888 if (!read_string(value.get_str(), value2))
2889 throw runtime_error("type mismatch");
2890 value = value2.get_value<T>();
2894 value = value.get_value<T>();
2898 int CommandLineRPC(int argc, char *argv[])
2905 while (argc > 1 && IsSwitchChar(argv[1][0]))
2913 throw runtime_error("too few parameters");
2914 string strMethod = argv[1];
2916 // Parameters default to strings
2918 for (int i = 2; i < argc; i++)
2919 params.push_back(argv[i]);
2920 int n = params.size();
2923 // Special case non-string parameter types
2925 if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
2926 if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2927 if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
2928 if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]);
2929 if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2930 if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2931 if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2932 if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
2933 if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2934 if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
2935 if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2936 if (strMethod == "getblockhash" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2937 if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]);
2938 if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2939 if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]);
2940 if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2941 if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2942 if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2943 if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2944 if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2945 if (strMethod == "walletpassphrase" && n > 2) ConvertTo<bool>(params[2]);
2946 if (strMethod == "listsinceblock" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2947 if (strMethod == "sendalert" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2948 if (strMethod == "sendalert" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2949 if (strMethod == "sendalert" && n > 4) ConvertTo<boost::int64_t>(params[4]);
2950 if (strMethod == "sendalert" && n > 5) ConvertTo<boost::int64_t>(params[5]);
2951 if (strMethod == "sendmany" && n > 1)
2953 string s = params[1].get_str();
2955 if (!read_string(s, v) || v.type() != obj_type)
2956 throw runtime_error("type mismatch");
2957 params[1] = v.get_obj();
2959 if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2960 if (strMethod == "reservebalance" && n > 0) ConvertTo<bool>(params[0]);
2961 if (strMethod == "reservebalance" && n > 1) ConvertTo<double>(params[1]);
2962 if (strMethod == "addmultisigaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2963 if (strMethod == "addmultisigaddress" && n > 1)
2965 string s = params[1].get_str();
2967 if (!read_string(s, v) || v.type() != array_type)
2968 throw runtime_error("type mismatch "+s);
2969 params[1] = v.get_array();
2973 Object reply = CallRPC(strMethod, params);
2976 const Value& result = find_value(reply, "result");
2977 const Value& error = find_value(reply, "error");
2979 if (error.type() != null_type)
2982 strPrint = "error: " + write_string(error, false);
2983 int code = find_value(error.get_obj(), "code").get_int();
2989 if (result.type() == null_type)
2991 else if (result.type() == str_type)
2992 strPrint = result.get_str();
2994 strPrint = write_string(result, true);
2997 catch (std::exception& e)
2999 strPrint = string("error: ") + e.what();
3004 PrintException(NULL, "CommandLineRPC()");
3009 fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
3018 int main(int argc, char *argv[])
3021 // Turn off microsoft heap dump noise
3022 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
3023 _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
3025 setbuf(stdin, NULL);
3026 setbuf(stdout, NULL);
3027 setbuf(stderr, NULL);
3031 if (argc >= 2 && string(argv[1]) == "-server")
3033 printf("server ready\n");
3034 ThreadRPCServer(NULL);
3038 return CommandLineRPC(argc, argv);
3041 catch (std::exception& e) {
3042 PrintException(&e, "main()");
3044 PrintException(NULL, "main()");
3050 const CRPCTable tableRPC;