1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2012 The Bitcoin developers
3 // Copyright (c) 2011-2012 The PPCoin developers
4 // Copyright (c) 2012-2013 The NovaCoin developers
5 // Distributed under the MIT/X11 software license, see the accompanying
6 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
14 #include "checkpoints.h"
15 #include "ui_interface.h"
16 #include "bitcoinrpc.h"
19 #include <boost/asio.hpp>
20 #include <boost/filesystem.hpp>
21 #include <boost/iostreams/concepts.hpp>
22 #include <boost/iostreams/stream.hpp>
23 #include <boost/algorithm/string.hpp>
24 #include <boost/lexical_cast.hpp>
25 #include <boost/asio/ssl.hpp>
26 #include <boost/filesystem/fstream.hpp>
27 typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> SSLStream;
29 #define printf OutputDebugStringF
30 // MinGW 3.4.5 gets "fatal error: had to relocate PCH" if the json headers are
31 // precompiled in headers.h. The problem might be when the pch file goes over
32 // a certain size around 145MB. If we need access to json_spirit outside this
33 // file, we could use the compiled json_spirit option.
36 using namespace boost;
37 using namespace boost::asio;
38 using namespace json_spirit;
40 void ThreadRPCServer2(void* parg);
42 static std::string strRPCUserColonPass;
44 static int64 nWalletUnlockTime;
45 static CCriticalSection cs_nWalletUnlockTime;
47 extern Value dumpprivkey(const Array& params, bool fHelp);
48 extern Value importprivkey(const Array& params, bool fHelp);
50 extern CBigNum bnProofOfWorkLimit;
52 Object JSONRPCError(int code, const string& message)
55 error.push_back(Pair("code", code));
56 error.push_back(Pair("message", message));
60 double GetDifficulty(const CBlockIndex* blockindex = NULL)
62 // Floating point number that is a multiple of the minimum difficulty,
63 // minimum difficulty = 1.0.
64 if (blockindex == NULL)
66 if (pindexBest == NULL)
69 blockindex = GetLastBlockIndex(pindexBest, false);
72 int nShift = (blockindex->nBits >> 24) & 0xff;
75 (double)0x0000ffff / (double)(blockindex->nBits & 0x00ffffff);
92 int64 AmountFromValue(const Value& value)
94 double dAmount = value.get_real();
95 if (dAmount <= 0.0 || dAmount > MAX_MONEY)
96 throw JSONRPCError(-3, "Invalid amount");
97 int64 nAmount = roundint64(dAmount * COIN);
98 if (!MoneyRange(nAmount))
99 throw JSONRPCError(-3, "Invalid amount");
103 Value ValueFromAmount(int64 amount)
105 return (double)amount / (double)COIN;
109 HexBits(unsigned int nBits)
115 uBits.nBits = htonl((int32_t)nBits);
116 return HexStr(BEGIN(uBits.cBits), END(uBits.cBits));
119 void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
121 int confirms = wtx.GetDepthInMainChain();
122 entry.push_back(Pair("confirmations", confirms));
125 entry.push_back(Pair("blockhash", wtx.hashBlock.GetHex()));
126 entry.push_back(Pair("blockindex", wtx.nIndex));
128 entry.push_back(Pair("txid", wtx.GetHash().GetHex()));
129 entry.push_back(Pair("time", (boost::int64_t)wtx.GetTxTime()));
130 BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
131 entry.push_back(Pair(item.first, item.second));
134 string AccountFromValue(const Value& value)
136 string strAccount = value.get_str();
137 if (strAccount == "*")
138 throw JSONRPCError(-11, "Invalid account name");
142 Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool fPrintTransactionDetail)
145 result.push_back(Pair("hash", block.GetHash().GetHex()));
146 result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION)));
147 result.push_back(Pair("height", blockindex->nHeight));
148 result.push_back(Pair("version", block.nVersion));
149 result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex()));
150 result.push_back(Pair("time", DateTimeStrFormat(block.GetBlockTime())));
151 result.push_back(Pair("nonce", (boost::uint64_t)block.nNonce));
152 result.push_back(Pair("bits", HexBits(block.nBits)));
153 result.push_back(Pair("difficulty", GetDifficulty(blockindex)));
154 result.push_back(Pair("mint", ValueFromAmount(blockindex->nMint)));
155 if (blockindex->pprev)
156 result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex()));
157 if (blockindex->pnext)
158 result.push_back(Pair("nextblockhash", blockindex->pnext->GetBlockHash().GetHex()));
160 BOOST_FOREACH (const CTransaction& tx, block.vtx)
162 if (fPrintTransactionDetail)
164 txinfo.push_back(tx.ToStringShort());
165 txinfo.push_back(DateTimeStrFormat(tx.nTime));
166 BOOST_FOREACH(const CTxIn& txin, tx.vin)
167 txinfo.push_back(txin.ToStringShort());
168 BOOST_FOREACH(const CTxOut& txout, tx.vout)
169 txinfo.push_back(txout.ToStringShort());
172 txinfo.push_back(tx.GetHash().GetHex());
174 result.push_back(Pair("tx", txinfo));
181 /// Note: This interface may still be subject to change.
184 string CRPCTable::help(string strCommand) const
187 set<rpcfn_type> setDone;
188 for (map<string, const CRPCCommand*>::const_iterator mi = mapCommands.begin(); mi != mapCommands.end(); ++mi)
190 const CRPCCommand *pcmd = mi->second;
191 string strMethod = mi->first;
192 // We already filter duplicates, but these deprecated screw up the sort order
193 if (strMethod == "getamountreceived" ||
194 strMethod == "getallreceived" ||
195 strMethod == "getblocknumber" || // deprecated
196 (strMethod.find("label") != string::npos))
198 if (strCommand != "" && strMethod != strCommand)
203 rpcfn_type pfn = pcmd->actor;
204 if (setDone.insert(pfn).second)
205 (*pfn)(params, true);
207 catch (std::exception& e)
209 // Help text is returned in an exception
210 string strHelp = string(e.what());
211 if (strCommand == "")
212 if (strHelp.find('\n') != string::npos)
213 strHelp = strHelp.substr(0, strHelp.find('\n'));
214 strRet += strHelp + "\n";
218 strRet = strprintf("help: unknown command: %s\n", strCommand.c_str());
219 strRet = strRet.substr(0,strRet.size()-1);
223 Value help(const Array& params, bool fHelp)
225 if (fHelp || params.size() > 1)
228 "List commands, or get help for a command.");
231 if (params.size() > 0)
232 strCommand = params[0].get_str();
234 return tableRPC.help(strCommand);
238 Value stop(const Array& params, bool fHelp)
240 if (fHelp || params.size() != 0)
243 "Stop novacoin server.");
244 // Shutdown will take long enough that the response should get back
246 return "novacoin server stopping";
250 Value getblockcount(const Array& params, bool fHelp)
252 if (fHelp || params.size() != 0)
255 "Returns the number of blocks in the longest block chain.");
262 Value getblocknumber(const Array& params, bool fHelp)
264 if (fHelp || params.size() != 0)
267 "Deprecated. Use getblockcount.");
273 Value getconnectioncount(const Array& params, bool fHelp)
275 if (fHelp || params.size() != 0)
277 "getconnectioncount\n"
278 "Returns the number of connections to other nodes.");
280 return (int)vNodes.size();
284 Value getdifficulty(const Array& params, bool fHelp)
286 if (fHelp || params.size() != 0)
289 "Returns difficulty as a multiple of the minimum difficulty.");
292 obj.push_back(Pair("proof-of-work", GetDifficulty()));
293 obj.push_back(Pair("proof-of-stake", GetDifficulty(GetLastBlockIndex(pindexBest, true))));
294 obj.push_back(Pair("search-interval", (int)nLastCoinStakeSearchInterval));
299 Value getgenerate(const Array& params, bool fHelp)
301 if (fHelp || params.size() != 0)
304 "Returns true or false.");
306 return GetBoolArg("-gen");
310 Value setgenerate(const Array& params, bool fHelp)
312 if (fHelp || params.size() < 1 || params.size() > 2)
314 "setgenerate <generate> [genproclimit]\n"
315 "<generate> is true or false to turn generation on or off.\n"
316 "Generation is limited to [genproclimit] processors, -1 is unlimited.");
318 bool fGenerate = true;
319 if (params.size() > 0)
320 fGenerate = params[0].get_bool();
322 if (params.size() > 1)
324 int nGenProcLimit = params[1].get_int();
325 mapArgs["-genproclimit"] = itostr(nGenProcLimit);
326 if (nGenProcLimit == 0)
329 mapArgs["-gen"] = (fGenerate ? "1" : "0");
331 GenerateBitcoins(fGenerate, pwalletMain);
336 Value gethashespersec(const Array& params, bool fHelp)
338 if (fHelp || params.size() != 0)
341 "Returns a recent hashes per second performance measurement while generating.");
343 if (GetTimeMillis() - nHPSTimerStart > 8000)
344 return (boost::int64_t)0;
345 return (boost::int64_t)dHashesPerSec;
349 Value getinfo(const Array& params, bool fHelp)
351 if (fHelp || params.size() != 0)
354 "Returns an object containing various state info.");
357 obj.push_back(Pair("version", FormatFullVersion()));
358 obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION));
359 obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
360 obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
361 obj.push_back(Pair("newmint", ValueFromAmount(pwalletMain->GetNewMint())));
362 obj.push_back(Pair("stake", ValueFromAmount(pwalletMain->GetStake())));
363 obj.push_back(Pair("blocks", (int)nBestHeight));
364 obj.push_back(Pair("moneysupply", ValueFromAmount(pindexBest->nMoneySupply)));
365 obj.push_back(Pair("connections", (int)vNodes.size()));
366 obj.push_back(Pair("proxy", (fUseProxy ? addrProxy.ToStringIPPort() : string())));
367 obj.push_back(Pair("ip", addrSeenByPeer.ToStringIP()));
368 obj.push_back(Pair("difficulty", (double)GetDifficulty()));
369 obj.push_back(Pair("testnet", fTestNet));
370 obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));
371 obj.push_back(Pair("keypoolsize", pwalletMain->GetKeyPoolSize()));
372 obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee)));
373 if (pwalletMain->IsCrypted())
374 obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime / 1000));
375 obj.push_back(Pair("errors", GetWarnings("statusbar")));
380 Value getmininginfo(const Array& params, bool fHelp)
382 if (fHelp || params.size() != 0)
385 "Returns an object containing mining-related information.");
388 obj.push_back(Pair("blocks", (int)nBestHeight));
389 obj.push_back(Pair("currentblocksize",(uint64_t)nLastBlockSize));
390 obj.push_back(Pair("currentblocktx",(uint64_t)nLastBlockTx));
391 obj.push_back(Pair("difficulty", (double)GetDifficulty()));
392 obj.push_back(Pair("errors", GetWarnings("statusbar")));
393 obj.push_back(Pair("generate", GetBoolArg("-gen")));
394 obj.push_back(Pair("genproclimit", (int)GetArg("-genproclimit", -1)));
395 obj.push_back(Pair("hashespersec", gethashespersec(params, false)));
396 obj.push_back(Pair("pooledtx", (uint64_t)mempool.size()));
397 obj.push_back(Pair("testnet", fTestNet));
402 Value getnewaddress(const Array& params, bool fHelp)
404 if (fHelp || params.size() > 1)
406 "getnewaddress [account]\n"
407 "Returns a new novacoin address for receiving payments. "
408 "If [account] is specified (recommended), it is added to the address book "
409 "so payments received with the address will be credited to [account].");
411 // Parse the account first so we don't generate a key if there's an error
413 if (params.size() > 0)
414 strAccount = AccountFromValue(params[0]);
416 if (!pwalletMain->IsLocked())
417 pwalletMain->TopUpKeyPool();
419 // Generate a new key that is added to wallet
420 std::vector<unsigned char> newKey;
421 if (!pwalletMain->GetKeyFromPool(newKey, false))
422 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
423 CBitcoinAddress address(newKey);
425 pwalletMain->SetAddressBookName(address, strAccount);
427 return address.ToString();
431 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
433 CWalletDB walletdb(pwalletMain->strWalletFile);
436 walletdb.ReadAccount(strAccount, account);
438 bool bKeyUsed = false;
440 // Check if the current key has been used
441 if (!account.vchPubKey.empty())
443 CScript scriptPubKey;
444 scriptPubKey.SetBitcoinAddress(account.vchPubKey);
445 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
446 it != pwalletMain->mapWallet.end() && !account.vchPubKey.empty();
449 const CWalletTx& wtx = (*it).second;
450 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
451 if (txout.scriptPubKey == scriptPubKey)
456 // Generate a new key
457 if (account.vchPubKey.empty() || bForceNew || bKeyUsed)
459 if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false))
460 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
462 pwalletMain->SetAddressBookName(CBitcoinAddress(account.vchPubKey), strAccount);
463 walletdb.WriteAccount(strAccount, account);
466 return CBitcoinAddress(account.vchPubKey);
469 Value getaccountaddress(const Array& params, bool fHelp)
471 if (fHelp || params.size() != 1)
473 "getaccountaddress <account>\n"
474 "Returns the current novacoin address for receiving payments to this account.");
476 // Parse the account first so we don't generate a key if there's an error
477 string strAccount = AccountFromValue(params[0]);
481 ret = GetAccountAddress(strAccount).ToString();
488 Value setaccount(const Array& params, bool fHelp)
490 if (fHelp || params.size() < 1 || params.size() > 2)
492 "setaccount <novacoinaddress> <account>\n"
493 "Sets the account associated with the given address.");
495 CBitcoinAddress address(params[0].get_str());
496 if (!address.IsValid())
497 throw JSONRPCError(-5, "Invalid novacoin address");
501 if (params.size() > 1)
502 strAccount = AccountFromValue(params[1]);
504 // Detect when changing the account of an address that is the 'unused current key' of another account:
505 if (pwalletMain->mapAddressBook.count(address))
507 string strOldAccount = pwalletMain->mapAddressBook[address];
508 if (address == GetAccountAddress(strOldAccount))
509 GetAccountAddress(strOldAccount, true);
512 pwalletMain->SetAddressBookName(address, strAccount);
518 Value getaccount(const Array& params, bool fHelp)
520 if (fHelp || params.size() != 1)
522 "getaccount <novacoinaddress>\n"
523 "Returns the account associated with the given address.");
525 CBitcoinAddress address(params[0].get_str());
526 if (!address.IsValid())
527 throw JSONRPCError(-5, "Invalid novacoin address");
530 map<CBitcoinAddress, string>::iterator mi = pwalletMain->mapAddressBook.find(address);
531 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
532 strAccount = (*mi).second;
537 Value getaddressesbyaccount(const Array& params, bool fHelp)
539 if (fHelp || params.size() != 1)
541 "getaddressesbyaccount <account>\n"
542 "Returns the list of addresses for the given account.");
544 string strAccount = AccountFromValue(params[0]);
546 // Find all addresses that have the given account
548 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
550 const CBitcoinAddress& address = item.first;
551 const string& strName = item.second;
552 if (strName == strAccount)
553 ret.push_back(address.ToString());
558 Value settxfee(const Array& params, bool fHelp)
560 if (fHelp || params.size() < 1 || params.size() > 1 || AmountFromValue(params[0]) < MIN_TX_FEE)
562 "settxfee <amount>\n"
563 "<amount> is a real and is rounded to 0.01 (cent)\n"
564 "Minimum and default transaction fee per KB is 1 cent");
566 nTransactionFee = AmountFromValue(params[0]);
567 nTransactionFee = (nTransactionFee / CENT) * CENT; // round to cent
571 Value sendtoaddress(const Array& params, bool fHelp)
573 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
575 "sendtoaddress <novacoinaddress> <amount> [comment] [comment-to]\n"
576 "<amount> is a real and is rounded to the nearest 0.000001\n"
577 "requires wallet passphrase to be set with walletpassphrase first");
578 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
580 "sendtoaddress <novacoinaddress> <amount> [comment] [comment-to]\n"
581 "<amount> is a real and is rounded to the nearest 0.000001");
583 CBitcoinAddress address(params[0].get_str());
584 if (!address.IsValid())
585 throw JSONRPCError(-5, "Invalid novacoin address");
588 int64 nAmount = AmountFromValue(params[1]);
589 if (nAmount < MIN_TXOUT_AMOUNT)
590 throw JSONRPCError(-101, "Send amount too small");
594 if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
595 wtx.mapValue["comment"] = params[2].get_str();
596 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
597 wtx.mapValue["to"] = params[3].get_str();
599 if (pwalletMain->IsLocked())
600 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
602 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
604 throw JSONRPCError(-4, strError);
606 return wtx.GetHash().GetHex();
609 Value signmessage(const Array& params, bool fHelp)
611 if (fHelp || params.size() != 2)
613 "signmessage <novacoinaddress> <message>\n"
614 "Sign a message with the private key of an address");
616 if (pwalletMain->IsLocked())
617 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
619 string strAddress = params[0].get_str();
620 string strMessage = params[1].get_str();
622 CBitcoinAddress addr(strAddress);
624 throw JSONRPCError(-3, "Invalid address");
627 if (!pwalletMain->GetKey(addr, key))
628 throw JSONRPCError(-4, "Private key not available");
630 CDataStream ss(SER_GETHASH, 0);
631 ss << strMessageMagic;
634 vector<unsigned char> vchSig;
635 if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig))
636 throw JSONRPCError(-5, "Sign failed");
638 return EncodeBase64(&vchSig[0], vchSig.size());
641 Value verifymessage(const Array& params, bool fHelp)
643 if (fHelp || params.size() != 3)
645 "verifymessage <novacoinaddress> <signature> <message>\n"
646 "Verify a signed message");
648 string strAddress = params[0].get_str();
649 string strSign = params[1].get_str();
650 string strMessage = params[2].get_str();
652 CBitcoinAddress addr(strAddress);
654 throw JSONRPCError(-3, "Invalid address");
656 bool fInvalid = false;
657 vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
660 throw JSONRPCError(-5, "Malformed base64 encoding");
662 CDataStream ss(SER_GETHASH, 0);
663 ss << strMessageMagic;
667 if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
670 return (CBitcoinAddress(key.GetPubKey()) == addr);
674 Value getreceivedbyaddress(const Array& params, bool fHelp)
676 if (fHelp || params.size() < 1 || params.size() > 2)
678 "getreceivedbyaddress <novacoinaddress> [minconf=1]\n"
679 "Returns the total amount received by <novacoinaddress> in transactions with at least [minconf] confirmations.");
682 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
683 CScript scriptPubKey;
684 if (!address.IsValid())
685 throw JSONRPCError(-5, "Invalid novacoin address");
686 scriptPubKey.SetBitcoinAddress(address);
687 if (!IsMine(*pwalletMain,scriptPubKey))
690 // Minimum confirmations
692 if (params.size() > 1)
693 nMinDepth = params[1].get_int();
697 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
699 const CWalletTx& wtx = (*it).second;
700 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
703 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
704 if (txout.scriptPubKey == scriptPubKey)
705 if (wtx.GetDepthInMainChain() >= nMinDepth)
706 nAmount += txout.nValue;
709 return ValueFromAmount(nAmount);
713 void GetAccountAddresses(string strAccount, set<CBitcoinAddress>& setAddress)
715 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
717 const CBitcoinAddress& address = item.first;
718 const string& strName = item.second;
719 if (strName == strAccount)
720 setAddress.insert(address);
725 Value getreceivedbyaccount(const Array& params, bool fHelp)
727 if (fHelp || params.size() < 1 || params.size() > 2)
729 "getreceivedbyaccount <account> [minconf=1]\n"
730 "Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.");
732 // Minimum confirmations
734 if (params.size() > 1)
735 nMinDepth = params[1].get_int();
737 // Get the set of pub keys assigned to account
738 string strAccount = AccountFromValue(params[0]);
739 set<CBitcoinAddress> setAddress;
740 GetAccountAddresses(strAccount, setAddress);
744 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
746 const CWalletTx& wtx = (*it).second;
747 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
750 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
752 CBitcoinAddress address;
753 if (ExtractAddress(txout.scriptPubKey, address) && pwalletMain->HaveKey(address) && setAddress.count(address))
754 if (wtx.GetDepthInMainChain() >= nMinDepth)
755 nAmount += txout.nValue;
759 return (double)nAmount / (double)COIN;
763 int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth)
767 // Tally wallet transactions
768 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
770 const CWalletTx& wtx = (*it).second;
774 int64 nGenerated, nReceived, nSent, nFee;
775 wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee);
777 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
778 nBalance += nReceived;
779 nBalance += nGenerated - nSent - nFee;
782 // Tally internal accounting entries
783 nBalance += walletdb.GetAccountCreditDebit(strAccount);
788 int64 GetAccountBalance(const string& strAccount, int nMinDepth)
790 CWalletDB walletdb(pwalletMain->strWalletFile);
791 return GetAccountBalance(walletdb, strAccount, nMinDepth);
795 Value getbalance(const Array& params, bool fHelp)
797 if (fHelp || params.size() > 2)
799 "getbalance [account] [minconf=1]\n"
800 "If [account] is not specified, returns the server's total available balance.\n"
801 "If [account] is specified, returns the balance in the account.");
803 if (params.size() == 0)
804 return ValueFromAmount(pwalletMain->GetBalance());
807 if (params.size() > 1)
808 nMinDepth = params[1].get_int();
810 if (params[0].get_str() == "*") {
811 // Calculate total balance a different way from GetBalance()
812 // (GetBalance() sums up all unspent TxOuts)
813 // getbalance and getbalance '*' should always return the same number.
815 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
817 const CWalletTx& wtx = (*it).second;
821 int64 allGeneratedImmature, allGeneratedMature, allFee;
822 allGeneratedImmature = allGeneratedMature = allFee = 0;
823 string strSentAccount;
824 list<pair<CBitcoinAddress, int64> > listReceived;
825 list<pair<CBitcoinAddress, int64> > listSent;
826 wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
827 if (wtx.GetDepthInMainChain() >= nMinDepth)
829 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listReceived)
830 nBalance += r.second;
832 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listSent)
833 nBalance -= r.second;
835 nBalance += allGeneratedMature;
837 return ValueFromAmount(nBalance);
840 string strAccount = AccountFromValue(params[0]);
842 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
844 return ValueFromAmount(nBalance);
848 Value movecmd(const Array& params, bool fHelp)
850 if (fHelp || params.size() < 3 || params.size() > 5)
852 "move <fromaccount> <toaccount> <amount> [minconf=1] [comment]\n"
853 "Move from one account in your wallet to another.");
855 string strFrom = AccountFromValue(params[0]);
856 string strTo = AccountFromValue(params[1]);
857 int64 nAmount = AmountFromValue(params[2]);
858 if (params.size() > 3)
859 // unused parameter, used to be nMinDepth, keep type-checking it though
860 (void)params[3].get_int();
862 if (params.size() > 4)
863 strComment = params[4].get_str();
865 CWalletDB walletdb(pwalletMain->strWalletFile);
866 if (!walletdb.TxnBegin())
867 throw JSONRPCError(-20, "database error");
869 int64 nNow = GetAdjustedTime();
872 CAccountingEntry debit;
873 debit.strAccount = strFrom;
874 debit.nCreditDebit = -nAmount;
876 debit.strOtherAccount = strTo;
877 debit.strComment = strComment;
878 walletdb.WriteAccountingEntry(debit);
881 CAccountingEntry credit;
882 credit.strAccount = strTo;
883 credit.nCreditDebit = nAmount;
885 credit.strOtherAccount = strFrom;
886 credit.strComment = strComment;
887 walletdb.WriteAccountingEntry(credit);
889 if (!walletdb.TxnCommit())
890 throw JSONRPCError(-20, "database error");
896 Value sendfrom(const Array& params, bool fHelp)
898 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
900 "sendfrom <fromaccount> <tonovacoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
901 "<amount> is a real and is rounded to the nearest 0.000001\n"
902 "requires wallet passphrase to be set with walletpassphrase first");
903 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
905 "sendfrom <fromaccount> <tonovacoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
906 "<amount> is a real and is rounded to the nearest 0.000001");
908 string strAccount = AccountFromValue(params[0]);
909 CBitcoinAddress address(params[1].get_str());
910 if (!address.IsValid())
911 throw JSONRPCError(-5, "Invalid novacoin address");
912 int64 nAmount = AmountFromValue(params[2]);
913 if (nAmount < MIN_TXOUT_AMOUNT)
914 throw JSONRPCError(-101, "Send amount too small");
916 if (params.size() > 3)
917 nMinDepth = params[3].get_int();
920 wtx.strFromAccount = strAccount;
921 if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
922 wtx.mapValue["comment"] = params[4].get_str();
923 if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
924 wtx.mapValue["to"] = params[5].get_str();
926 if (pwalletMain->IsLocked())
927 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
930 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
931 if (nAmount > nBalance)
932 throw JSONRPCError(-6, "Account has insufficient funds");
935 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
937 throw JSONRPCError(-4, strError);
939 return wtx.GetHash().GetHex();
943 Value sendmany(const Array& params, bool fHelp)
945 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
947 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
948 "amounts are double-precision floating point numbers\n"
949 "requires wallet passphrase to be set with walletpassphrase first");
950 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
952 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
953 "amounts are double-precision floating point numbers");
955 string strAccount = AccountFromValue(params[0]);
956 Object sendTo = params[1].get_obj();
958 if (params.size() > 2)
959 nMinDepth = params[2].get_int();
962 wtx.strFromAccount = strAccount;
963 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
964 wtx.mapValue["comment"] = params[3].get_str();
966 set<CBitcoinAddress> setAddress;
967 vector<pair<CScript, int64> > vecSend;
969 int64 totalAmount = 0;
970 BOOST_FOREACH(const Pair& s, sendTo)
972 CBitcoinAddress address(s.name_);
973 if (!address.IsValid())
974 throw JSONRPCError(-5, string("Invalid novacoin address:")+s.name_);
976 if (setAddress.count(address))
977 throw JSONRPCError(-8, string("Invalid parameter, duplicated address: ")+s.name_);
978 setAddress.insert(address);
980 CScript scriptPubKey;
981 scriptPubKey.SetBitcoinAddress(address);
982 int64 nAmount = AmountFromValue(s.value_);
983 if (nAmount < MIN_TXOUT_AMOUNT)
984 throw JSONRPCError(-101, "Send amount too small");
985 totalAmount += nAmount;
987 vecSend.push_back(make_pair(scriptPubKey, nAmount));
990 if (pwalletMain->IsLocked())
991 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
992 if (fWalletUnlockMintOnly)
993 throw JSONRPCError(-13, "Error: Wallet unlocked for block minting only.");
996 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
997 if (totalAmount > nBalance)
998 throw JSONRPCError(-6, "Account has insufficient funds");
1001 CReserveKey keyChange(pwalletMain);
1002 int64 nFeeRequired = 0;
1003 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
1006 if (totalAmount + nFeeRequired > pwalletMain->GetBalance())
1007 throw JSONRPCError(-6, "Insufficient funds");
1008 throw JSONRPCError(-4, "Transaction creation failed");
1010 if (!pwalletMain->CommitTransaction(wtx, keyChange))
1011 throw JSONRPCError(-4, "Transaction commit failed");
1013 return wtx.GetHash().GetHex();
1016 Value addmultisigaddress(const Array& params, bool fHelp)
1018 if (fHelp || params.size() < 2 || params.size() > 3)
1020 string msg = "addmultisigaddress <nrequired> <'[\"key\",\"key\"]'> [account]\n"
1021 "Add a nrequired-to-sign multisignature address to the wallet\"\n"
1022 "each key is a novacoin address or hex-encoded public key\n"
1023 "If [account] is specified, assign address to [account].";
1024 throw runtime_error(msg);
1027 int nRequired = params[0].get_int();
1028 const Array& keys = params[1].get_array();
1030 if (params.size() > 2)
1031 strAccount = AccountFromValue(params[2]);
1033 // Gather public keys
1035 throw runtime_error("a multisignature address must require at least one key to redeem");
1036 if ((int)keys.size() < nRequired)
1037 throw runtime_error(
1038 strprintf("not enough keys supplied "
1039 "(got %d keys, but need at least %d to redeem)", keys.size(), nRequired));
1040 std::vector<CKey> pubkeys;
1041 pubkeys.resize(keys.size());
1042 for (unsigned int i = 0; i < keys.size(); i++)
1044 const std::string& ks = keys[i].get_str();
1046 // Case 1: bitcoin address and we have full public key:
1047 CBitcoinAddress address(ks);
1048 if (address.IsValid())
1050 if (address.IsScript())
1051 throw runtime_error(
1052 strprintf("%s is a pay-to-script address",ks.c_str()));
1053 std::vector<unsigned char> vchPubKey;
1054 if (!pwalletMain->GetPubKey(address, vchPubKey))
1055 throw runtime_error(
1056 strprintf("no full public key for address %s",ks.c_str()));
1057 if (vchPubKey.empty() || !pubkeys[i].SetPubKey(vchPubKey))
1058 throw runtime_error(" Invalid public key: "+ks);
1061 // Case 2: hex public key
1064 vector<unsigned char> vchPubKey = ParseHex(ks);
1065 if (vchPubKey.empty() || !pubkeys[i].SetPubKey(vchPubKey))
1066 throw runtime_error(" Invalid public key: "+ks);
1070 throw runtime_error(" Invalid public key: "+ks);
1074 // Construct using pay-to-script-hash:
1076 inner.SetMultisig(nRequired, pubkeys);
1078 uint160 scriptHash = Hash160(inner);
1079 CScript scriptPubKey;
1080 scriptPubKey.SetPayToScriptHash(inner);
1081 pwalletMain->AddCScript(inner);
1082 CBitcoinAddress address;
1083 address.SetScriptHash160(scriptHash);
1085 pwalletMain->SetAddressBookName(address, strAccount);
1086 return address.ToString();
1097 nConf = std::numeric_limits<int>::max();
1101 Value ListReceived(const Array& params, bool fByAccounts)
1103 // Minimum confirmations
1105 if (params.size() > 0)
1106 nMinDepth = params[0].get_int();
1108 // Whether to include empty accounts
1109 bool fIncludeEmpty = false;
1110 if (params.size() > 1)
1111 fIncludeEmpty = params[1].get_bool();
1114 map<CBitcoinAddress, tallyitem> mapTally;
1115 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1117 const CWalletTx& wtx = (*it).second;
1119 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
1122 int nDepth = wtx.GetDepthInMainChain();
1123 if (nDepth < nMinDepth)
1126 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
1128 CBitcoinAddress address;
1129 if (!ExtractAddress(txout.scriptPubKey, address) || !pwalletMain->HaveKey(address) || !address.IsValid())
1132 tallyitem& item = mapTally[address];
1133 item.nAmount += txout.nValue;
1134 item.nConf = min(item.nConf, nDepth);
1140 map<string, tallyitem> mapAccountTally;
1141 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
1143 const CBitcoinAddress& address = item.first;
1144 const string& strAccount = item.second;
1145 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
1146 if (it == mapTally.end() && !fIncludeEmpty)
1150 int nConf = std::numeric_limits<int>::max();
1151 if (it != mapTally.end())
1153 nAmount = (*it).second.nAmount;
1154 nConf = (*it).second.nConf;
1159 tallyitem& item = mapAccountTally[strAccount];
1160 item.nAmount += nAmount;
1161 item.nConf = min(item.nConf, nConf);
1166 obj.push_back(Pair("address", address.ToString()));
1167 obj.push_back(Pair("account", strAccount));
1168 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1169 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1176 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
1178 int64 nAmount = (*it).second.nAmount;
1179 int nConf = (*it).second.nConf;
1181 obj.push_back(Pair("account", (*it).first));
1182 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1183 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1191 Value listreceivedbyaddress(const Array& params, bool fHelp)
1193 if (fHelp || params.size() > 2)
1194 throw runtime_error(
1195 "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
1196 "[minconf] is the minimum number of confirmations before payments are included.\n"
1197 "[includeempty] whether to include addresses that haven't received any payments.\n"
1198 "Returns an array of objects containing:\n"
1199 " \"address\" : receiving address\n"
1200 " \"account\" : the account of the receiving address\n"
1201 " \"amount\" : total amount received by the address\n"
1202 " \"confirmations\" : number of confirmations of the most recent transaction included");
1204 return ListReceived(params, false);
1207 Value listreceivedbyaccount(const Array& params, bool fHelp)
1209 if (fHelp || params.size() > 2)
1210 throw runtime_error(
1211 "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
1212 "[minconf] is the minimum number of confirmations before payments are included.\n"
1213 "[includeempty] whether to include accounts that haven't received any payments.\n"
1214 "Returns an array of objects containing:\n"
1215 " \"account\" : the account of the receiving addresses\n"
1216 " \"amount\" : total amount received by addresses with this account\n"
1217 " \"confirmations\" : number of confirmations of the most recent transaction included");
1219 return ListReceived(params, true);
1222 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret)
1224 int64 nGeneratedImmature, nGeneratedMature, nFee;
1225 string strSentAccount;
1226 list<pair<CBitcoinAddress, int64> > listReceived;
1227 list<pair<CBitcoinAddress, int64> > listSent;
1229 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1231 bool fAllAccounts = (strAccount == string("*"));
1233 // Generated blocks assigned to account ""
1234 if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == ""))
1237 entry.push_back(Pair("account", string("")));
1238 if (nGeneratedImmature)
1240 entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
1241 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
1245 entry.push_back(Pair("category", "generate"));
1246 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
1249 WalletTxToJSON(wtx, entry);
1250 ret.push_back(entry);
1254 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1256 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1259 entry.push_back(Pair("account", strSentAccount));
1260 entry.push_back(Pair("address", s.first.ToString()));
1261 entry.push_back(Pair("category", "send"));
1262 entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1263 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1265 WalletTxToJSON(wtx, entry);
1266 ret.push_back(entry);
1271 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1273 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1276 if (pwalletMain->mapAddressBook.count(r.first))
1277 account = pwalletMain->mapAddressBook[r.first];
1278 if (fAllAccounts || (account == strAccount))
1281 entry.push_back(Pair("account", account));
1282 entry.push_back(Pair("address", r.first.ToString()));
1283 entry.push_back(Pair("category", "receive"));
1284 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1286 WalletTxToJSON(wtx, entry);
1287 ret.push_back(entry);
1293 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1295 bool fAllAccounts = (strAccount == string("*"));
1297 if (fAllAccounts || acentry.strAccount == strAccount)
1300 entry.push_back(Pair("account", acentry.strAccount));
1301 entry.push_back(Pair("category", "move"));
1302 entry.push_back(Pair("time", (boost::int64_t)acentry.nTime));
1303 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1304 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1305 entry.push_back(Pair("comment", acentry.strComment));
1306 ret.push_back(entry);
1310 Value listtransactions(const Array& params, bool fHelp)
1312 if (fHelp || params.size() > 3)
1313 throw runtime_error(
1314 "listtransactions [account] [count=10] [from=0]\n"
1315 "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1317 string strAccount = "*";
1318 if (params.size() > 0)
1319 strAccount = params[0].get_str();
1321 if (params.size() > 1)
1322 nCount = params[1].get_int();
1324 if (params.size() > 2)
1325 nFrom = params[2].get_int();
1328 throw JSONRPCError(-8, "Negative count");
1330 throw JSONRPCError(-8, "Negative from");
1333 CWalletDB walletdb(pwalletMain->strWalletFile);
1335 // First: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap.
1336 typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
1337 typedef multimap<int64, TxPair > TxItems;
1340 // Note: maintaining indices in the database of (account,time) --> txid and (account, time) --> acentry
1341 // would make this much faster for applications that do this a lot.
1342 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1344 CWalletTx* wtx = &((*it).second);
1345 txByTime.insert(make_pair(wtx->GetTxTime(), TxPair(wtx, (CAccountingEntry*)0)));
1347 list<CAccountingEntry> acentries;
1348 walletdb.ListAccountCreditDebit(strAccount, acentries);
1349 BOOST_FOREACH(CAccountingEntry& entry, acentries)
1351 txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
1354 // iterate backwards until we have nCount items to return:
1355 for (TxItems::reverse_iterator it = txByTime.rbegin(); it != txByTime.rend(); ++it)
1357 CWalletTx *const pwtx = (*it).second.first;
1359 ListTransactions(*pwtx, strAccount, 0, true, ret);
1360 CAccountingEntry *const pacentry = (*it).second.second;
1362 AcentryToJSON(*pacentry, strAccount, ret);
1364 if (ret.size() >= (nCount+nFrom)) break;
1366 // ret is newest to oldest
1368 if (nFrom > (int)ret.size())
1370 if ((nFrom + nCount) > (int)ret.size())
1371 nCount = ret.size() - nFrom;
1372 Array::iterator first = ret.begin();
1373 std::advance(first, nFrom);
1374 Array::iterator last = ret.begin();
1375 std::advance(last, nFrom+nCount);
1377 if (last != ret.end()) ret.erase(last, ret.end());
1378 if (first != ret.begin()) ret.erase(ret.begin(), first);
1380 std::reverse(ret.begin(), ret.end()); // Return oldest to newest
1385 Value listaccounts(const Array& params, bool fHelp)
1387 if (fHelp || params.size() > 1)
1388 throw runtime_error(
1389 "listaccounts [minconf=1]\n"
1390 "Returns Object that has account names as keys, account balances as values.");
1393 if (params.size() > 0)
1394 nMinDepth = params[0].get_int();
1396 map<string, int64> mapAccountBalances;
1397 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& entry, pwalletMain->mapAddressBook) {
1398 if (pwalletMain->HaveKey(entry.first)) // This address belongs to me
1399 mapAccountBalances[entry.second] = 0;
1402 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1404 const CWalletTx& wtx = (*it).second;
1405 int64 nGeneratedImmature, nGeneratedMature, nFee;
1406 string strSentAccount;
1407 list<pair<CBitcoinAddress, int64> > listReceived;
1408 list<pair<CBitcoinAddress, int64> > listSent;
1409 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1410 mapAccountBalances[strSentAccount] -= nFee;
1411 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1412 mapAccountBalances[strSentAccount] -= s.second;
1413 if (wtx.GetDepthInMainChain() >= nMinDepth)
1415 mapAccountBalances[""] += nGeneratedMature;
1416 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1417 if (pwalletMain->mapAddressBook.count(r.first))
1418 mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1420 mapAccountBalances[""] += r.second;
1424 list<CAccountingEntry> acentries;
1425 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1426 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1427 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1430 BOOST_FOREACH(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) {
1431 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1436 Value listsinceblock(const Array& params, bool fHelp)
1439 throw runtime_error(
1440 "listsinceblock [blockhash] [target-confirmations]\n"
1441 "Get all transactions in blocks since block [blockhash], or all transactions if omitted");
1443 CBlockIndex *pindex = NULL;
1444 int target_confirms = 1;
1446 if (params.size() > 0)
1448 uint256 blockId = 0;
1450 blockId.SetHex(params[0].get_str());
1451 pindex = CBlockLocator(blockId).GetBlockIndex();
1454 if (params.size() > 1)
1456 target_confirms = params[1].get_int();
1458 if (target_confirms < 1)
1459 throw JSONRPCError(-8, "Invalid parameter");
1462 int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1;
1466 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1468 CWalletTx tx = (*it).second;
1470 if (depth == -1 || tx.GetDepthInMainChain() < depth)
1471 ListTransactions(tx, "*", 0, true, transactions);
1476 if (target_confirms == 1)
1478 lastblock = hashBestChain;
1482 int target_height = pindexBest->nHeight + 1 - target_confirms;
1485 for (block = pindexBest;
1486 block && block->nHeight > target_height;
1487 block = block->pprev) { }
1489 lastblock = block ? block->GetBlockHash() : 0;
1493 ret.push_back(Pair("transactions", transactions));
1494 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1499 Value gettransaction(const Array& params, bool fHelp)
1501 if (fHelp || params.size() != 1)
1502 throw runtime_error(
1503 "gettransaction <txid>\n"
1504 "Get detailed information about <txid>");
1507 hash.SetHex(params[0].get_str());
1511 if (!pwalletMain->mapWallet.count(hash))
1512 throw JSONRPCError(-5, "Invalid or non-wallet transaction id");
1513 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1515 int64 nCredit = wtx.GetCredit();
1516 int64 nDebit = wtx.GetDebit();
1517 int64 nNet = nCredit - nDebit;
1518 int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
1520 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1522 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1524 WalletTxToJSON(pwalletMain->mapWallet[hash], entry);
1527 ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
1528 entry.push_back(Pair("details", details));
1534 Value backupwallet(const Array& params, bool fHelp)
1536 if (fHelp || params.size() != 1)
1537 throw runtime_error(
1538 "backupwallet <destination>\n"
1539 "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1541 string strDest = params[0].get_str();
1542 BackupWallet(*pwalletMain, strDest);
1548 Value keypoolrefill(const Array& params, bool fHelp)
1550 if (pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1551 throw runtime_error(
1553 "Fills the keypool, requires wallet passphrase to be set.");
1554 if (!pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1555 throw runtime_error(
1557 "Fills the keypool.");
1559 if (pwalletMain->IsLocked())
1560 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
1562 pwalletMain->TopUpKeyPool();
1564 if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100))
1565 throw JSONRPCError(-4, "Error refreshing keypool.");
1571 void ThreadTopUpKeyPool(void* parg)
1573 pwalletMain->TopUpKeyPool();
1576 void ThreadCleanWalletPassphrase(void* parg)
1578 int64 nMyWakeTime = GetTimeMillis() + *((int64*)parg) * 1000;
1580 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1582 if (nWalletUnlockTime == 0)
1584 nWalletUnlockTime = nMyWakeTime;
1588 if (nWalletUnlockTime==0)
1590 int64 nToSleep = nWalletUnlockTime - GetTimeMillis();
1594 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1596 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1600 if (nWalletUnlockTime)
1602 nWalletUnlockTime = 0;
1603 pwalletMain->Lock();
1608 if (nWalletUnlockTime < nMyWakeTime)
1609 nWalletUnlockTime = nMyWakeTime;
1612 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1614 delete (int64*)parg;
1617 Value walletpassphrase(const Array& params, bool fHelp)
1619 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 3))
1620 throw runtime_error(
1621 "walletpassphrase <passphrase> <timeout> [mintonly]\n"
1622 "Stores the wallet decryption key in memory for <timeout> seconds.\n"
1623 "mintonly is optional true/false allowing only block minting.");
1626 if (!pwalletMain->IsCrypted())
1627 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1629 if (!pwalletMain->IsLocked())
1630 throw JSONRPCError(-17, "Error: Wallet is already unlocked, use walletlock first if need to change unlock settings.");
1632 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1633 SecureString strWalletPass;
1634 strWalletPass.reserve(100);
1635 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1636 // Alternately, find a way to make params[0] mlock()'d to begin with.
1637 strWalletPass = params[0].get_str().c_str();
1639 if (strWalletPass.length() > 0)
1641 if (!pwalletMain->Unlock(strWalletPass))
1642 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1645 throw runtime_error(
1646 "walletpassphrase <passphrase> <timeout>\n"
1647 "Stores the wallet decryption key in memory for <timeout> seconds.");
1649 CreateThread(ThreadTopUpKeyPool, NULL);
1650 int64* pnSleepTime = new int64(params[1].get_int64());
1651 CreateThread(ThreadCleanWalletPassphrase, pnSleepTime);
1653 // ppcoin: if user OS account compromised prevent trivial sendmoney commands
1654 if (params.size() > 2)
1655 fWalletUnlockMintOnly = params[2].get_bool();
1657 fWalletUnlockMintOnly = false;
1663 Value walletpassphrasechange(const Array& params, bool fHelp)
1665 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1666 throw runtime_error(
1667 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1668 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1671 if (!pwalletMain->IsCrypted())
1672 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1674 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1675 // Alternately, find a way to make params[0] mlock()'d to begin with.
1676 SecureString strOldWalletPass;
1677 strOldWalletPass.reserve(100);
1678 strOldWalletPass = params[0].get_str().c_str();
1680 SecureString strNewWalletPass;
1681 strNewWalletPass.reserve(100);
1682 strNewWalletPass = params[1].get_str().c_str();
1684 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1685 throw runtime_error(
1686 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1687 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1689 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1690 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1696 Value walletlock(const Array& params, bool fHelp)
1698 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1699 throw runtime_error(
1701 "Removes the wallet encryption key from memory, locking the wallet.\n"
1702 "After calling this method, you will need to call walletpassphrase again\n"
1703 "before being able to call any methods which require the wallet to be unlocked.");
1706 if (!pwalletMain->IsCrypted())
1707 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called.");
1710 LOCK(cs_nWalletUnlockTime);
1711 pwalletMain->Lock();
1712 nWalletUnlockTime = 0;
1719 Value encryptwallet(const Array& params, bool fHelp)
1721 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1722 throw runtime_error(
1723 "encryptwallet <passphrase>\n"
1724 "Encrypts the wallet with <passphrase>.");
1727 if (pwalletMain->IsCrypted())
1728 throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
1730 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1731 // Alternately, find a way to make params[0] mlock()'d to begin with.
1732 SecureString strWalletPass;
1733 strWalletPass.reserve(100);
1734 strWalletPass = params[0].get_str().c_str();
1736 if (strWalletPass.length() < 1)
1737 throw runtime_error(
1738 "encryptwallet <passphrase>\n"
1739 "Encrypts the wallet with <passphrase>.");
1741 if (!pwalletMain->EncryptWallet(strWalletPass))
1742 throw JSONRPCError(-16, "Error: Failed to encrypt the wallet.");
1744 // BDB seems to have a bad habit of writing old data into
1745 // slack space in .dat files; that is bad if the old data is
1746 // unencrypted private keys. So:
1748 return "wallet encrypted; novacoin server stopping, restart to run with encrypted wallet";
1752 Value validateaddress(const Array& params, bool fHelp)
1754 if (fHelp || params.size() != 1)
1755 throw runtime_error(
1756 "validateaddress <novacoinaddress>\n"
1757 "Return information about <novacoinaddress>.");
1759 CBitcoinAddress address(params[0].get_str());
1760 bool isValid = address.IsValid();
1763 ret.push_back(Pair("isvalid", isValid));
1766 // Call Hash160ToAddress() so we always return current ADDRESSVERSION
1767 // version of the address:
1768 string currentAddress = address.ToString();
1769 ret.push_back(Pair("address", currentAddress));
1770 if (pwalletMain->HaveKey(address))
1772 ret.push_back(Pair("ismine", true));
1773 std::vector<unsigned char> vchPubKey;
1774 pwalletMain->GetPubKey(address, vchPubKey);
1775 ret.push_back(Pair("pubkey", HexStr(vchPubKey)));
1777 key.SetPubKey(vchPubKey);
1778 ret.push_back(Pair("iscompressed", key.IsCompressed()));
1780 else if (pwalletMain->HaveCScript(address.GetHash160()))
1782 ret.push_back(Pair("isscript", true));
1784 pwalletMain->GetCScript(address.GetHash160(), subscript);
1785 ret.push_back(Pair("ismine", ::IsMine(*pwalletMain, subscript)));
1786 std::vector<CBitcoinAddress> addresses;
1787 txnouttype whichType;
1789 ExtractAddresses(subscript, whichType, addresses, nRequired);
1790 ret.push_back(Pair("script", GetTxnOutputType(whichType)));
1792 BOOST_FOREACH(const CBitcoinAddress& addr, addresses)
1793 a.push_back(addr.ToString());
1794 ret.push_back(Pair("addresses", a));
1795 if (whichType == TX_MULTISIG)
1796 ret.push_back(Pair("sigsrequired", nRequired));
1799 ret.push_back(Pair("ismine", false));
1800 if (pwalletMain->mapAddressBook.count(address))
1801 ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
1806 Value getwork(const Array& params, bool fHelp)
1808 if (fHelp || params.size() > 1)
1809 throw runtime_error(
1811 "If [data] is not specified, returns formatted hash data to work on:\n"
1812 " \"midstate\" : precomputed hash state after hashing the first half of the data (DEPRECATED)\n" // deprecated
1813 " \"data\" : block data\n"
1814 " \"hash1\" : formatted hash buffer for second hash (DEPRECATED)\n" // deprecated
1815 " \"target\" : little endian hash target\n"
1816 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1819 throw JSONRPCError(-9, "NovaCoin is not connected!");
1821 if (IsInitialBlockDownload())
1822 throw JSONRPCError(-10, "NovaCoin is downloading blocks...");
1824 typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
1825 static mapNewBlock_t mapNewBlock;
1826 static vector<CBlock*> vNewBlock;
1827 static CReserveKey reservekey(pwalletMain);
1829 if (params.size() == 0)
1832 static unsigned int nTransactionsUpdatedLast;
1833 static CBlockIndex* pindexPrev;
1834 static int64 nStart;
1835 static CBlock* pblock;
1836 if (pindexPrev != pindexBest ||
1837 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
1839 if (pindexPrev != pindexBest)
1841 // Deallocate old blocks since they're obsolete now
1842 mapNewBlock.clear();
1843 BOOST_FOREACH(CBlock* pblock, vNewBlock)
1847 nTransactionsUpdatedLast = nTransactionsUpdated;
1848 pindexPrev = pindexBest;
1852 pblock = CreateNewBlock(pwalletMain);
1854 throw JSONRPCError(-7, "Out of memory");
1855 vNewBlock.push_back(pblock);
1859 pblock->UpdateTime(pindexPrev);
1862 // Update nExtraNonce
1863 static unsigned int nExtraNonce = 0;
1864 IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
1867 mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
1869 // Prebuild hash buffers
1873 FormatHashBuffers(pblock, pmidstate, pdata, phash1);
1875 uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
1878 result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate)))); // deprecated
1879 result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata))));
1880 result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1)))); // deprecated
1881 result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
1887 vector<unsigned char> vchData = ParseHex(params[0].get_str());
1888 if (vchData.size() != 128)
1889 throw JSONRPCError(-8, "Invalid parameter");
1890 CBlock* pdata = (CBlock*)&vchData[0];
1893 for (int i = 0; i < 128/4; i++)
1894 ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]);
1897 if (!mapNewBlock.count(pdata->hashMerkleRoot))
1899 CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
1901 pblock->nTime = pdata->nTime;
1902 pblock->nNonce = pdata->nNonce;
1903 pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
1904 pblock->hashMerkleRoot = pblock->BuildMerkleTree();
1905 if (!pblock->SignBlock(*pwalletMain))
1906 throw JSONRPCError(-100, "Unable to sign block, wallet locked?");
1908 return CheckWork(pblock, *pwalletMain, reservekey);
1913 Value getmemorypool(const Array& params, bool fHelp)
1915 if (fHelp || params.size() > 1)
1916 throw runtime_error(
1917 "getmemorypool [data]\n"
1918 "If [data] is not specified, returns data needed to construct a block to work on:\n"
1919 " \"version\" : block version\n"
1920 " \"previousblockhash\" : hash of current highest block\n"
1921 " \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
1922 " \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
1923 " \"coinbaseflags\" : data that should be included in coinbase so support for new features can be judged\n"
1924 " \"time\" : timestamp appropriate for next block\n"
1925 " \"mintime\" : minimum timestamp appropriate for next block\n"
1926 " \"curtime\" : current timestamp\n"
1927 " \"bits\" : compressed target of next block\n"
1928 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1930 if (params.size() == 0)
1933 throw JSONRPCError(-9, "NovaCoin is not connected!");
1935 if (IsInitialBlockDownload())
1936 throw JSONRPCError(-10, "NovaCoin is downloading blocks...");
1938 static CReserveKey reservekey(pwalletMain);
1941 static unsigned int nTransactionsUpdatedLast;
1942 static CBlockIndex* pindexPrev;
1943 static int64 nStart;
1944 static CBlock* pblock;
1945 if (pindexPrev != pindexBest ||
1946 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5))
1948 nTransactionsUpdatedLast = nTransactionsUpdated;
1949 pindexPrev = pindexBest;
1955 pblock = CreateNewBlock(pwalletMain);
1957 throw JSONRPCError(-7, "Out of memory");
1961 pblock->UpdateTime(pindexPrev);
1965 BOOST_FOREACH(CTransaction tx, pblock->vtx) {
1966 if(tx.IsCoinBase() || tx.IsCoinStake())
1969 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
1972 transactions.push_back(HexStr(ssTx.begin(), ssTx.end()));
1976 result.push_back(Pair("version", pblock->nVersion));
1977 result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
1978 result.push_back(Pair("transactions", transactions));
1979 result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
1980 result.push_back(Pair("coinbaseflags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end())));
1981 result.push_back(Pair("time", (int64_t)pblock->nTime));
1982 result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1));
1983 result.push_back(Pair("curtime", (int64_t)GetAdjustedTime()));
1984 result.push_back(Pair("bits", HexBits(pblock->nBits)));
1991 CDataStream ssBlock(ParseHex(params[0].get_str()), SER_NETWORK, PROTOCOL_VERSION);
1995 return ProcessBlock(NULL, &pblock);
1999 Value getnewpubkey(const Array& params, bool fHelp)
2001 if (fHelp || params.size() > 1)
2002 throw runtime_error(
2003 "getnewpubkey [account]\n"
2004 "Returns new public key for coinbase generation.");
2006 // Parse the account first so we don't generate a key if there's an error
2008 if (params.size() > 0)
2009 strAccount = AccountFromValue(params[0]);
2011 if (!pwalletMain->IsLocked())
2012 pwalletMain->TopUpKeyPool();
2014 // Generate a new key that is added to wallet
2015 std::vector<unsigned char> newKey = pwalletMain->GenerateNewKey(false);
2018 throw JSONRPCError(-12, "Error: Unable to create key");
2020 CBitcoinAddress address(newKey);
2021 pwalletMain->SetAddressBookName(address, strAccount);
2023 return HexStr(newKey.begin(), newKey.end());
2027 Value getblockhash(const Array& params, bool fHelp)
2029 if (fHelp || params.size() != 1)
2030 throw runtime_error(
2031 "getblockhash <index>\n"
2032 "Returns hash of block in best-block-chain at <index>.");
2034 int nHeight = params[0].get_int();
2035 if (nHeight < 0 || nHeight > nBestHeight)
2036 throw runtime_error("Block number out of range.");
2039 CBlockIndex* pblockindex = mapBlockIndex[hashBestChain];
2040 while (pblockindex->nHeight > nHeight)
2041 pblockindex = pblockindex->pprev;
2042 return pblockindex->phashBlock->GetHex();
2045 Value getblock(const Array& params, bool fHelp)
2047 if (fHelp || params.size() < 1 || params.size() > 2)
2048 throw runtime_error(
2049 "getblock <hash> [txinfo]\n"
2050 "txinfo optional to print more detailed tx info\n"
2051 "Returns details of a block with given block-hash.");
2053 std::string strHash = params[0].get_str();
2054 uint256 hash(strHash);
2056 if (mapBlockIndex.count(hash) == 0)
2057 throw JSONRPCError(-5, "Block not found");
2060 CBlockIndex* pblockindex = mapBlockIndex[hash];
2061 block.ReadFromDisk(pblockindex, true);
2063 return blockToJSON(block, pblockindex, params.size() > 1 ? params[1].get_bool() : false);
2067 // ppcoin: get information of sync-checkpoint
2068 Value getcheckpoint(const Array& params, bool fHelp)
2070 if (fHelp || params.size() != 0)
2071 throw runtime_error(
2073 "Show info of synchronized checkpoint.\n");
2076 CBlockIndex* pindexCheckpoint;
2078 result.push_back(Pair("synccheckpoint", Checkpoints::hashSyncCheckpoint.ToString().c_str()));
2079 pindexCheckpoint = mapBlockIndex[Checkpoints::hashSyncCheckpoint];
2080 result.push_back(Pair("height", pindexCheckpoint->nHeight));
2081 result.push_back(Pair("timestamp", DateTimeStrFormat(pindexCheckpoint->GetBlockTime()).c_str()));
2082 if (mapArgs.count("-checkpointkey"))
2083 result.push_back(Pair("checkpointmaster", true));
2089 // ppcoin: reserve balance from being staked for network protection
2090 Value reservebalance(const Array& params, bool fHelp)
2092 if (fHelp || params.size() > 2)
2093 throw runtime_error(
2094 "reservebalance [<reserve> [amount]]\n"
2095 "<reserve> is true or false to turn balance reserve on or off.\n"
2096 "<amount> is a real and rounded to cent.\n"
2097 "Set reserve amount not participating in network protection.\n"
2098 "If no parameters provided current setting is printed.\n");
2100 if (params.size() > 0)
2102 bool fReserve = params[0].get_bool();
2105 if (params.size() == 1)
2106 throw runtime_error("must provide amount to reserve balance.\n");
2107 int64 nAmount = AmountFromValue(params[1]);
2108 nAmount = (nAmount / CENT) * CENT; // round to cent
2110 throw runtime_error("amount cannot be negative.\n");
2111 mapArgs["-reservebalance"] = FormatMoney(nAmount).c_str();
2115 if (params.size() > 1)
2116 throw runtime_error("cannot specify amount to turn off reserve.\n");
2117 mapArgs["-reservebalance"] = "0";
2122 int64 nReserveBalance = 0;
2123 if (mapArgs.count("-reservebalance") && !ParseMoney(mapArgs["-reservebalance"], nReserveBalance))
2124 throw runtime_error("invalid reserve balance amount\n");
2125 result.push_back(Pair("reserve", (nReserveBalance > 0)));
2126 result.push_back(Pair("amount", ValueFromAmount(nReserveBalance)));
2131 // ppcoin: check wallet integrity
2132 Value checkwallet(const Array& params, bool fHelp)
2134 if (fHelp || params.size() > 0)
2135 throw runtime_error(
2137 "Check wallet for integrity.\n");
2140 int64 nBalanceInQuestion;
2141 pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion, true);
2143 if (nMismatchSpent == 0)
2144 result.push_back(Pair("wallet check passed", true));
2147 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
2148 result.push_back(Pair("amount in question", ValueFromAmount(nBalanceInQuestion)));
2154 // ppcoin: repair wallet
2155 Value repairwallet(const Array& params, bool fHelp)
2157 if (fHelp || params.size() > 0)
2158 throw runtime_error(
2160 "Repair wallet if checkwallet reports any problem.\n");
2163 int64 nBalanceInQuestion;
2164 pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion);
2166 if (nMismatchSpent == 0)
2167 result.push_back(Pair("wallet check passed", true));
2170 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
2171 result.push_back(Pair("amount affected by repair", ValueFromAmount(nBalanceInQuestion)));
2176 // ppcoin: make a public-private key pair
2177 Value makekeypair(const Array& params, bool fHelp)
2179 if (fHelp || params.size() > 1)
2180 throw runtime_error(
2181 "makekeypair [prefix]\n"
2182 "Make a public/private key pair.\n"
2183 "[prefix] is optional preferred prefix for the public key.\n");
2185 string strPrefix = "";
2186 if (params.size() > 0)
2187 strPrefix = params[0].get_str();
2193 key.MakeNewKey(false);
2195 } while (nCount < 10000 && strPrefix != HexStr(key.GetPubKey()).substr(0, strPrefix.size()));
2197 if (strPrefix != HexStr(key.GetPubKey()).substr(0, strPrefix.size()))
2200 CPrivKey vchPrivKey = key.GetPrivKey();
2202 result.push_back(Pair("PrivateKey", HexStr<CPrivKey::iterator>(vchPrivKey.begin(), vchPrivKey.end())));
2203 result.push_back(Pair("PublicKey", HexStr(key.GetPubKey())));
2207 extern CCriticalSection cs_mapAlerts;
2208 extern map<uint256, CAlert> mapAlerts;
2210 // ppcoin: send alert.
2211 // There is a known deadlock situation with ThreadMessageHandler
2212 // ThreadMessageHandler: holds cs_vSend and acquiring cs_main in SendMessages()
2213 // ThreadRPCServer: holds cs_main and acquiring cs_vSend in alert.RelayTo()/PushMessage()/BeginMessage()
2214 Value sendalert(const Array& params, bool fHelp)
2216 if (fHelp || params.size() < 6)
2217 throw runtime_error(
2218 "sendalert <message> <privatekey> <minver> <maxver> <priority> <id> [cancelupto]\n"
2219 "<message> is the alert text message\n"
2220 "<privatekey> is hex string of alert master private key\n"
2221 "<minver> is the minimum applicable internal client version\n"
2222 "<maxver> is the maximum applicable internal client version\n"
2223 "<priority> is integer priority number\n"
2224 "<id> is the alert id\n"
2225 "[cancelupto] cancels all alert id's up to this number\n"
2226 "Returns true or false.");
2231 alert.strStatusBar = params[0].get_str();
2232 alert.nMinVer = params[2].get_int();
2233 alert.nMaxVer = params[3].get_int();
2234 alert.nPriority = params[4].get_int();
2235 alert.nID = params[5].get_int();
2236 if (params.size() > 6)
2237 alert.nCancel = params[6].get_int();
2238 alert.nVersion = PROTOCOL_VERSION;
2239 alert.nRelayUntil = GetAdjustedTime() + 365*24*60*60;
2240 alert.nExpiration = GetAdjustedTime() + 365*24*60*60;
2242 CDataStream sMsg(SER_NETWORK, PROTOCOL_VERSION);
2243 sMsg << (CUnsignedAlert)alert;
2244 alert.vchMsg = vector<unsigned char>(sMsg.begin(), sMsg.end());
2246 vector<unsigned char> vchPrivKey = ParseHex(params[1].get_str());
2247 key.SetPrivKey(CPrivKey(vchPrivKey.begin(), vchPrivKey.end())); // if key is not correct openssl may crash
2248 if (!key.Sign(Hash(alert.vchMsg.begin(), alert.vchMsg.end()), alert.vchSig))
2249 throw runtime_error(
2250 "Unable to sign alert, check private key?\n");
2251 if(!alert.ProcessAlert())
2252 throw runtime_error(
2253 "Failed to process alert.\n");
2257 BOOST_FOREACH(CNode* pnode, vNodes)
2258 alert.RelayTo(pnode);
2262 result.push_back(Pair("strStatusBar", alert.strStatusBar));
2263 result.push_back(Pair("nVersion", alert.nVersion));
2264 result.push_back(Pair("nMinVer", alert.nMinVer));
2265 result.push_back(Pair("nMaxVer", alert.nMaxVer));
2266 result.push_back(Pair("nPriority", alert.nPriority));
2267 result.push_back(Pair("nID", alert.nID));
2268 if (alert.nCancel > 0)
2269 result.push_back(Pair("nCancel", alert.nCancel));
2280 static const CRPCCommand vRPCCommands[] =
2281 { // name function safe mode?
2282 // ------------------------ ----------------------- ----------
2283 { "help", &help, true },
2284 { "stop", &stop, true },
2285 { "getblockcount", &getblockcount, true },
2286 { "getblocknumber", &getblocknumber, true },
2287 { "getconnectioncount", &getconnectioncount, true },
2288 { "getdifficulty", &getdifficulty, true },
2289 { "getgenerate", &getgenerate, true },
2290 { "setgenerate", &setgenerate, true },
2291 { "gethashespersec", &gethashespersec, true },
2292 { "getinfo", &getinfo, true },
2293 { "getmininginfo", &getmininginfo, true },
2294 { "getnewaddress", &getnewaddress, true },
2295 { "getnewpubkey", &getnewpubkey, true },
2296 { "getaccountaddress", &getaccountaddress, true },
2297 { "setaccount", &setaccount, true },
2298 { "getaccount", &getaccount, false },
2299 { "getaddressesbyaccount", &getaddressesbyaccount, true },
2300 { "sendtoaddress", &sendtoaddress, false },
2301 { "getreceivedbyaddress", &getreceivedbyaddress, false },
2302 { "getreceivedbyaccount", &getreceivedbyaccount, false },
2303 { "listreceivedbyaddress", &listreceivedbyaddress, false },
2304 { "listreceivedbyaccount", &listreceivedbyaccount, false },
2305 { "backupwallet", &backupwallet, true },
2306 { "keypoolrefill", &keypoolrefill, true },
2307 { "walletpassphrase", &walletpassphrase, true },
2308 { "walletpassphrasechange", &walletpassphrasechange, false },
2309 { "walletlock", &walletlock, true },
2310 { "encryptwallet", &encryptwallet, false },
2311 { "validateaddress", &validateaddress, true },
2312 { "getbalance", &getbalance, false },
2313 { "move", &movecmd, false },
2314 { "sendfrom", &sendfrom, false },
2315 { "sendmany", &sendmany, false },
2316 { "addmultisigaddress", &addmultisigaddress, false },
2317 { "getblock", &getblock, false },
2318 { "getblockhash", &getblockhash, false },
2319 { "gettransaction", &gettransaction, false },
2320 { "listtransactions", &listtransactions, false },
2321 { "signmessage", &signmessage, false },
2322 { "verifymessage", &verifymessage, false },
2323 { "getwork", &getwork, true },
2324 { "listaccounts", &listaccounts, false },
2325 { "settxfee", &settxfee, false },
2326 { "getmemorypool", &getmemorypool, true },
2327 { "listsinceblock", &listsinceblock, false },
2328 { "dumpprivkey", &dumpprivkey, false },
2329 { "importprivkey", &importprivkey, false },
2330 { "getcheckpoint", &getcheckpoint, true },
2331 { "reservebalance", &reservebalance, false},
2332 { "checkwallet", &checkwallet, false},
2333 { "repairwallet", &repairwallet, false},
2334 { "makekeypair", &makekeypair, false},
2335 { "sendalert", &sendalert, false},
2338 CRPCTable::CRPCTable()
2341 for (vcidx = 0; vcidx < (sizeof(vRPCCommands) / sizeof(vRPCCommands[0])); vcidx++)
2343 const CRPCCommand *pcmd;
2345 pcmd = &vRPCCommands[vcidx];
2346 mapCommands[pcmd->name] = pcmd;
2350 const CRPCCommand *CRPCTable::operator[](string name) const
2352 map<string, const CRPCCommand*>::const_iterator it = mapCommands.find(name);
2353 if (it == mapCommands.end())
2355 return (*it).second;
2361 // This ain't Apache. We're just using HTTP header for the length field
2362 // and to be compatible with other JSON-RPC implementations.
2365 string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
2368 s << "POST / HTTP/1.1\r\n"
2369 << "User-Agent: novacoin-json-rpc/" << FormatFullVersion() << "\r\n"
2370 << "Host: 127.0.0.1\r\n"
2371 << "Content-Type: application/json\r\n"
2372 << "Content-Length: " << strMsg.size() << "\r\n"
2373 << "Connection: close\r\n"
2374 << "Accept: application/json\r\n";
2375 BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
2376 s << item.first << ": " << item.second << "\r\n";
2377 s << "\r\n" << strMsg;
2382 string rfc1123Time()
2387 struct tm* now_gmt = gmtime(&now);
2388 string locale(setlocale(LC_TIME, NULL));
2389 setlocale(LC_TIME, "C"); // we want posix (aka "C") weekday/month strings
2390 strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt);
2391 setlocale(LC_TIME, locale.c_str());
2392 return string(buffer);
2395 static string HTTPReply(int nStatus, const string& strMsg)
2398 return strprintf("HTTP/1.0 401 Authorization Required\r\n"
2400 "Server: novacoin-json-rpc/%s\r\n"
2401 "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
2402 "Content-Type: text/html\r\n"
2403 "Content-Length: 296\r\n"
2405 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
2406 "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
2409 "<TITLE>Error</TITLE>\r\n"
2410 "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
2412 "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
2413 "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
2414 const char *cStatus;
2415 if (nStatus == 200) cStatus = "OK";
2416 else if (nStatus == 400) cStatus = "Bad Request";
2417 else if (nStatus == 403) cStatus = "Forbidden";
2418 else if (nStatus == 404) cStatus = "Not Found";
2419 else if (nStatus == 500) cStatus = "Internal Server Error";
2422 "HTTP/1.1 %d %s\r\n"
2424 "Connection: close\r\n"
2425 "Content-Length: %d\r\n"
2426 "Content-Type: application/json\r\n"
2427 "Server: novacoin-json-rpc/%s\r\n"
2432 rfc1123Time().c_str(),
2434 FormatFullVersion().c_str(),
2438 int ReadHTTPStatus(std::basic_istream<char>& stream)
2441 getline(stream, str);
2442 vector<string> vWords;
2443 boost::split(vWords, str, boost::is_any_of(" "));
2444 if (vWords.size() < 2)
2446 return atoi(vWords[1].c_str());
2449 int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
2455 std::getline(stream, str);
2456 if (str.empty() || str == "\r")
2458 string::size_type nColon = str.find(":");
2459 if (nColon != string::npos)
2461 string strHeader = str.substr(0, nColon);
2462 boost::trim(strHeader);
2463 boost::to_lower(strHeader);
2464 string strValue = str.substr(nColon+1);
2465 boost::trim(strValue);
2466 mapHeadersRet[strHeader] = strValue;
2467 if (strHeader == "content-length")
2468 nLen = atoi(strValue.c_str());
2474 int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
2476 mapHeadersRet.clear();
2480 int nStatus = ReadHTTPStatus(stream);
2483 int nLen = ReadHTTPHeader(stream, mapHeadersRet);
2484 if (nLen < 0 || nLen > (int)MAX_SIZE)
2490 vector<char> vch(nLen);
2491 stream.read(&vch[0], nLen);
2492 strMessageRet = string(vch.begin(), vch.end());
2498 bool HTTPAuthorized(map<string, string>& mapHeaders)
2500 string strAuth = mapHeaders["authorization"];
2501 if (strAuth.substr(0,6) != "Basic ")
2503 string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
2504 string strUserPass = DecodeBase64(strUserPass64);
2505 return strUserPass == strRPCUserColonPass;
2509 // JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
2510 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
2511 // unspecified (HTTP errors and contents of 'error').
2513 // 1.0 spec: http://json-rpc.org/wiki/specification
2514 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
2515 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
2518 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
2521 request.push_back(Pair("method", strMethod));
2522 request.push_back(Pair("params", params));
2523 request.push_back(Pair("id", id));
2524 return write_string(Value(request), false) + "\n";
2527 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
2530 if (error.type() != null_type)
2531 reply.push_back(Pair("result", Value::null));
2533 reply.push_back(Pair("result", result));
2534 reply.push_back(Pair("error", error));
2535 reply.push_back(Pair("id", id));
2536 return write_string(Value(reply), false) + "\n";
2539 void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
2541 // Send error reply from json-rpc error object
2543 int code = find_value(objError, "code").get_int();
2544 if (code == -32600) nStatus = 400;
2545 else if (code == -32601) nStatus = 404;
2546 string strReply = JSONRPCReply(Value::null, objError, id);
2547 stream << HTTPReply(nStatus, strReply) << std::flush;
2550 bool ClientAllowed(const string& strAddress)
2552 if (strAddress == asio::ip::address_v4::loopback().to_string())
2554 const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
2555 BOOST_FOREACH(string strAllow, vAllow)
2556 if (WildcardMatch(strAddress, strAllow))
2562 // IOStream device that speaks SSL but can also speak non-SSL
2564 class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
2566 SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
2568 fUseSSL = fUseSSLIn;
2569 fNeedHandshake = fUseSSLIn;
2572 void handshake(ssl::stream_base::handshake_type role)
2574 if (!fNeedHandshake) return;
2575 fNeedHandshake = false;
2576 stream.handshake(role);
2578 std::streamsize read(char* s, std::streamsize n)
2580 handshake(ssl::stream_base::server); // HTTPS servers read first
2581 if (fUseSSL) return stream.read_some(asio::buffer(s, n));
2582 return stream.next_layer().read_some(asio::buffer(s, n));
2584 std::streamsize write(const char* s, std::streamsize n)
2586 handshake(ssl::stream_base::client); // HTTPS clients write first
2587 if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
2588 return asio::write(stream.next_layer(), asio::buffer(s, n));
2590 bool connect(const std::string& server, const std::string& port)
2592 ip::tcp::resolver resolver(stream.get_io_service());
2593 ip::tcp::resolver::query query(server.c_str(), port.c_str());
2594 ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
2595 ip::tcp::resolver::iterator end;
2596 boost::system::error_code error = asio::error::host_not_found;
2597 while (error && endpoint_iterator != end)
2599 stream.lowest_layer().close();
2600 stream.lowest_layer().connect(*endpoint_iterator++, error);
2608 bool fNeedHandshake;
2613 void ThreadRPCServer(void* parg)
2615 IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
2618 vnThreadsRunning[THREAD_RPCSERVER]++;
2619 ThreadRPCServer2(parg);
2620 vnThreadsRunning[THREAD_RPCSERVER]--;
2622 catch (std::exception& e) {
2623 vnThreadsRunning[THREAD_RPCSERVER]--;
2624 PrintException(&e, "ThreadRPCServer()");
2626 vnThreadsRunning[THREAD_RPCSERVER]--;
2627 PrintException(NULL, "ThreadRPCServer()");
2629 printf("ThreadRPCServer exiting\n");
2632 void ThreadRPCServer2(void* parg)
2634 printf("ThreadRPCServer started\n");
2636 strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
2637 if (mapArgs["-rpcpassword"] == "")
2639 unsigned char rand_pwd[32];
2640 RAND_bytes(rand_pwd, 32);
2641 string strWhatAmI = "To use novacoind";
2642 if (mapArgs.count("-server"))
2643 strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
2644 else if (mapArgs.count("-daemon"))
2645 strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
2646 ThreadSafeMessageBox(strprintf(
2647 _("%s, you must set a rpcpassword in the configuration file:\n %s\n"
2648 "It is recommended you use the following random password:\n"
2649 "rpcuser=bitcoinrpc\n"
2651 "(you do not need to remember this password)\n"
2652 "If the file does not exist, create it with owner-readable-only file permissions.\n"),
2654 GetConfigFile().string().c_str(),
2655 EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str()),
2656 _("Error"), wxOK | wxMODAL);
2661 bool fUseSSL = GetBoolArg("-rpcssl");
2662 asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
2664 asio::io_service io_service;
2665 ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", RPC_PORT));
2666 ip::tcp::acceptor acceptor(io_service);
2669 acceptor.open(endpoint.protocol());
2670 acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
2671 acceptor.bind(endpoint);
2672 acceptor.listen(socket_base::max_connections);
2674 catch(boost::system::system_error &e)
2676 ThreadSafeMessageBox(strprintf(_("An error occured while setting up the RPC port %i for listening: %s"), endpoint.port(), e.what()),
2677 _("Error"), wxOK | wxMODAL);
2682 ssl::context context(io_service, ssl::context::sslv23);
2685 context.set_options(ssl::context::no_sslv2);
2687 filesystem::path pathCertFile(GetArg("-rpcsslcertificatechainfile", "server.cert"));
2688 if (!pathCertFile.is_complete()) pathCertFile = filesystem::path(GetDataDir()) / pathCertFile;
2689 if (filesystem::exists(pathCertFile)) context.use_certificate_chain_file(pathCertFile.string());
2690 else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", pathCertFile.string().c_str());
2692 filesystem::path pathPKFile(GetArg("-rpcsslprivatekeyfile", "server.pem"));
2693 if (!pathPKFile.is_complete()) pathPKFile = filesystem::path(GetDataDir()) / pathPKFile;
2694 if (filesystem::exists(pathPKFile)) context.use_private_key_file(pathPKFile.string(), ssl::context::pem);
2695 else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pathPKFile.string().c_str());
2697 string strCiphers = GetArg("-rpcsslciphers", "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
2698 SSL_CTX_set_cipher_list(context.impl(), strCiphers.c_str());
2703 // Accept connection
2704 SSLStream sslStream(io_service, context);
2705 SSLIOStreamDevice d(sslStream, fUseSSL);
2706 iostreams::stream<SSLIOStreamDevice> stream(d);
2708 ip::tcp::endpoint peer;
2709 vnThreadsRunning[THREAD_RPCSERVER]--;
2710 acceptor.accept(sslStream.lowest_layer(), peer);
2711 vnThreadsRunning[4]++;
2715 // Restrict callers by IP
2716 if (!ClientAllowed(peer.address().to_string()))
2718 // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
2720 stream << HTTPReply(403, "") << std::flush;
2724 map<string, string> mapHeaders;
2727 boost::thread api_caller(ReadHTTP, boost::ref(stream), boost::ref(mapHeaders), boost::ref(strRequest));
2728 if (!api_caller.timed_join(boost::posix_time::seconds(GetArg("-rpctimeout", 30))))
2731 printf("ThreadRPCServer ReadHTTP timeout\n");
2735 // Check authorization
2736 if (mapHeaders.count("authorization") == 0)
2738 stream << HTTPReply(401, "") << std::flush;
2741 if (!HTTPAuthorized(mapHeaders))
2743 printf("ThreadRPCServer incorrect password attempt from %s\n",peer.address().to_string().c_str());
2744 /* Deter brute-forcing short passwords.
2745 If this results in a DOS the user really
2746 shouldn't have their RPC port exposed.*/
2747 if (mapArgs["-rpcpassword"].size() < 20)
2750 stream << HTTPReply(401, "") << std::flush;
2754 Value id = Value::null;
2759 if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
2760 throw JSONRPCError(-32700, "Parse error");
2761 const Object& request = valRequest.get_obj();
2763 // Parse id now so errors from here on will have the id
2764 id = find_value(request, "id");
2767 Value valMethod = find_value(request, "method");
2768 if (valMethod.type() == null_type)
2769 throw JSONRPCError(-32600, "Missing method");
2770 if (valMethod.type() != str_type)
2771 throw JSONRPCError(-32600, "Method must be a string");
2772 string strMethod = valMethod.get_str();
2773 if (strMethod != "getwork" && strMethod != "getmemorypool")
2774 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
2777 Value valParams = find_value(request, "params");
2779 if (valParams.type() == array_type)
2780 params = valParams.get_array();
2781 else if (valParams.type() == null_type)
2784 throw JSONRPCError(-32600, "Params must be an array");
2787 const CRPCCommand *pcmd = tableRPC[strMethod];
2789 throw JSONRPCError(-32601, "Method not found");
2791 // Observe safe mode
2792 string strWarning = GetWarnings("rpc");
2793 if (strWarning != "" && !GetBoolArg("-disablesafemode") &&
2795 throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
2802 LOCK2(cs_main, pwalletMain->cs_wallet);
2803 result = pcmd->actor(params, false);
2807 string strReply = JSONRPCReply(result, Value::null, id);
2808 stream << HTTPReply(200, strReply) << std::flush;
2810 catch (std::exception& e)
2812 ErrorReply(stream, JSONRPCError(-1, e.what()), id);
2815 catch (Object& objError)
2817 ErrorReply(stream, objError, id);
2819 catch (std::exception& e)
2821 ErrorReply(stream, JSONRPCError(-32700, e.what()), id);
2829 Object CallRPC(const string& strMethod, const Array& params)
2831 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2832 throw runtime_error(strprintf(
2833 _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
2834 "If the file does not exist, create it with owner-readable-only file permissions."),
2835 GetConfigFile().string().c_str()));
2837 // Connect to localhost
2838 bool fUseSSL = GetBoolArg("-rpcssl");
2839 asio::io_service io_service;
2840 ssl::context context(io_service, ssl::context::sslv23);
2841 context.set_options(ssl::context::no_sslv2);
2842 SSLStream sslStream(io_service, context);
2843 SSLIOStreamDevice d(sslStream, fUseSSL);
2844 iostreams::stream<SSLIOStreamDevice> stream(d);
2845 if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", CBigNum(RPC_PORT).ToString().c_str())))
2846 throw runtime_error("couldn't connect to server");
2848 // HTTP basic authentication
2849 string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
2850 map<string, string> mapRequestHeaders;
2851 mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
2854 string strRequest = JSONRPCRequest(strMethod, params, 1);
2855 string strPost = HTTPPost(strRequest, mapRequestHeaders);
2856 stream << strPost << std::flush;
2859 map<string, string> mapHeaders;
2861 int nStatus = ReadHTTP(stream, mapHeaders, strReply);
2863 throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
2864 else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
2865 throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
2866 else if (strReply.empty())
2867 throw runtime_error("no response from server");
2871 if (!read_string(strReply, valReply))
2872 throw runtime_error("couldn't parse reply from server");
2873 const Object& reply = valReply.get_obj();
2875 throw runtime_error("expected reply to have result, error and id properties");
2883 template<typename T>
2884 void ConvertTo(Value& value)
2886 if (value.type() == str_type)
2888 // reinterpret string as unquoted json value
2890 if (!read_string(value.get_str(), value2))
2891 throw runtime_error("type mismatch");
2892 value = value2.get_value<T>();
2896 value = value.get_value<T>();
2900 int CommandLineRPC(int argc, char *argv[])
2907 while (argc > 1 && IsSwitchChar(argv[1][0]))
2915 throw runtime_error("too few parameters");
2916 string strMethod = argv[1];
2918 // Parameters default to strings
2920 for (int i = 2; i < argc; i++)
2921 params.push_back(argv[i]);
2922 int n = params.size();
2925 // Special case non-string parameter types
2927 if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
2928 if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2929 if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
2930 if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]);
2931 if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2932 if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2933 if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2934 if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
2935 if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2936 if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
2937 if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2938 if (strMethod == "getblockhash" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2939 if (strMethod == "getblock" && n > 1) ConvertTo<bool>(params[1]);
2940 if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]);
2941 if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2942 if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]);
2943 if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2944 if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2945 if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2946 if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2947 if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2948 if (strMethod == "walletpassphrase" && n > 2) ConvertTo<bool>(params[2]);
2949 if (strMethod == "listsinceblock" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2950 if (strMethod == "sendalert" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2951 if (strMethod == "sendalert" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2952 if (strMethod == "sendalert" && n > 4) ConvertTo<boost::int64_t>(params[4]);
2953 if (strMethod == "sendalert" && n > 5) ConvertTo<boost::int64_t>(params[5]);
2954 if (strMethod == "sendalert" && n > 6) ConvertTo<boost::int64_t>(params[6]);
2955 if (strMethod == "sendmany" && n > 1)
2957 string s = params[1].get_str();
2959 if (!read_string(s, v) || v.type() != obj_type)
2960 throw runtime_error("type mismatch");
2961 params[1] = v.get_obj();
2963 if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2964 if (strMethod == "reservebalance" && n > 0) ConvertTo<bool>(params[0]);
2965 if (strMethod == "reservebalance" && n > 1) ConvertTo<double>(params[1]);
2966 if (strMethod == "addmultisigaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2967 if (strMethod == "addmultisigaddress" && n > 1)
2969 string s = params[1].get_str();
2971 if (!read_string(s, v) || v.type() != array_type)
2972 throw runtime_error("type mismatch "+s);
2973 params[1] = v.get_array();
2977 Object reply = CallRPC(strMethod, params);
2980 const Value& result = find_value(reply, "result");
2981 const Value& error = find_value(reply, "error");
2983 if (error.type() != null_type)
2986 strPrint = "error: " + write_string(error, false);
2987 int code = find_value(error.get_obj(), "code").get_int();
2993 if (result.type() == null_type)
2995 else if (result.type() == str_type)
2996 strPrint = result.get_str();
2998 strPrint = write_string(result, true);
3001 catch (std::exception& e)
3003 strPrint = string("error: ") + e.what();
3008 PrintException(NULL, "CommandLineRPC()");
3013 fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
3022 int main(int argc, char *argv[])
3025 // Turn off microsoft heap dump noise
3026 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
3027 _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
3029 setbuf(stdin, NULL);
3030 setbuf(stdout, NULL);
3031 setbuf(stderr, NULL);
3035 if (argc >= 2 && string(argv[1]) == "-server")
3037 printf("server ready\n");
3038 ThreadRPCServer(NULL);
3042 return CommandLineRPC(argc, argv);
3045 catch (std::exception& e) {
3046 PrintException(&e, "main()");
3048 PrintException(NULL, "main()");
3054 const CRPCTable tableRPC;