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 static CReserveKey reservekey(pwalletMain);
1997 if(!pblock.SignBlock(*pwalletMain))
1998 throw JSONRPCError(-100, "Unable to sign block, wallet locked?");
2000 return CheckWork(&pblock, *pwalletMain, reservekey);
2004 Value getnewpubkey(const Array& params, bool fHelp)
2006 if (fHelp || params.size() > 1)
2007 throw runtime_error(
2008 "getnewpubkey [account]\n"
2009 "Returns new public key for coinbase generation.");
2011 // Parse the account first so we don't generate a key if there's an error
2013 if (params.size() > 0)
2014 strAccount = AccountFromValue(params[0]);
2016 if (!pwalletMain->IsLocked())
2017 pwalletMain->TopUpKeyPool();
2019 // Generate a new key that is added to wallet
2020 std::vector<unsigned char> newKey = pwalletMain->GenerateNewKey(false);
2023 throw JSONRPCError(-12, "Error: Unable to create key");
2025 CBitcoinAddress address(newKey);
2026 pwalletMain->SetAddressBookName(address, strAccount);
2028 return HexStr(newKey.begin(), newKey.end());
2032 Value getblockhash(const Array& params, bool fHelp)
2034 if (fHelp || params.size() != 1)
2035 throw runtime_error(
2036 "getblockhash <index>\n"
2037 "Returns hash of block in best-block-chain at <index>.");
2039 int nHeight = params[0].get_int();
2040 if (nHeight < 0 || nHeight > nBestHeight)
2041 throw runtime_error("Block number out of range.");
2044 CBlockIndex* pblockindex = mapBlockIndex[hashBestChain];
2045 while (pblockindex->nHeight > nHeight)
2046 pblockindex = pblockindex->pprev;
2047 return pblockindex->phashBlock->GetHex();
2050 Value getblock(const Array& params, bool fHelp)
2052 if (fHelp || params.size() < 1 || params.size() > 2)
2053 throw runtime_error(
2054 "getblock <hash> [txinfo]\n"
2055 "txinfo optional to print more detailed tx info\n"
2056 "Returns details of a block with given block-hash.");
2058 std::string strHash = params[0].get_str();
2059 uint256 hash(strHash);
2061 if (mapBlockIndex.count(hash) == 0)
2062 throw JSONRPCError(-5, "Block not found");
2065 CBlockIndex* pblockindex = mapBlockIndex[hash];
2066 block.ReadFromDisk(pblockindex, true);
2068 return blockToJSON(block, pblockindex, params.size() > 1 ? params[1].get_bool() : false);
2072 // ppcoin: get information of sync-checkpoint
2073 Value getcheckpoint(const Array& params, bool fHelp)
2075 if (fHelp || params.size() != 0)
2076 throw runtime_error(
2078 "Show info of synchronized checkpoint.\n");
2081 CBlockIndex* pindexCheckpoint;
2083 result.push_back(Pair("synccheckpoint", Checkpoints::hashSyncCheckpoint.ToString().c_str()));
2084 pindexCheckpoint = mapBlockIndex[Checkpoints::hashSyncCheckpoint];
2085 result.push_back(Pair("height", pindexCheckpoint->nHeight));
2086 result.push_back(Pair("timestamp", DateTimeStrFormat(pindexCheckpoint->GetBlockTime()).c_str()));
2087 if (mapArgs.count("-checkpointkey"))
2088 result.push_back(Pair("checkpointmaster", true));
2094 // ppcoin: reserve balance from being staked for network protection
2095 Value reservebalance(const Array& params, bool fHelp)
2097 if (fHelp || params.size() > 2)
2098 throw runtime_error(
2099 "reservebalance [<reserve> [amount]]\n"
2100 "<reserve> is true or false to turn balance reserve on or off.\n"
2101 "<amount> is a real and rounded to cent.\n"
2102 "Set reserve amount not participating in network protection.\n"
2103 "If no parameters provided current setting is printed.\n");
2105 if (params.size() > 0)
2107 bool fReserve = params[0].get_bool();
2110 if (params.size() == 1)
2111 throw runtime_error("must provide amount to reserve balance.\n");
2112 int64 nAmount = AmountFromValue(params[1]);
2113 nAmount = (nAmount / CENT) * CENT; // round to cent
2115 throw runtime_error("amount cannot be negative.\n");
2116 mapArgs["-reservebalance"] = FormatMoney(nAmount).c_str();
2120 if (params.size() > 1)
2121 throw runtime_error("cannot specify amount to turn off reserve.\n");
2122 mapArgs["-reservebalance"] = "0";
2127 int64 nReserveBalance = 0;
2128 if (mapArgs.count("-reservebalance") && !ParseMoney(mapArgs["-reservebalance"], nReserveBalance))
2129 throw runtime_error("invalid reserve balance amount\n");
2130 result.push_back(Pair("reserve", (nReserveBalance > 0)));
2131 result.push_back(Pair("amount", ValueFromAmount(nReserveBalance)));
2136 // ppcoin: check wallet integrity
2137 Value checkwallet(const Array& params, bool fHelp)
2139 if (fHelp || params.size() > 0)
2140 throw runtime_error(
2142 "Check wallet for integrity.\n");
2145 int64 nBalanceInQuestion;
2146 pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion, true);
2148 if (nMismatchSpent == 0)
2149 result.push_back(Pair("wallet check passed", true));
2152 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
2153 result.push_back(Pair("amount in question", ValueFromAmount(nBalanceInQuestion)));
2159 // ppcoin: repair wallet
2160 Value repairwallet(const Array& params, bool fHelp)
2162 if (fHelp || params.size() > 0)
2163 throw runtime_error(
2165 "Repair wallet if checkwallet reports any problem.\n");
2168 int64 nBalanceInQuestion;
2169 pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion);
2171 if (nMismatchSpent == 0)
2172 result.push_back(Pair("wallet check passed", true));
2175 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
2176 result.push_back(Pair("amount affected by repair", ValueFromAmount(nBalanceInQuestion)));
2181 // ppcoin: make a public-private key pair
2182 Value makekeypair(const Array& params, bool fHelp)
2184 if (fHelp || params.size() > 1)
2185 throw runtime_error(
2186 "makekeypair [prefix]\n"
2187 "Make a public/private key pair.\n"
2188 "[prefix] is optional preferred prefix for the public key.\n");
2190 string strPrefix = "";
2191 if (params.size() > 0)
2192 strPrefix = params[0].get_str();
2198 key.MakeNewKey(false);
2200 } while (nCount < 10000 && strPrefix != HexStr(key.GetPubKey()).substr(0, strPrefix.size()));
2202 if (strPrefix != HexStr(key.GetPubKey()).substr(0, strPrefix.size()))
2205 CPrivKey vchPrivKey = key.GetPrivKey();
2207 result.push_back(Pair("PrivateKey", HexStr<CPrivKey::iterator>(vchPrivKey.begin(), vchPrivKey.end())));
2208 result.push_back(Pair("PublicKey", HexStr(key.GetPubKey())));
2212 extern CCriticalSection cs_mapAlerts;
2213 extern map<uint256, CAlert> mapAlerts;
2215 // ppcoin: send alert.
2216 // There is a known deadlock situation with ThreadMessageHandler
2217 // ThreadMessageHandler: holds cs_vSend and acquiring cs_main in SendMessages()
2218 // ThreadRPCServer: holds cs_main and acquiring cs_vSend in alert.RelayTo()/PushMessage()/BeginMessage()
2219 Value sendalert(const Array& params, bool fHelp)
2221 if (fHelp || params.size() < 6)
2222 throw runtime_error(
2223 "sendalert <message> <privatekey> <minver> <maxver> <priority> <id> [cancelupto]\n"
2224 "<message> is the alert text message\n"
2225 "<privatekey> is hex string of alert master private key\n"
2226 "<minver> is the minimum applicable internal client version\n"
2227 "<maxver> is the maximum applicable internal client version\n"
2228 "<priority> is integer priority number\n"
2229 "<id> is the alert id\n"
2230 "[cancelupto] cancels all alert id's up to this number\n"
2231 "Returns true or false.");
2236 alert.strStatusBar = params[0].get_str();
2237 alert.nMinVer = params[2].get_int();
2238 alert.nMaxVer = params[3].get_int();
2239 alert.nPriority = params[4].get_int();
2240 alert.nID = params[5].get_int();
2241 if (params.size() > 6)
2242 alert.nCancel = params[6].get_int();
2243 alert.nVersion = PROTOCOL_VERSION;
2244 alert.nRelayUntil = GetAdjustedTime() + 365*24*60*60;
2245 alert.nExpiration = GetAdjustedTime() + 365*24*60*60;
2247 CDataStream sMsg(SER_NETWORK, PROTOCOL_VERSION);
2248 sMsg << (CUnsignedAlert)alert;
2249 alert.vchMsg = vector<unsigned char>(sMsg.begin(), sMsg.end());
2251 vector<unsigned char> vchPrivKey = ParseHex(params[1].get_str());
2252 key.SetPrivKey(CPrivKey(vchPrivKey.begin(), vchPrivKey.end())); // if key is not correct openssl may crash
2253 if (!key.Sign(Hash(alert.vchMsg.begin(), alert.vchMsg.end()), alert.vchSig))
2254 throw runtime_error(
2255 "Unable to sign alert, check private key?\n");
2256 if(!alert.ProcessAlert())
2257 throw runtime_error(
2258 "Failed to process alert.\n");
2262 BOOST_FOREACH(CNode* pnode, vNodes)
2263 alert.RelayTo(pnode);
2267 result.push_back(Pair("strStatusBar", alert.strStatusBar));
2268 result.push_back(Pair("nVersion", alert.nVersion));
2269 result.push_back(Pair("nMinVer", alert.nMinVer));
2270 result.push_back(Pair("nMaxVer", alert.nMaxVer));
2271 result.push_back(Pair("nPriority", alert.nPriority));
2272 result.push_back(Pair("nID", alert.nID));
2273 if (alert.nCancel > 0)
2274 result.push_back(Pair("nCancel", alert.nCancel));
2285 static const CRPCCommand vRPCCommands[] =
2286 { // name function safe mode?
2287 // ------------------------ ----------------------- ----------
2288 { "help", &help, true },
2289 { "stop", &stop, true },
2290 { "getblockcount", &getblockcount, true },
2291 { "getblocknumber", &getblocknumber, true },
2292 { "getconnectioncount", &getconnectioncount, true },
2293 { "getdifficulty", &getdifficulty, true },
2294 { "getgenerate", &getgenerate, true },
2295 { "setgenerate", &setgenerate, true },
2296 { "gethashespersec", &gethashespersec, true },
2297 { "getinfo", &getinfo, true },
2298 { "getmininginfo", &getmininginfo, true },
2299 { "getnewaddress", &getnewaddress, true },
2300 { "getnewpubkey", &getnewpubkey, true },
2301 { "getaccountaddress", &getaccountaddress, true },
2302 { "setaccount", &setaccount, true },
2303 { "getaccount", &getaccount, false },
2304 { "getaddressesbyaccount", &getaddressesbyaccount, true },
2305 { "sendtoaddress", &sendtoaddress, false },
2306 { "getreceivedbyaddress", &getreceivedbyaddress, false },
2307 { "getreceivedbyaccount", &getreceivedbyaccount, false },
2308 { "listreceivedbyaddress", &listreceivedbyaddress, false },
2309 { "listreceivedbyaccount", &listreceivedbyaccount, false },
2310 { "backupwallet", &backupwallet, true },
2311 { "keypoolrefill", &keypoolrefill, true },
2312 { "walletpassphrase", &walletpassphrase, true },
2313 { "walletpassphrasechange", &walletpassphrasechange, false },
2314 { "walletlock", &walletlock, true },
2315 { "encryptwallet", &encryptwallet, false },
2316 { "validateaddress", &validateaddress, true },
2317 { "getbalance", &getbalance, false },
2318 { "move", &movecmd, false },
2319 { "sendfrom", &sendfrom, false },
2320 { "sendmany", &sendmany, false },
2321 { "addmultisigaddress", &addmultisigaddress, false },
2322 { "getblock", &getblock, false },
2323 { "getblockhash", &getblockhash, false },
2324 { "gettransaction", &gettransaction, false },
2325 { "listtransactions", &listtransactions, false },
2326 { "signmessage", &signmessage, false },
2327 { "verifymessage", &verifymessage, false },
2328 { "getwork", &getwork, true },
2329 { "listaccounts", &listaccounts, false },
2330 { "settxfee", &settxfee, false },
2331 { "getmemorypool", &getmemorypool, true },
2332 { "listsinceblock", &listsinceblock, false },
2333 { "dumpprivkey", &dumpprivkey, false },
2334 { "importprivkey", &importprivkey, false },
2335 { "getcheckpoint", &getcheckpoint, true },
2336 { "reservebalance", &reservebalance, false},
2337 { "checkwallet", &checkwallet, false},
2338 { "repairwallet", &repairwallet, false},
2339 { "makekeypair", &makekeypair, false},
2340 { "sendalert", &sendalert, false},
2343 CRPCTable::CRPCTable()
2346 for (vcidx = 0; vcidx < (sizeof(vRPCCommands) / sizeof(vRPCCommands[0])); vcidx++)
2348 const CRPCCommand *pcmd;
2350 pcmd = &vRPCCommands[vcidx];
2351 mapCommands[pcmd->name] = pcmd;
2355 const CRPCCommand *CRPCTable::operator[](string name) const
2357 map<string, const CRPCCommand*>::const_iterator it = mapCommands.find(name);
2358 if (it == mapCommands.end())
2360 return (*it).second;
2366 // This ain't Apache. We're just using HTTP header for the length field
2367 // and to be compatible with other JSON-RPC implementations.
2370 string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
2373 s << "POST / HTTP/1.1\r\n"
2374 << "User-Agent: novacoin-json-rpc/" << FormatFullVersion() << "\r\n"
2375 << "Host: 127.0.0.1\r\n"
2376 << "Content-Type: application/json\r\n"
2377 << "Content-Length: " << strMsg.size() << "\r\n"
2378 << "Connection: close\r\n"
2379 << "Accept: application/json\r\n";
2380 BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
2381 s << item.first << ": " << item.second << "\r\n";
2382 s << "\r\n" << strMsg;
2387 string rfc1123Time()
2392 struct tm* now_gmt = gmtime(&now);
2393 string locale(setlocale(LC_TIME, NULL));
2394 setlocale(LC_TIME, "C"); // we want posix (aka "C") weekday/month strings
2395 strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt);
2396 setlocale(LC_TIME, locale.c_str());
2397 return string(buffer);
2400 static string HTTPReply(int nStatus, const string& strMsg)
2403 return strprintf("HTTP/1.0 401 Authorization Required\r\n"
2405 "Server: novacoin-json-rpc/%s\r\n"
2406 "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
2407 "Content-Type: text/html\r\n"
2408 "Content-Length: 296\r\n"
2410 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
2411 "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
2414 "<TITLE>Error</TITLE>\r\n"
2415 "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
2417 "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
2418 "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
2419 const char *cStatus;
2420 if (nStatus == 200) cStatus = "OK";
2421 else if (nStatus == 400) cStatus = "Bad Request";
2422 else if (nStatus == 403) cStatus = "Forbidden";
2423 else if (nStatus == 404) cStatus = "Not Found";
2424 else if (nStatus == 500) cStatus = "Internal Server Error";
2427 "HTTP/1.1 %d %s\r\n"
2429 "Connection: close\r\n"
2430 "Content-Length: %d\r\n"
2431 "Content-Type: application/json\r\n"
2432 "Server: novacoin-json-rpc/%s\r\n"
2437 rfc1123Time().c_str(),
2439 FormatFullVersion().c_str(),
2443 int ReadHTTPStatus(std::basic_istream<char>& stream)
2446 getline(stream, str);
2447 vector<string> vWords;
2448 boost::split(vWords, str, boost::is_any_of(" "));
2449 if (vWords.size() < 2)
2451 return atoi(vWords[1].c_str());
2454 int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
2460 std::getline(stream, str);
2461 if (str.empty() || str == "\r")
2463 string::size_type nColon = str.find(":");
2464 if (nColon != string::npos)
2466 string strHeader = str.substr(0, nColon);
2467 boost::trim(strHeader);
2468 boost::to_lower(strHeader);
2469 string strValue = str.substr(nColon+1);
2470 boost::trim(strValue);
2471 mapHeadersRet[strHeader] = strValue;
2472 if (strHeader == "content-length")
2473 nLen = atoi(strValue.c_str());
2479 int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
2481 mapHeadersRet.clear();
2485 int nStatus = ReadHTTPStatus(stream);
2488 int nLen = ReadHTTPHeader(stream, mapHeadersRet);
2489 if (nLen < 0 || nLen > (int)MAX_SIZE)
2495 vector<char> vch(nLen);
2496 stream.read(&vch[0], nLen);
2497 strMessageRet = string(vch.begin(), vch.end());
2503 bool HTTPAuthorized(map<string, string>& mapHeaders)
2505 string strAuth = mapHeaders["authorization"];
2506 if (strAuth.substr(0,6) != "Basic ")
2508 string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
2509 string strUserPass = DecodeBase64(strUserPass64);
2510 return strUserPass == strRPCUserColonPass;
2514 // JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
2515 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
2516 // unspecified (HTTP errors and contents of 'error').
2518 // 1.0 spec: http://json-rpc.org/wiki/specification
2519 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
2520 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
2523 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
2526 request.push_back(Pair("method", strMethod));
2527 request.push_back(Pair("params", params));
2528 request.push_back(Pair("id", id));
2529 return write_string(Value(request), false) + "\n";
2532 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
2535 if (error.type() != null_type)
2536 reply.push_back(Pair("result", Value::null));
2538 reply.push_back(Pair("result", result));
2539 reply.push_back(Pair("error", error));
2540 reply.push_back(Pair("id", id));
2541 return write_string(Value(reply), false) + "\n";
2544 void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
2546 // Send error reply from json-rpc error object
2548 int code = find_value(objError, "code").get_int();
2549 if (code == -32600) nStatus = 400;
2550 else if (code == -32601) nStatus = 404;
2551 string strReply = JSONRPCReply(Value::null, objError, id);
2552 stream << HTTPReply(nStatus, strReply) << std::flush;
2555 bool ClientAllowed(const string& strAddress)
2557 if (strAddress == asio::ip::address_v4::loopback().to_string())
2559 const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
2560 BOOST_FOREACH(string strAllow, vAllow)
2561 if (WildcardMatch(strAddress, strAllow))
2567 // IOStream device that speaks SSL but can also speak non-SSL
2569 class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
2571 SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
2573 fUseSSL = fUseSSLIn;
2574 fNeedHandshake = fUseSSLIn;
2577 void handshake(ssl::stream_base::handshake_type role)
2579 if (!fNeedHandshake) return;
2580 fNeedHandshake = false;
2581 stream.handshake(role);
2583 std::streamsize read(char* s, std::streamsize n)
2585 handshake(ssl::stream_base::server); // HTTPS servers read first
2586 if (fUseSSL) return stream.read_some(asio::buffer(s, n));
2587 return stream.next_layer().read_some(asio::buffer(s, n));
2589 std::streamsize write(const char* s, std::streamsize n)
2591 handshake(ssl::stream_base::client); // HTTPS clients write first
2592 if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
2593 return asio::write(stream.next_layer(), asio::buffer(s, n));
2595 bool connect(const std::string& server, const std::string& port)
2597 ip::tcp::resolver resolver(stream.get_io_service());
2598 ip::tcp::resolver::query query(server.c_str(), port.c_str());
2599 ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
2600 ip::tcp::resolver::iterator end;
2601 boost::system::error_code error = asio::error::host_not_found;
2602 while (error && endpoint_iterator != end)
2604 stream.lowest_layer().close();
2605 stream.lowest_layer().connect(*endpoint_iterator++, error);
2613 bool fNeedHandshake;
2618 void ThreadRPCServer(void* parg)
2620 IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
2623 vnThreadsRunning[THREAD_RPCSERVER]++;
2624 ThreadRPCServer2(parg);
2625 vnThreadsRunning[THREAD_RPCSERVER]--;
2627 catch (std::exception& e) {
2628 vnThreadsRunning[THREAD_RPCSERVER]--;
2629 PrintException(&e, "ThreadRPCServer()");
2631 vnThreadsRunning[THREAD_RPCSERVER]--;
2632 PrintException(NULL, "ThreadRPCServer()");
2634 printf("ThreadRPCServer exiting\n");
2637 void ThreadRPCServer2(void* parg)
2639 printf("ThreadRPCServer started\n");
2641 strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
2642 if (mapArgs["-rpcpassword"] == "")
2644 unsigned char rand_pwd[32];
2645 RAND_bytes(rand_pwd, 32);
2646 string strWhatAmI = "To use novacoind";
2647 if (mapArgs.count("-server"))
2648 strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
2649 else if (mapArgs.count("-daemon"))
2650 strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
2651 ThreadSafeMessageBox(strprintf(
2652 _("%s, you must set a rpcpassword in the configuration file:\n %s\n"
2653 "It is recommended you use the following random password:\n"
2654 "rpcuser=bitcoinrpc\n"
2656 "(you do not need to remember this password)\n"
2657 "If the file does not exist, create it with owner-readable-only file permissions.\n"),
2659 GetConfigFile().string().c_str(),
2660 EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str()),
2661 _("Error"), wxOK | wxMODAL);
2666 bool fUseSSL = GetBoolArg("-rpcssl");
2667 asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
2669 asio::io_service io_service;
2670 ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", RPC_PORT));
2671 ip::tcp::acceptor acceptor(io_service);
2674 acceptor.open(endpoint.protocol());
2675 acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
2676 acceptor.bind(endpoint);
2677 acceptor.listen(socket_base::max_connections);
2679 catch(boost::system::system_error &e)
2681 ThreadSafeMessageBox(strprintf(_("An error occured while setting up the RPC port %i for listening: %s"), endpoint.port(), e.what()),
2682 _("Error"), wxOK | wxMODAL);
2687 ssl::context context(io_service, ssl::context::sslv23);
2690 context.set_options(ssl::context::no_sslv2);
2692 filesystem::path pathCertFile(GetArg("-rpcsslcertificatechainfile", "server.cert"));
2693 if (!pathCertFile.is_complete()) pathCertFile = filesystem::path(GetDataDir()) / pathCertFile;
2694 if (filesystem::exists(pathCertFile)) context.use_certificate_chain_file(pathCertFile.string());
2695 else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", pathCertFile.string().c_str());
2697 filesystem::path pathPKFile(GetArg("-rpcsslprivatekeyfile", "server.pem"));
2698 if (!pathPKFile.is_complete()) pathPKFile = filesystem::path(GetDataDir()) / pathPKFile;
2699 if (filesystem::exists(pathPKFile)) context.use_private_key_file(pathPKFile.string(), ssl::context::pem);
2700 else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pathPKFile.string().c_str());
2702 string strCiphers = GetArg("-rpcsslciphers", "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
2703 SSL_CTX_set_cipher_list(context.impl(), strCiphers.c_str());
2708 // Accept connection
2709 SSLStream sslStream(io_service, context);
2710 SSLIOStreamDevice d(sslStream, fUseSSL);
2711 iostreams::stream<SSLIOStreamDevice> stream(d);
2713 ip::tcp::endpoint peer;
2714 vnThreadsRunning[THREAD_RPCSERVER]--;
2715 acceptor.accept(sslStream.lowest_layer(), peer);
2716 vnThreadsRunning[4]++;
2720 // Restrict callers by IP
2721 if (!ClientAllowed(peer.address().to_string()))
2723 // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
2725 stream << HTTPReply(403, "") << std::flush;
2729 map<string, string> mapHeaders;
2732 boost::thread api_caller(ReadHTTP, boost::ref(stream), boost::ref(mapHeaders), boost::ref(strRequest));
2733 if (!api_caller.timed_join(boost::posix_time::seconds(GetArg("-rpctimeout", 30))))
2736 printf("ThreadRPCServer ReadHTTP timeout\n");
2740 // Check authorization
2741 if (mapHeaders.count("authorization") == 0)
2743 stream << HTTPReply(401, "") << std::flush;
2746 if (!HTTPAuthorized(mapHeaders))
2748 printf("ThreadRPCServer incorrect password attempt from %s\n",peer.address().to_string().c_str());
2749 /* Deter brute-forcing short passwords.
2750 If this results in a DOS the user really
2751 shouldn't have their RPC port exposed.*/
2752 if (mapArgs["-rpcpassword"].size() < 20)
2755 stream << HTTPReply(401, "") << std::flush;
2759 Value id = Value::null;
2764 if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
2765 throw JSONRPCError(-32700, "Parse error");
2766 const Object& request = valRequest.get_obj();
2768 // Parse id now so errors from here on will have the id
2769 id = find_value(request, "id");
2772 Value valMethod = find_value(request, "method");
2773 if (valMethod.type() == null_type)
2774 throw JSONRPCError(-32600, "Missing method");
2775 if (valMethod.type() != str_type)
2776 throw JSONRPCError(-32600, "Method must be a string");
2777 string strMethod = valMethod.get_str();
2778 if (strMethod != "getwork" && strMethod != "getmemorypool")
2779 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
2782 Value valParams = find_value(request, "params");
2784 if (valParams.type() == array_type)
2785 params = valParams.get_array();
2786 else if (valParams.type() == null_type)
2789 throw JSONRPCError(-32600, "Params must be an array");
2792 const CRPCCommand *pcmd = tableRPC[strMethod];
2794 throw JSONRPCError(-32601, "Method not found");
2796 // Observe safe mode
2797 string strWarning = GetWarnings("rpc");
2798 if (strWarning != "" && !GetBoolArg("-disablesafemode") &&
2800 throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
2807 LOCK2(cs_main, pwalletMain->cs_wallet);
2808 result = pcmd->actor(params, false);
2812 string strReply = JSONRPCReply(result, Value::null, id);
2813 stream << HTTPReply(200, strReply) << std::flush;
2815 catch (std::exception& e)
2817 ErrorReply(stream, JSONRPCError(-1, e.what()), id);
2820 catch (Object& objError)
2822 ErrorReply(stream, objError, id);
2824 catch (std::exception& e)
2826 ErrorReply(stream, JSONRPCError(-32700, e.what()), id);
2834 Object CallRPC(const string& strMethod, const Array& params)
2836 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
2837 throw runtime_error(strprintf(
2838 _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
2839 "If the file does not exist, create it with owner-readable-only file permissions."),
2840 GetConfigFile().string().c_str()));
2842 // Connect to localhost
2843 bool fUseSSL = GetBoolArg("-rpcssl");
2844 asio::io_service io_service;
2845 ssl::context context(io_service, ssl::context::sslv23);
2846 context.set_options(ssl::context::no_sslv2);
2847 SSLStream sslStream(io_service, context);
2848 SSLIOStreamDevice d(sslStream, fUseSSL);
2849 iostreams::stream<SSLIOStreamDevice> stream(d);
2850 if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", CBigNum(RPC_PORT).ToString().c_str())))
2851 throw runtime_error("couldn't connect to server");
2853 // HTTP basic authentication
2854 string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
2855 map<string, string> mapRequestHeaders;
2856 mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
2859 string strRequest = JSONRPCRequest(strMethod, params, 1);
2860 string strPost = HTTPPost(strRequest, mapRequestHeaders);
2861 stream << strPost << std::flush;
2864 map<string, string> mapHeaders;
2866 int nStatus = ReadHTTP(stream, mapHeaders, strReply);
2868 throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
2869 else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
2870 throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
2871 else if (strReply.empty())
2872 throw runtime_error("no response from server");
2876 if (!read_string(strReply, valReply))
2877 throw runtime_error("couldn't parse reply from server");
2878 const Object& reply = valReply.get_obj();
2880 throw runtime_error("expected reply to have result, error and id properties");
2888 template<typename T>
2889 void ConvertTo(Value& value)
2891 if (value.type() == str_type)
2893 // reinterpret string as unquoted json value
2895 if (!read_string(value.get_str(), value2))
2896 throw runtime_error("type mismatch");
2897 value = value2.get_value<T>();
2901 value = value.get_value<T>();
2905 int CommandLineRPC(int argc, char *argv[])
2912 while (argc > 1 && IsSwitchChar(argv[1][0]))
2920 throw runtime_error("too few parameters");
2921 string strMethod = argv[1];
2923 // Parameters default to strings
2925 for (int i = 2; i < argc; i++)
2926 params.push_back(argv[i]);
2927 int n = params.size();
2930 // Special case non-string parameter types
2932 if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
2933 if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2934 if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
2935 if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]);
2936 if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2937 if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2938 if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2939 if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
2940 if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2941 if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
2942 if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2943 if (strMethod == "getblockhash" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2944 if (strMethod == "getblock" && n > 1) ConvertTo<bool>(params[1]);
2945 if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]);
2946 if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2947 if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]);
2948 if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2949 if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2950 if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2951 if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2952 if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2953 if (strMethod == "walletpassphrase" && n > 2) ConvertTo<bool>(params[2]);
2954 if (strMethod == "listsinceblock" && n > 1) ConvertTo<boost::int64_t>(params[1]);
2955 if (strMethod == "sendalert" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2956 if (strMethod == "sendalert" && n > 3) ConvertTo<boost::int64_t>(params[3]);
2957 if (strMethod == "sendalert" && n > 4) ConvertTo<boost::int64_t>(params[4]);
2958 if (strMethod == "sendalert" && n > 5) ConvertTo<boost::int64_t>(params[5]);
2959 if (strMethod == "sendalert" && n > 6) ConvertTo<boost::int64_t>(params[6]);
2960 if (strMethod == "sendmany" && n > 1)
2962 string s = params[1].get_str();
2964 if (!read_string(s, v) || v.type() != obj_type)
2965 throw runtime_error("type mismatch");
2966 params[1] = v.get_obj();
2968 if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]);
2969 if (strMethod == "reservebalance" && n > 0) ConvertTo<bool>(params[0]);
2970 if (strMethod == "reservebalance" && n > 1) ConvertTo<double>(params[1]);
2971 if (strMethod == "addmultisigaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
2972 if (strMethod == "addmultisigaddress" && n > 1)
2974 string s = params[1].get_str();
2976 if (!read_string(s, v) || v.type() != array_type)
2977 throw runtime_error("type mismatch "+s);
2978 params[1] = v.get_array();
2982 Object reply = CallRPC(strMethod, params);
2985 const Value& result = find_value(reply, "result");
2986 const Value& error = find_value(reply, "error");
2988 if (error.type() != null_type)
2991 strPrint = "error: " + write_string(error, false);
2992 int code = find_value(error.get_obj(), "code").get_int();
2998 if (result.type() == null_type)
3000 else if (result.type() == str_type)
3001 strPrint = result.get_str();
3003 strPrint = write_string(result, true);
3006 catch (std::exception& e)
3008 strPrint = string("error: ") + e.what();
3013 PrintException(NULL, "CommandLineRPC()");
3018 fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
3027 int main(int argc, char *argv[])
3030 // Turn off microsoft heap dump noise
3031 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
3032 _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
3034 setbuf(stdin, NULL);
3035 setbuf(stdout, NULL);
3036 setbuf(stderr, NULL);
3040 if (argc >= 2 && string(argv[1]) == "-server")
3042 printf("server ready\n");
3043 ThreadRPCServer(NULL);
3047 return CommandLineRPC(argc, argv);
3050 catch (std::exception& e) {
3051 PrintException(&e, "main()");
3053 PrintException(NULL, "main()");
3059 const CRPCTable tableRPC;