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 getblockhash(const Array& params, bool fHelp)
2001 if (fHelp || params.size() != 1)
2002 throw runtime_error(
2003 "getblockhash <index>\n"
2004 "Returns hash of block in best-block-chain at <index>.");
2006 int nHeight = params[0].get_int();
2007 if (nHeight < 0 || nHeight > nBestHeight)
2008 throw runtime_error("Block number out of range.");
2011 CBlockIndex* pblockindex = mapBlockIndex[hashBestChain];
2012 while (pblockindex->nHeight > nHeight)
2013 pblockindex = pblockindex->pprev;
2014 return pblockindex->phashBlock->GetHex();
2017 Value getblock(const Array& params, bool fHelp)
2019 if (fHelp || params.size() < 1 || params.size() > 2)
2020 throw runtime_error(
2021 "getblock <hash> [txinfo]\n"
2022 "txinfo optional to print more detailed tx info\n"
2023 "Returns details of a block with given block-hash.");
2025 std::string strHash = params[0].get_str();
2026 uint256 hash(strHash);
2028 if (mapBlockIndex.count(hash) == 0)
2029 throw JSONRPCError(-5, "Block not found");
2032 CBlockIndex* pblockindex = mapBlockIndex[hash];
2033 block.ReadFromDisk(pblockindex, true);
2035 return blockToJSON(block, pblockindex, params.size() > 1 ? params[1].get_bool() : false);
2039 // ppcoin: get information of sync-checkpoint
2040 Value getcheckpoint(const Array& params, bool fHelp)
2042 if (fHelp || params.size() != 0)
2043 throw runtime_error(
2045 "Show info of synchronized checkpoint.\n");
2048 CBlockIndex* pindexCheckpoint;
2050 result.push_back(Pair("synccheckpoint", Checkpoints::hashSyncCheckpoint.ToString().c_str()));
2051 pindexCheckpoint = mapBlockIndex[Checkpoints::hashSyncCheckpoint];
2052 result.push_back(Pair("height", pindexCheckpoint->nHeight));
2053 result.push_back(Pair("timestamp", DateTimeStrFormat(pindexCheckpoint->GetBlockTime()).c_str()));
2054 if (mapArgs.count("-checkpointkey"))
2055 result.push_back(Pair("checkpointmaster", true));
2061 // ppcoin: reserve balance from being staked for network protection
2062 Value reservebalance(const Array& params, bool fHelp)
2064 if (fHelp || params.size() > 2)
2065 throw runtime_error(
2066 "reservebalance [<reserve> [amount]]\n"
2067 "<reserve> is true or false to turn balance reserve on or off.\n"
2068 "<amount> is a real and rounded to cent.\n"
2069 "Set reserve amount not participating in network protection.\n"
2070 "If no parameters provided current setting is printed.\n");
2072 if (params.size() > 0)
2074 bool fReserve = params[0].get_bool();
2077 if (params.size() == 1)
2078 throw runtime_error("must provide amount to reserve balance.\n");
2079 int64 nAmount = AmountFromValue(params[1]);
2080 nAmount = (nAmount / CENT) * CENT; // round to cent
2082 throw runtime_error("amount cannot be negative.\n");
2083 mapArgs["-reservebalance"] = FormatMoney(nAmount).c_str();
2087 if (params.size() > 1)
2088 throw runtime_error("cannot specify amount to turn off reserve.\n");
2089 mapArgs["-reservebalance"] = "0";
2094 int64 nReserveBalance = 0;
2095 if (mapArgs.count("-reservebalance") && !ParseMoney(mapArgs["-reservebalance"], nReserveBalance))
2096 throw runtime_error("invalid reserve balance amount\n");
2097 result.push_back(Pair("reserve", (nReserveBalance > 0)));
2098 result.push_back(Pair("amount", ValueFromAmount(nReserveBalance)));
2103 // ppcoin: check wallet integrity
2104 Value checkwallet(const Array& params, bool fHelp)
2106 if (fHelp || params.size() > 0)
2107 throw runtime_error(
2109 "Check wallet for integrity.\n");
2112 int64 nBalanceInQuestion;
2113 pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion, true);
2115 if (nMismatchSpent == 0)
2116 result.push_back(Pair("wallet check passed", true));
2119 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
2120 result.push_back(Pair("amount in question", ValueFromAmount(nBalanceInQuestion)));
2126 // ppcoin: repair wallet
2127 Value repairwallet(const Array& params, bool fHelp)
2129 if (fHelp || params.size() > 0)
2130 throw runtime_error(
2132 "Repair wallet if checkwallet reports any problem.\n");
2135 int64 nBalanceInQuestion;
2136 pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion);
2138 if (nMismatchSpent == 0)
2139 result.push_back(Pair("wallet check passed", true));
2142 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
2143 result.push_back(Pair("amount affected by repair", ValueFromAmount(nBalanceInQuestion)));
2148 // ppcoin: make a public-private key pair
2149 Value makekeypair(const Array& params, bool fHelp)
2151 if (fHelp || params.size() > 1)
2152 throw runtime_error(
2153 "makekeypair [prefix]\n"
2154 "Make a public/private key pair.\n"
2155 "[prefix] is optional preferred prefix for the public key.\n");
2157 string strPrefix = "";
2158 if (params.size() > 0)
2159 strPrefix = params[0].get_str();
2165 key.MakeNewKey(false);
2167 } while (nCount < 10000 && strPrefix != HexStr(key.GetPubKey()).substr(0, strPrefix.size()));
2169 if (strPrefix != HexStr(key.GetPubKey()).substr(0, strPrefix.size()))
2172 CPrivKey vchPrivKey = key.GetPrivKey();
2174 result.push_back(Pair("PrivateKey", HexStr<CPrivKey::iterator>(vchPrivKey.begin(), vchPrivKey.end())));
2175 result.push_back(Pair("PublicKey", HexStr(key.GetPubKey())));
2179 extern CCriticalSection cs_mapAlerts;
2180 extern map<uint256, CAlert> mapAlerts;
2182 // ppcoin: send alert.
2183 // There is a known deadlock situation with ThreadMessageHandler
2184 // ThreadMessageHandler: holds cs_vSend and acquiring cs_main in SendMessages()
2185 // ThreadRPCServer: holds cs_main and acquiring cs_vSend in alert.RelayTo()/PushMessage()/BeginMessage()
2186 Value sendalert(const Array& params, bool fHelp)
2188 if (fHelp || params.size() < 6)
2189 throw runtime_error(
2190 "sendalert <message> <privatekey> <minver> <maxver> <priority> <id> [cancelupto]\n"
2191 "<message> is the alert text message\n"
2192 "<privatekey> is hex string of alert master private key\n"
2193 "<minver> is the minimum applicable internal client version\n"
2194 "<maxver> is the maximum applicable internal client version\n"
2195 "<priority> is integer priority number\n"
2196 "<id> is the alert id\n"
2197 "[cancelupto] cancels all alert id's up to this number\n"
2198 "Returns true or false.");
2203 alert.strStatusBar = params[0].get_str();
2204 alert.nMinVer = params[2].get_int();
2205 alert.nMaxVer = params[3].get_int();
2206 alert.nPriority = params[4].get_int();
2207 alert.nID = params[5].get_int();
2208 if (params.size() > 6)
2209 alert.nCancel = params[6].get_int();
2210 alert.nVersion = PROTOCOL_VERSION;
2211 alert.nRelayUntil = GetAdjustedTime() + 365*24*60*60;
2212 alert.nExpiration = GetAdjustedTime() + 365*24*60*60;
2214 CDataStream sMsg(SER_NETWORK, PROTOCOL_VERSION);
2215 sMsg << (CUnsignedAlert)alert;
2216 alert.vchMsg = vector<unsigned char>(sMsg.begin(), sMsg.end());
2218 vector<unsigned char> vchPrivKey = ParseHex(params[1].get_str());
2219 key.SetPrivKey(CPrivKey(vchPrivKey.begin(), vchPrivKey.end())); // if key is not correct openssl may crash
2220 if (!key.Sign(Hash(alert.vchMsg.begin(), alert.vchMsg.end()), alert.vchSig))
2221 throw runtime_error(
2222 "Unable to sign alert, check private key?\n");
2223 if(!alert.ProcessAlert())
2224 throw runtime_error(
2225 "Failed to process alert.\n");
2229 BOOST_FOREACH(CNode* pnode, vNodes)
2230 alert.RelayTo(pnode);
2234 result.push_back(Pair("strStatusBar", alert.strStatusBar));
2235 result.push_back(Pair("nVersion", alert.nVersion));
2236 result.push_back(Pair("nMinVer", alert.nMinVer));
2237 result.push_back(Pair("nMaxVer", alert.nMaxVer));
2238 result.push_back(Pair("nPriority", alert.nPriority));
2239 result.push_back(Pair("nID", alert.nID));
2240 if (alert.nCancel > 0)
2241 result.push_back(Pair("nCancel", alert.nCancel));
2252 static const CRPCCommand vRPCCommands[] =
2253 { // name function safe mode?
2254 // ------------------------ ----------------------- ----------
2255 { "help", &help, true },
2256 { "stop", &stop, true },
2257 { "getblockcount", &getblockcount, true },
2258 { "getblocknumber", &getblocknumber, true },
2259 { "getconnectioncount", &getconnectioncount, true },
2260 { "getdifficulty", &getdifficulty, true },
2261 { "getgenerate", &getgenerate, true },
2262 { "setgenerate", &setgenerate, true },
2263 { "gethashespersec", &gethashespersec, true },
2264 { "getinfo", &getinfo, true },
2265 { "getmininginfo", &getmininginfo, true },
2266 { "getnewaddress", &getnewaddress, true },
2267 { "getaccountaddress", &getaccountaddress, true },
2268 { "setaccount", &setaccount, true },
2269 { "getaccount", &getaccount, false },
2270 { "getaddressesbyaccount", &getaddressesbyaccount, true },
2271 { "sendtoaddress", &sendtoaddress, false },
2272 { "getreceivedbyaddress", &getreceivedbyaddress, false },
2273 { "getreceivedbyaccount", &getreceivedbyaccount, false },
2274 { "listreceivedbyaddress", &listreceivedbyaddress, false },
2275 { "listreceivedbyaccount", &listreceivedbyaccount, false },
2276 { "backupwallet", &backupwallet, true },
2277 { "keypoolrefill", &keypoolrefill, true },
2278 { "walletpassphrase", &walletpassphrase, true },
2279 { "walletpassphrasechange", &walletpassphrasechange, false },
2280 { "walletlock", &walletlock, true },
2281 { "encryptwallet", &encryptwallet, false },
2282 { "validateaddress", &validateaddress, true },
2283 { "getbalance", &getbalance, false },
2284 { "move", &movecmd, false },
2285 { "sendfrom", &sendfrom, false },
2286 { "sendmany", &sendmany, false },
2287 { "addmultisigaddress", &addmultisigaddress, false },
2288 { "getblock", &getblock, false },
2289 { "getblockhash", &getblockhash, false },
2290 { "gettransaction", &gettransaction, false },
2291 { "listtransactions", &listtransactions, false },
2292 { "signmessage", &signmessage, false },
2293 { "verifymessage", &verifymessage, false },
2294 { "getwork", &getwork, true },
2295 { "listaccounts", &listaccounts, false },
2296 { "settxfee", &settxfee, false },
2297 { "getmemorypool", &getmemorypool, true },
2298 { "listsinceblock", &listsinceblock, false },
2299 { "dumpprivkey", &dumpprivkey, false },
2300 { "importprivkey", &importprivkey, false },
2301 { "getcheckpoint", &getcheckpoint, true },
2302 { "reservebalance", &reservebalance, false},
2303 { "checkwallet", &checkwallet, false},
2304 { "repairwallet", &repairwallet, false},
2305 { "makekeypair", &makekeypair, false},
2306 { "sendalert", &sendalert, false},
2309 CRPCTable::CRPCTable()
2312 for (vcidx = 0; vcidx < (sizeof(vRPCCommands) / sizeof(vRPCCommands[0])); vcidx++)
2314 const CRPCCommand *pcmd;
2316 pcmd = &vRPCCommands[vcidx];
2317 mapCommands[pcmd->name] = pcmd;
2321 const CRPCCommand *CRPCTable::operator[](string name) const
2323 map<string, const CRPCCommand*>::const_iterator it = mapCommands.find(name);
2324 if (it == mapCommands.end())
2326 return (*it).second;
2332 // This ain't Apache. We're just using HTTP header for the length field
2333 // and to be compatible with other JSON-RPC implementations.
2336 string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
2339 s << "POST / HTTP/1.1\r\n"
2340 << "User-Agent: novacoin-json-rpc/" << FormatFullVersion() << "\r\n"
2341 << "Host: 127.0.0.1\r\n"
2342 << "Content-Type: application/json\r\n"
2343 << "Content-Length: " << strMsg.size() << "\r\n"
2344 << "Connection: close\r\n"
2345 << "Accept: application/json\r\n";
2346 BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
2347 s << item.first << ": " << item.second << "\r\n";
2348 s << "\r\n" << strMsg;
2353 string rfc1123Time()
2358 struct tm* now_gmt = gmtime(&now);
2359 string locale(setlocale(LC_TIME, NULL));
2360 setlocale(LC_TIME, "C"); // we want posix (aka "C") weekday/month strings
2361 strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt);
2362 setlocale(LC_TIME, locale.c_str());
2363 return string(buffer);
2366 static string HTTPReply(int nStatus, const string& strMsg)
2369 return strprintf("HTTP/1.0 401 Authorization Required\r\n"
2371 "Server: novacoin-json-rpc/%s\r\n"
2372 "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
2373 "Content-Type: text/html\r\n"
2374 "Content-Length: 296\r\n"
2376 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
2377 "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
2380 "<TITLE>Error</TITLE>\r\n"
2381 "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
2383 "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
2384 "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
2385 const char *cStatus;
2386 if (nStatus == 200) cStatus = "OK";
2387 else if (nStatus == 400) cStatus = "Bad Request";
2388 else if (nStatus == 403) cStatus = "Forbidden";
2389 else if (nStatus == 404) cStatus = "Not Found";
2390 else if (nStatus == 500) cStatus = "Internal Server Error";
2393 "HTTP/1.1 %d %s\r\n"
2395 "Connection: close\r\n"
2396 "Content-Length: %d\r\n"
2397 "Content-Type: application/json\r\n"
2398 "Server: novacoin-json-rpc/%s\r\n"
2403 rfc1123Time().c_str(),
2405 FormatFullVersion().c_str(),
2409 int ReadHTTPStatus(std::basic_istream<char>& stream)
2412 getline(stream, str);
2413 vector<string> vWords;
2414 boost::split(vWords, str, boost::is_any_of(" "));
2415 if (vWords.size() < 2)
2417 return atoi(vWords[1].c_str());
2420 int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
2426 std::getline(stream, str);
2427 if (str.empty() || str == "\r")
2429 string::size_type nColon = str.find(":");
2430 if (nColon != string::npos)
2432 string strHeader = str.substr(0, nColon);
2433 boost::trim(strHeader);
2434 boost::to_lower(strHeader);
2435 string strValue = str.substr(nColon+1);
2436 boost::trim(strValue);
2437 mapHeadersRet[strHeader] = strValue;
2438 if (strHeader == "content-length")
2439 nLen = atoi(strValue.c_str());
2445 int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
2447 mapHeadersRet.clear();
2451 int nStatus = ReadHTTPStatus(stream);
2454 int nLen = ReadHTTPHeader(stream, mapHeadersRet);
2455 if (nLen < 0 || nLen > (int)MAX_SIZE)
2461 vector<char> vch(nLen);
2462 stream.read(&vch[0], nLen);
2463 strMessageRet = string(vch.begin(), vch.end());
2469 bool HTTPAuthorized(map<string, string>& mapHeaders)
2471 string strAuth = mapHeaders["authorization"];
2472 if (strAuth.substr(0,6) != "Basic ")
2474 string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
2475 string strUserPass = DecodeBase64(strUserPass64);
2476 return strUserPass == strRPCUserColonPass;
2480 // JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
2481 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
2482 // unspecified (HTTP errors and contents of 'error').
2484 // 1.0 spec: http://json-rpc.org/wiki/specification
2485 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
2486 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
2489 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
2492 request.push_back(Pair("method", strMethod));
2493 request.push_back(Pair("params", params));
2494 request.push_back(Pair("id", id));
2495 return write_string(Value(request), false) + "\n";
2498 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
2501 if (error.type() != null_type)
2502 reply.push_back(Pair("result", Value::null));
2504 reply.push_back(Pair("result", result));
2505 reply.push_back(Pair("error", error));
2506 reply.push_back(Pair("id", id));
2507 return write_string(Value(reply), false) + "\n";
2510 void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
2512 // Send error reply from json-rpc error object
2514 int code = find_value(objError, "code").get_int();
2515 if (code == -32600) nStatus = 400;
2516 else if (code == -32601) nStatus = 404;
2517 string strReply = JSONRPCReply(Value::null, objError, id);
2518 stream << HTTPReply(nStatus, strReply) << std::flush;
2521 bool ClientAllowed(const string& strAddress)
2523 if (strAddress == asio::ip::address_v4::loopback().to_string())
2525 const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
2526 BOOST_FOREACH(string strAllow, vAllow)
2527 if (WildcardMatch(strAddress, strAllow))
2533 // IOStream device that speaks SSL but can also speak non-SSL
2535 class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
2537 SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
2539 fUseSSL = fUseSSLIn;
2540 fNeedHandshake = fUseSSLIn;
2543 void handshake(ssl::stream_base::handshake_type role)
2545 if (!fNeedHandshake) return;
2546 fNeedHandshake = false;
2547 stream.handshake(role);
2549 std::streamsize read(char* s, std::streamsize n)
2551 handshake(ssl::stream_base::server); // HTTPS servers read first
2552 if (fUseSSL) return stream.read_some(asio::buffer(s, n));
2553 return stream.next_layer().read_some(asio::buffer(s, n));
2555 std::streamsize write(const char* s, std::streamsize n)
2557 handshake(ssl::stream_base::client); // HTTPS clients write first
2558 if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
2559 return asio::write(stream.next_layer(), asio::buffer(s, n));
2561 bool connect(const std::string& server, const std::string& port)
2563 ip::tcp::resolver resolver(stream.get_io_service());
2564 ip::tcp::resolver::query query(server.c_str(), port.c_str());
2565 ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
2566 ip::tcp::resolver::iterator end;
2567 boost::system::error_code error = asio::error::host_not_found;
2568 while (error && endpoint_iterator != end)
2570 stream.lowest_layer().close();
2571 stream.lowest_layer().connect(*endpoint_iterator++, error);
2579 bool fNeedHandshake;
2584 void ThreadRPCServer(void* parg)
2586 IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
2589 vnThreadsRunning[THREAD_RPCSERVER]++;
2590 ThreadRPCServer2(parg);
2591 vnThreadsRunning[THREAD_RPCSERVER]--;
2593 catch (std::exception& e) {
2594 vnThreadsRunning[THREAD_RPCSERVER]--;
2595 PrintException(&e, "ThreadRPCServer()");
2597 vnThreadsRunning[THREAD_RPCSERVER]--;
2598 PrintException(NULL, "ThreadRPCServer()");
2600 printf("ThreadRPCServer exiting\n");
2603 void ThreadRPCServer2(void* parg)
2605 printf("ThreadRPCServer started\n");
2607 strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
2608 if (mapArgs["-rpcpassword"] == "")
2610 unsigned char rand_pwd[32];
2611 RAND_bytes(rand_pwd, 32);
2612 string strWhatAmI = "To use novacoind";
2613 if (mapArgs.count("-server"))
2614 strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
2615 else if (mapArgs.count("-daemon"))
2616 strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
2617 ThreadSafeMessageBox(strprintf(
2618 _("%s, you must set a rpcpassword in the configuration file:\n %s\n"
2619 "It is recommended you use the following random password:\n"
2620 "rpcuser=bitcoinrpc\n"
2622 "(you do not need to remember this password)\n"
2623 "If the file does not exist, create it with owner-readable-only file permissions.\n"),
2625 GetConfigFile().string().c_str(),
2626 EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str()),
2627 _("Error"), wxOK | wxMODAL);
2632 bool fUseSSL = GetBoolArg("-rpcssl");
2633 asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
2635 asio::io_service io_service;
2636 ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", RPC_PORT));
2637 ip::tcp::acceptor acceptor(io_service);
2640 acceptor.open(endpoint.protocol());
2641 acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
2642 acceptor.bind(endpoint);
2643 acceptor.listen(socket_base::max_connections);
2645 catch(boost::system::system_error &e)
2647 ThreadSafeMessageBox(strprintf(_("An error occured while setting up the RPC port %i for listening: %s"), endpoint.port(), e.what()),
2648 _("Error"), wxOK | wxMODAL);
2653 ssl::context context(io_service, ssl::context::sslv23);
2656 context.set_options(ssl::context::no_sslv2);
2658 filesystem::path pathCertFile(GetArg("-rpcsslcertificatechainfile", "server.cert"));
2659 if (!pathCertFile.is_complete()) pathCertFile = filesystem::path(GetDataDir()) / pathCertFile;
2660 if (filesystem::exists(pathCertFile)) context.use_certificate_chain_file(pathCertFile.string());
2661 else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", pathCertFile.string().c_str());
2663 filesystem::path pathPKFile(GetArg("-rpcsslprivatekeyfile", "server.pem"));
2664 if (!pathPKFile.is_complete()) pathPKFile = filesystem::path(GetDataDir()) / pathPKFile;
2665 if (filesystem::exists(pathPKFile)) context.use_private_key_file(pathPKFile.string(), ssl::context::pem);
2666 else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pathPKFile.string().c_str());
2668 string strCiphers = GetArg("-rpcsslciphers", "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
2669 SSL_CTX_set_cipher_list(context.impl(), strCiphers.c_str());
2674 // Accept connection
2675 SSLStream sslStream(io_service, context);
2676 SSLIOStreamDevice d(sslStream, fUseSSL);
2677 iostreams::stream<SSLIOStreamDevice> stream(d);
2679 ip::tcp::endpoint peer;
2680 vnThreadsRunning[THREAD_RPCSERVER]--;
2681 acceptor.accept(sslStream.lowest_layer(), peer);
2682 vnThreadsRunning[4]++;
2686 // Restrict callers by IP
2687 if (!ClientAllowed(peer.address().to_string()))
2689 // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
2691 stream << HTTPReply(403, "") << std::flush;
2695 map<string, string> mapHeaders;
2698 boost::thread api_caller(ReadHTTP, boost::ref(stream), boost::ref(mapHeaders), boost::ref(strRequest));
2699 if (!api_caller.timed_join(boost::posix_time::seconds(GetArg("-rpctimeout", 30))))
2702 printf("ThreadRPCServer ReadHTTP timeout\n");
2706 // Check authorization
2707 if (mapHeaders.count("authorization") == 0)
2709 stream << HTTPReply(401, "") << std::flush;
2712 if (!HTTPAuthorized(mapHeaders))
2714 printf("ThreadRPCServer incorrect password attempt from %s\n",peer.address().to_string().c_str());
2715 /* Deter brute-forcing short passwords.
2716 If this results in a DOS the user really
2717 shouldn't have their RPC port exposed.*/
2718 if (mapArgs["-rpcpassword"].size() < 20)
2721 stream << HTTPReply(401, "") << std::flush;
2725 Value id = Value::null;
2730 if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
2731 throw JSONRPCError(-32700, "Parse error");
2732 const Object& request = valRequest.get_obj();
2734 // Parse id now so errors from here on will have the id
2735 id = find_value(request, "id");
2738 Value valMethod = find_value(request, "method");
2739 if (valMethod.type() == null_type)
2740 throw JSONRPCError(-32600, "Missing method");
2741 if (valMethod.type() != str_type)
2742 throw JSONRPCError(-32600, "Method must be a string");
2743 string strMethod = valMethod.get_str();
2744 if (strMethod != "getwork" && strMethod != "getmemorypool")
2745 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
2748 Value valParams = find_value(request, "params");
2750 if (valParams.type() == array_type)
2751 params = valParams.get_array();
2752 else if (valParams.type() == null_type)
2755 throw JSONRPCError(-32600, "Params must be an array");
2758 const CRPCCommand *pcmd = tableRPC[strMethod];
2760 throw JSONRPCError(-32601, "Method not found");
2762 // Observe safe mode
2763 string strWarning = GetWarnings("rpc");
2764 if (strWarning != "" && !GetBoolArg("-disablesafemode") &&
2766 throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
2773 LOCK2(cs_main, pwalletMain->cs_wallet);
2774 result = pcmd->actor(params, false);
2778 string strReply = JSONRPCReply(result, Value::null, id);
2779 stream << HTTPReply(200, strReply) << std::flush;
2781 catch (std::exception& e)
2783 ErrorReply(stream, JSONRPCError(-1, e.what()), id);
2786 catch (Object& objError)
2788 ErrorReply(stream, objError, id);
2790 catch (std::exception& e)
2792 ErrorReply(stream, JSONRPCError(-32700, e.what()), id);
2800 Object CallRPC(const string& strMethod, const Array& params)
2802 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2803 throw runtime_error(strprintf(
2804 _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
2805 "If the file does not exist, create it with owner-readable-only file permissions."),
2806 GetConfigFile().string().c_str()));
2808 // Connect to localhost
2809 bool fUseSSL = GetBoolArg("-rpcssl");
2810 asio::io_service io_service;
2811 ssl::context context(io_service, ssl::context::sslv23);
2812 context.set_options(ssl::context::no_sslv2);
2813 SSLStream sslStream(io_service, context);
2814 SSLIOStreamDevice d(sslStream, fUseSSL);
2815 iostreams::stream<SSLIOStreamDevice> stream(d);
2816 if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", CBigNum(RPC_PORT).ToString().c_str())))
2817 throw runtime_error("couldn't connect to server");
2819 // HTTP basic authentication
2820 string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
2821 map<string, string> mapRequestHeaders;
2822 mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
2825 string strRequest = JSONRPCRequest(strMethod, params, 1);
2826 string strPost = HTTPPost(strRequest, mapRequestHeaders);
2827 stream << strPost << std::flush;
2830 map<string, string> mapHeaders;
2832 int nStatus = ReadHTTP(stream, mapHeaders, strReply);
2834 throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
2835 else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
2836 throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
2837 else if (strReply.empty())
2838 throw runtime_error("no response from server");
2842 if (!read_string(strReply, valReply))
2843 throw runtime_error("couldn't parse reply from server");
2844 const Object& reply = valReply.get_obj();
2846 throw runtime_error("expected reply to have result, error and id properties");
2854 template<typename T>
2855 void ConvertTo(Value& value)
2857 if (value.type() == str_type)
2859 // reinterpret string as unquoted json value
2861 if (!read_string(value.get_str(), value2))
2862 throw runtime_error("type mismatch");
2863 value = value2.get_value<T>();
2867 value = value.get_value<T>();
2871 int CommandLineRPC(int argc, char *argv[])
2878 while (argc > 1 && IsSwitchChar(argv[1][0]))
2886 throw runtime_error("too few parameters");
2887 string strMethod = argv[1];
2889 // Parameters default to strings
2891 for (int i = 2; i < argc; i++)
2892 params.push_back(argv[i]);
2893 int n = params.size();
2896 // Special case non-string parameter types
2898 if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
2899 if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2900 if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
2901 if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]);
2902 if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2903 if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2904 if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2905 if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
2906 if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2907 if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
2908 if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2909 if (strMethod == "getblockhash" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2910 if (strMethod == "getblock" && n > 1) ConvertTo<bool>(params[1]);
2911 if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]);
2912 if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2913 if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]);
2914 if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2915 if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2916 if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2917 if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2918 if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2919 if (strMethod == "walletpassphrase" && n > 2) ConvertTo<bool>(params[2]);
2920 if (strMethod == "listsinceblock" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2921 if (strMethod == "sendalert" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2922 if (strMethod == "sendalert" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2923 if (strMethod == "sendalert" && n > 4) ConvertTo<boost::int64_t>(params[4]);
2924 if (strMethod == "sendalert" && n > 5) ConvertTo<boost::int64_t>(params[5]);
2925 if (strMethod == "sendalert" && n > 6) ConvertTo<boost::int64_t>(params[6]);
2926 if (strMethod == "sendmany" && n > 1)
2928 string s = params[1].get_str();
2930 if (!read_string(s, v) || v.type() != obj_type)
2931 throw runtime_error("type mismatch");
2932 params[1] = v.get_obj();
2934 if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2935 if (strMethod == "reservebalance" && n > 0) ConvertTo<bool>(params[0]);
2936 if (strMethod == "reservebalance" && n > 1) ConvertTo<double>(params[1]);
2937 if (strMethod == "addmultisigaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2938 if (strMethod == "addmultisigaddress" && n > 1)
2940 string s = params[1].get_str();
2942 if (!read_string(s, v) || v.type() != array_type)
2943 throw runtime_error("type mismatch "+s);
2944 params[1] = v.get_array();
2948 Object reply = CallRPC(strMethod, params);
2951 const Value& result = find_value(reply, "result");
2952 const Value& error = find_value(reply, "error");
2954 if (error.type() != null_type)
2957 strPrint = "error: " + write_string(error, false);
2958 int code = find_value(error.get_obj(), "code").get_int();
2964 if (result.type() == null_type)
2966 else if (result.type() == str_type)
2967 strPrint = result.get_str();
2969 strPrint = write_string(result, true);
2972 catch (std::exception& e)
2974 strPrint = string("error: ") + e.what();
2979 PrintException(NULL, "CommandLineRPC()");
2984 fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
2993 int main(int argc, char *argv[])
2996 // Turn off microsoft heap dump noise
2997 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
2998 _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
3000 setbuf(stdin, NULL);
3001 setbuf(stdout, NULL);
3002 setbuf(stderr, NULL);
3006 if (argc >= 2 && string(argv[1]) == "-server")
3008 printf("server ready\n");
3009 ThreadRPCServer(NULL);
3013 return CommandLineRPC(argc, argv);
3016 catch (std::exception& e) {
3017 PrintException(&e, "main()");
3019 PrintException(NULL, "main()");
3025 const CRPCTable tableRPC;