1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2012 The Bitcoin developers
3 // Copyright (c) 2011-2013 The PPCoin developers
4 // Copyright (c) 2013 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 Object JSONRPCError(int code, const string& message)
53 error.push_back(Pair("code", code));
54 error.push_back(Pair("message", message));
58 double GetDifficulty(const CBlockIndex* blockindex = NULL)
60 // Floating point number that is a multiple of the minimum difficulty,
61 // minimum difficulty = 1.0.
62 if (blockindex == NULL)
64 if (pindexBest == NULL)
67 blockindex = GetLastBlockIndex(pindexBest, false);
70 int nShift = (blockindex->nBits >> 24) & 0xff;
73 (double)0x0000ffff / (double)(blockindex->nBits & 0x00ffffff);
90 int64 AmountFromValue(const Value& value)
92 double dAmount = value.get_real();
93 if (dAmount <= 0.0 || dAmount > MAX_MONEY)
94 throw JSONRPCError(-3, "Invalid amount");
95 int64 nAmount = roundint64(dAmount * COIN);
96 if (!MoneyRange(nAmount))
97 throw JSONRPCError(-3, "Invalid amount");
101 Value ValueFromAmount(int64 amount)
103 return (double)amount / (double)COIN;
107 HexBits(unsigned int nBits)
113 uBits.nBits = htonl((int32_t)nBits);
114 return HexStr(BEGIN(uBits.cBits), END(uBits.cBits));
117 unsigned int BitsHex(std::string HexBits)
124 vector<unsigned char> vchBits = ParseHex(HexBits);
125 copy(vchBits.begin(), vchBits.begin() + 4, uBits.cBits);
126 uBits.nBits = htonl((int32_t)uBits.nBits);
130 void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
132 int confirms = wtx.GetDepthInMainChain();
133 entry.push_back(Pair("confirmations", confirms));
136 entry.push_back(Pair("blockhash", wtx.hashBlock.GetHex()));
137 entry.push_back(Pair("blockindex", wtx.nIndex));
139 entry.push_back(Pair("txid", wtx.GetHash().GetHex()));
140 entry.push_back(Pair("time", (boost::int64_t)wtx.GetTxTime()));
141 BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
142 entry.push_back(Pair(item.first, item.second));
145 string AccountFromValue(const Value& value)
147 string strAccount = value.get_str();
148 if (strAccount == "*")
149 throw JSONRPCError(-11, "Invalid account name");
153 Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool fPrintTransactionDetail)
156 result.push_back(Pair("hash", block.GetHash().GetHex()));
157 result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION)));
158 result.push_back(Pair("height", blockindex->nHeight));
159 result.push_back(Pair("version", block.nVersion));
160 result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex()));
161 result.push_back(Pair("time", DateTimeStrFormat(block.GetBlockTime())));
162 result.push_back(Pair("nonce", (boost::uint64_t)block.nNonce));
163 result.push_back(Pair("bits", HexBits(block.nBits)));
164 result.push_back(Pair("difficulty", GetDifficulty(blockindex)));
165 result.push_back(Pair("mint", ValueFromAmount(blockindex->nMint)));
166 if (blockindex->pprev)
167 result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex()));
168 if (blockindex->pnext)
169 result.push_back(Pair("nextblockhash", blockindex->pnext->GetBlockHash().GetHex()));
170 result.push_back(Pair("flags", strprintf("%s%s", blockindex->IsProofOfStake()? "proof-of-stake" : "proof-of-work", blockindex->GeneratedStakeModifier()? " stake-modifier": "")));
171 result.push_back(Pair("proofhash", blockindex->IsProofOfStake()? blockindex->hashProofOfStake.GetHex() : blockindex->GetBlockHash().GetHex()));
172 result.push_back(Pair("entropybit", (int)blockindex->GetStakeEntropyBit()));
173 result.push_back(Pair("modifier", strprintf("%016"PRI64x, blockindex->nStakeModifier)));
174 result.push_back(Pair("modifierchecksum", strprintf("%08x", blockindex->nStakeModifierChecksum)));
176 BOOST_FOREACH (const CTransaction& tx, block.vtx)
178 if (fPrintTransactionDetail)
180 txinfo.push_back(tx.ToStringShort());
181 txinfo.push_back(DateTimeStrFormat(tx.nTime));
182 BOOST_FOREACH(const CTxIn& txin, tx.vin)
183 txinfo.push_back(txin.ToStringShort());
184 BOOST_FOREACH(const CTxOut& txout, tx.vout)
185 txinfo.push_back(txout.ToStringShort());
188 txinfo.push_back(tx.GetHash().GetHex());
190 result.push_back(Pair("tx", txinfo));
197 /// Note: This interface may still be subject to change.
200 string CRPCTable::help(string strCommand) const
203 set<rpcfn_type> setDone;
204 for (map<string, const CRPCCommand*>::const_iterator mi = mapCommands.begin(); mi != mapCommands.end(); ++mi)
206 const CRPCCommand *pcmd = mi->second;
207 string strMethod = mi->first;
208 // We already filter duplicates, but these deprecated screw up the sort order
209 if (strMethod == "getamountreceived" ||
210 strMethod == "getallreceived" ||
211 strMethod == "getblocknumber" || // deprecated
212 (strMethod.find("label") != string::npos))
214 if (strCommand != "" && strMethod != strCommand)
219 rpcfn_type pfn = pcmd->actor;
220 if (setDone.insert(pfn).second)
221 (*pfn)(params, true);
223 catch (std::exception& e)
225 // Help text is returned in an exception
226 string strHelp = string(e.what());
227 if (strCommand == "")
228 if (strHelp.find('\n') != string::npos)
229 strHelp = strHelp.substr(0, strHelp.find('\n'));
230 strRet += strHelp + "\n";
234 strRet = strprintf("help: unknown command: %s\n", strCommand.c_str());
235 strRet = strRet.substr(0,strRet.size()-1);
239 Value help(const Array& params, bool fHelp)
241 if (fHelp || params.size() > 1)
244 "List commands, or get help for a command.");
247 if (params.size() > 0)
248 strCommand = params[0].get_str();
250 return tableRPC.help(strCommand);
254 Value stop(const Array& params, bool fHelp)
256 if (fHelp || params.size() != 0)
259 "Stop novacoin server.");
260 // Shutdown will take long enough that the response should get back
262 return "novacoin server stopping";
266 Value getblockcount(const Array& params, bool fHelp)
268 if (fHelp || params.size() != 0)
271 "Returns the number of blocks in the longest block chain.");
278 Value getblocknumber(const Array& params, bool fHelp)
280 if (fHelp || params.size() != 0)
283 "Deprecated. Use getblockcount.");
289 Value getconnectioncount(const Array& params, bool fHelp)
291 if (fHelp || params.size() != 0)
293 "getconnectioncount\n"
294 "Returns the number of connections to other nodes.");
296 return (int)vNodes.size();
300 Value getdifficulty(const Array& params, bool fHelp)
302 if (fHelp || params.size() != 0)
305 "Returns difficulty as a multiple of the minimum difficulty.");
308 obj.push_back(Pair("proof-of-work", GetDifficulty()));
309 obj.push_back(Pair("proof-of-stake", GetDifficulty(GetLastBlockIndex(pindexBest, true))));
310 obj.push_back(Pair("search-interval", (int)nLastCoinStakeSearchInterval));
315 Value getgenerate(const Array& params, bool fHelp)
317 if (fHelp || params.size() != 0)
320 "Returns true or false.");
322 return GetBoolArg("-gen");
326 Value setgenerate(const Array& params, bool fHelp)
328 if (fHelp || params.size() < 1 || params.size() > 2)
330 "setgenerate <generate> [genproclimit]\n"
331 "<generate> is true or false to turn generation on or off.\n"
332 "Generation is limited to [genproclimit] processors, -1 is unlimited.");
334 bool fGenerate = true;
335 if (params.size() > 0)
336 fGenerate = params[0].get_bool();
338 if (params.size() > 1)
340 int nGenProcLimit = params[1].get_int();
341 mapArgs["-genproclimit"] = itostr(nGenProcLimit);
342 if (nGenProcLimit == 0)
345 mapArgs["-gen"] = (fGenerate ? "1" : "0");
347 GenerateBitcoins(fGenerate, pwalletMain);
352 Value gethashespersec(const Array& params, bool fHelp)
354 if (fHelp || params.size() != 0)
357 "Returns a recent hashes per second performance measurement while generating.");
359 if (GetTimeMillis() - nHPSTimerStart > 8000)
360 return (boost::int64_t)0;
361 return (boost::int64_t)dHashesPerSec;
365 Value getinfo(const Array& params, bool fHelp)
367 if (fHelp || params.size() != 0)
370 "Returns an object containing various state info.");
373 obj.push_back(Pair("version", FormatFullVersion()));
374 obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION));
375 obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
376 obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
377 obj.push_back(Pair("newmint", ValueFromAmount(pwalletMain->GetNewMint())));
378 obj.push_back(Pair("stake", ValueFromAmount(pwalletMain->GetStake())));
379 obj.push_back(Pair("blocks", (int)nBestHeight));
380 obj.push_back(Pair("moneysupply", ValueFromAmount(pindexBest->nMoneySupply)));
381 obj.push_back(Pair("connections", (int)vNodes.size()));
382 obj.push_back(Pair("proxy", (fUseProxy ? addrProxy.ToStringIPPort() : string())));
383 obj.push_back(Pair("ip", addrSeenByPeer.ToStringIP()));
384 obj.push_back(Pair("difficulty", (double)GetDifficulty()));
385 obj.push_back(Pair("testnet", fTestNet));
386 obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));
387 obj.push_back(Pair("keypoolsize", pwalletMain->GetKeyPoolSize()));
388 obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee)));
389 if (pwalletMain->IsCrypted())
390 obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime / 1000));
391 obj.push_back(Pair("errors", GetWarnings("statusbar")));
396 Value getmininginfo(const Array& params, bool fHelp)
398 if (fHelp || params.size() != 0)
401 "Returns an object containing mining-related information.");
404 obj.push_back(Pair("blocks", (int)nBestHeight));
405 obj.push_back(Pair("currentblocksize",(uint64_t)nLastBlockSize));
406 obj.push_back(Pair("currentblocktx",(uint64_t)nLastBlockTx));
407 obj.push_back(Pair("difficulty", (double)GetDifficulty()));
408 obj.push_back(Pair("errors", GetWarnings("statusbar")));
409 obj.push_back(Pair("generate", GetBoolArg("-gen")));
410 obj.push_back(Pair("genproclimit", (int)GetArg("-genproclimit", -1)));
411 obj.push_back(Pair("hashespersec", gethashespersec(params, false)));
412 obj.push_back(Pair("pooledtx", (uint64_t)mempool.size()));
413 obj.push_back(Pair("testnet", fTestNet));
418 Value getnewaddress(const Array& params, bool fHelp)
420 if (fHelp || params.size() > 1)
422 "getnewaddress [account]\n"
423 "Returns a new novacoin address for receiving payments. "
424 "If [account] is specified (recommended), it is added to the address book "
425 "so payments received with the address will be credited to [account].");
427 // Parse the account first so we don't generate a key if there's an error
429 if (params.size() > 0)
430 strAccount = AccountFromValue(params[0]);
432 if (!pwalletMain->IsLocked())
433 pwalletMain->TopUpKeyPool();
435 // Generate a new key that is added to wallet
436 std::vector<unsigned char> newKey;
437 if (!pwalletMain->GetKeyFromPool(newKey, false))
438 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
439 CBitcoinAddress address(newKey);
441 pwalletMain->SetAddressBookName(address, strAccount);
443 return address.ToString();
447 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
449 CWalletDB walletdb(pwalletMain->strWalletFile);
452 walletdb.ReadAccount(strAccount, account);
454 bool bKeyUsed = false;
456 // Check if the current key has been used
457 if (!account.vchPubKey.empty())
459 CScript scriptPubKey;
460 scriptPubKey.SetBitcoinAddress(account.vchPubKey);
461 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
462 it != pwalletMain->mapWallet.end() && !account.vchPubKey.empty();
465 const CWalletTx& wtx = (*it).second;
466 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
467 if (txout.scriptPubKey == scriptPubKey)
472 // Generate a new key
473 if (account.vchPubKey.empty() || bForceNew || bKeyUsed)
475 if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false))
476 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
478 pwalletMain->SetAddressBookName(CBitcoinAddress(account.vchPubKey), strAccount);
479 walletdb.WriteAccount(strAccount, account);
482 return CBitcoinAddress(account.vchPubKey);
485 Value getaccountaddress(const Array& params, bool fHelp)
487 if (fHelp || params.size() != 1)
489 "getaccountaddress <account>\n"
490 "Returns the current novacoin address for receiving payments to this account.");
492 // Parse the account first so we don't generate a key if there's an error
493 string strAccount = AccountFromValue(params[0]);
497 ret = GetAccountAddress(strAccount).ToString();
504 Value setaccount(const Array& params, bool fHelp)
506 if (fHelp || params.size() < 1 || params.size() > 2)
508 "setaccount <novacoinaddress> <account>\n"
509 "Sets the account associated with the given address.");
511 CBitcoinAddress address(params[0].get_str());
512 if (!address.IsValid())
513 throw JSONRPCError(-5, "Invalid novacoin address");
517 if (params.size() > 1)
518 strAccount = AccountFromValue(params[1]);
520 // Detect when changing the account of an address that is the 'unused current key' of another account:
521 if (pwalletMain->mapAddressBook.count(address))
523 string strOldAccount = pwalletMain->mapAddressBook[address];
524 if (address == GetAccountAddress(strOldAccount))
525 GetAccountAddress(strOldAccount, true);
528 pwalletMain->SetAddressBookName(address, strAccount);
534 Value getaccount(const Array& params, bool fHelp)
536 if (fHelp || params.size() != 1)
538 "getaccount <novacoinaddress>\n"
539 "Returns the account associated with the given address.");
541 CBitcoinAddress address(params[0].get_str());
542 if (!address.IsValid())
543 throw JSONRPCError(-5, "Invalid novacoin address");
546 map<CBitcoinAddress, string>::iterator mi = pwalletMain->mapAddressBook.find(address);
547 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
548 strAccount = (*mi).second;
553 Value getaddressesbyaccount(const Array& params, bool fHelp)
555 if (fHelp || params.size() != 1)
557 "getaddressesbyaccount <account>\n"
558 "Returns the list of addresses for the given account.");
560 string strAccount = AccountFromValue(params[0]);
562 // Find all addresses that have the given account
564 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
566 const CBitcoinAddress& address = item.first;
567 const string& strName = item.second;
568 if (strName == strAccount)
569 ret.push_back(address.ToString());
574 Value settxfee(const Array& params, bool fHelp)
576 if (fHelp || params.size() < 1 || params.size() > 1 || AmountFromValue(params[0]) < MIN_TX_FEE)
578 "settxfee <amount>\n"
579 "<amount> is a real and is rounded to 0.01 (cent)\n"
580 "Minimum and default transaction fee per KB is 1 cent");
582 nTransactionFee = AmountFromValue(params[0]);
583 nTransactionFee = (nTransactionFee / CENT) * CENT; // round to cent
587 Value sendtoaddress(const Array& params, bool fHelp)
589 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
591 "sendtoaddress <novacoinaddress> <amount> [comment] [comment-to]\n"
592 "<amount> is a real and is rounded to the nearest 0.000001\n"
593 "requires wallet passphrase to be set with walletpassphrase first");
594 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
596 "sendtoaddress <novacoinaddress> <amount> [comment] [comment-to]\n"
597 "<amount> is a real and is rounded to the nearest 0.000001");
599 CBitcoinAddress address(params[0].get_str());
600 if (!address.IsValid())
601 throw JSONRPCError(-5, "Invalid novacoin address");
604 int64 nAmount = AmountFromValue(params[1]);
605 if (nAmount < MIN_TXOUT_AMOUNT)
606 throw JSONRPCError(-101, "Send amount too small");
610 if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
611 wtx.mapValue["comment"] = params[2].get_str();
612 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
613 wtx.mapValue["to"] = params[3].get_str();
615 if (pwalletMain->IsLocked())
616 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
618 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
620 throw JSONRPCError(-4, strError);
622 return wtx.GetHash().GetHex();
625 Value signmessage(const Array& params, bool fHelp)
627 if (fHelp || params.size() != 2)
629 "signmessage <novacoinaddress> <message>\n"
630 "Sign a message with the private key of an address");
632 if (pwalletMain->IsLocked())
633 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
635 string strAddress = params[0].get_str();
636 string strMessage = params[1].get_str();
638 CBitcoinAddress addr(strAddress);
640 throw JSONRPCError(-3, "Invalid address");
643 if (!pwalletMain->GetKey(addr, key))
644 throw JSONRPCError(-4, "Private key not available");
646 CDataStream ss(SER_GETHASH, 0);
647 ss << strMessageMagic;
650 vector<unsigned char> vchSig;
651 if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig))
652 throw JSONRPCError(-5, "Sign failed");
654 return EncodeBase64(&vchSig[0], vchSig.size());
657 Value verifymessage(const Array& params, bool fHelp)
659 if (fHelp || params.size() != 3)
661 "verifymessage <novacoinaddress> <signature> <message>\n"
662 "Verify a signed message");
664 string strAddress = params[0].get_str();
665 string strSign = params[1].get_str();
666 string strMessage = params[2].get_str();
668 CBitcoinAddress addr(strAddress);
670 throw JSONRPCError(-3, "Invalid address");
672 bool fInvalid = false;
673 vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
676 throw JSONRPCError(-5, "Malformed base64 encoding");
678 CDataStream ss(SER_GETHASH, 0);
679 ss << strMessageMagic;
683 if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
686 return (CBitcoinAddress(key.GetPubKey()) == addr);
690 Value getreceivedbyaddress(const Array& params, bool fHelp)
692 if (fHelp || params.size() < 1 || params.size() > 2)
694 "getreceivedbyaddress <novacoinaddress> [minconf=1]\n"
695 "Returns the total amount received by <novacoinaddress> in transactions with at least [minconf] confirmations.");
698 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
699 CScript scriptPubKey;
700 if (!address.IsValid())
701 throw JSONRPCError(-5, "Invalid novacoin address");
702 scriptPubKey.SetBitcoinAddress(address);
703 if (!IsMine(*pwalletMain,scriptPubKey))
706 // Minimum confirmations
708 if (params.size() > 1)
709 nMinDepth = params[1].get_int();
713 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
715 const CWalletTx& wtx = (*it).second;
716 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
719 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
720 if (txout.scriptPubKey == scriptPubKey)
721 if (wtx.GetDepthInMainChain() >= nMinDepth)
722 nAmount += txout.nValue;
725 return ValueFromAmount(nAmount);
729 void GetAccountAddresses(string strAccount, set<CBitcoinAddress>& setAddress)
731 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
733 const CBitcoinAddress& address = item.first;
734 const string& strName = item.second;
735 if (strName == strAccount)
736 setAddress.insert(address);
741 Value getreceivedbyaccount(const Array& params, bool fHelp)
743 if (fHelp || params.size() < 1 || params.size() > 2)
745 "getreceivedbyaccount <account> [minconf=1]\n"
746 "Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.");
748 // Minimum confirmations
750 if (params.size() > 1)
751 nMinDepth = params[1].get_int();
753 // Get the set of pub keys assigned to account
754 string strAccount = AccountFromValue(params[0]);
755 set<CBitcoinAddress> setAddress;
756 GetAccountAddresses(strAccount, setAddress);
760 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
762 const CWalletTx& wtx = (*it).second;
763 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
766 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
768 CBitcoinAddress address;
769 if (ExtractAddress(txout.scriptPubKey, address) && pwalletMain->HaveKey(address) && setAddress.count(address))
770 if (wtx.GetDepthInMainChain() >= nMinDepth)
771 nAmount += txout.nValue;
775 return (double)nAmount / (double)COIN;
779 int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth)
783 // Tally wallet transactions
784 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
786 const CWalletTx& wtx = (*it).second;
790 int64 nGenerated, nReceived, nSent, nFee;
791 wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee);
793 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
794 nBalance += nReceived;
795 nBalance += nGenerated - nSent - nFee;
798 // Tally internal accounting entries
799 nBalance += walletdb.GetAccountCreditDebit(strAccount);
804 int64 GetAccountBalance(const string& strAccount, int nMinDepth)
806 CWalletDB walletdb(pwalletMain->strWalletFile);
807 return GetAccountBalance(walletdb, strAccount, nMinDepth);
811 Value getbalance(const Array& params, bool fHelp)
813 if (fHelp || params.size() > 2)
815 "getbalance [account] [minconf=1]\n"
816 "If [account] is not specified, returns the server's total available balance.\n"
817 "If [account] is specified, returns the balance in the account.");
819 if (params.size() == 0)
820 return ValueFromAmount(pwalletMain->GetBalance());
823 if (params.size() > 1)
824 nMinDepth = params[1].get_int();
826 if (params[0].get_str() == "*") {
827 // Calculate total balance a different way from GetBalance()
828 // (GetBalance() sums up all unspent TxOuts)
829 // getbalance and getbalance '*' should always return the same number.
831 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
833 const CWalletTx& wtx = (*it).second;
837 int64 allGeneratedImmature, allGeneratedMature, allFee;
838 allGeneratedImmature = allGeneratedMature = allFee = 0;
839 string strSentAccount;
840 list<pair<CBitcoinAddress, int64> > listReceived;
841 list<pair<CBitcoinAddress, int64> > listSent;
842 wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
843 if (wtx.GetDepthInMainChain() >= nMinDepth)
845 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listReceived)
846 nBalance += r.second;
848 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listSent)
849 nBalance -= r.second;
851 nBalance += allGeneratedMature;
853 return ValueFromAmount(nBalance);
856 string strAccount = AccountFromValue(params[0]);
858 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
860 return ValueFromAmount(nBalance);
864 Value getpowreward(const Array& params, bool fHelp)
866 if (fHelp || params.size() > 1)
868 "getpowreward [nBits]\n"
869 "Returns PoW reward for block with provided difficulty.");
871 if (params.size() == 0)
872 throw JSONRPCError(-200, "no bits provided");
874 std::string sBits = params[0].get_str();
876 if (sBits.length() != 8)
877 throw JSONRPCError(-201, "incorrect bits provided");
879 unsigned int nBits = BitsHex(sBits);
881 return (int)GetProofOfWorkReward(nBits);
886 Value movecmd(const Array& params, bool fHelp)
888 if (fHelp || params.size() < 3 || params.size() > 5)
890 "move <fromaccount> <toaccount> <amount> [minconf=1] [comment]\n"
891 "Move from one account in your wallet to another.");
893 string strFrom = AccountFromValue(params[0]);
894 string strTo = AccountFromValue(params[1]);
895 int64 nAmount = AmountFromValue(params[2]);
896 if (params.size() > 3)
897 // unused parameter, used to be nMinDepth, keep type-checking it though
898 (void)params[3].get_int();
900 if (params.size() > 4)
901 strComment = params[4].get_str();
903 CWalletDB walletdb(pwalletMain->strWalletFile);
904 if (!walletdb.TxnBegin())
905 throw JSONRPCError(-20, "database error");
907 int64 nNow = GetAdjustedTime();
910 CAccountingEntry debit;
911 debit.strAccount = strFrom;
912 debit.nCreditDebit = -nAmount;
914 debit.strOtherAccount = strTo;
915 debit.strComment = strComment;
916 walletdb.WriteAccountingEntry(debit);
919 CAccountingEntry credit;
920 credit.strAccount = strTo;
921 credit.nCreditDebit = nAmount;
923 credit.strOtherAccount = strFrom;
924 credit.strComment = strComment;
925 walletdb.WriteAccountingEntry(credit);
927 if (!walletdb.TxnCommit())
928 throw JSONRPCError(-20, "database error");
934 Value sendfrom(const Array& params, bool fHelp)
936 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
938 "sendfrom <fromaccount> <tonovacoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
939 "<amount> is a real and is rounded to the nearest 0.000001\n"
940 "requires wallet passphrase to be set with walletpassphrase first");
941 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
943 "sendfrom <fromaccount> <tonovacoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
944 "<amount> is a real and is rounded to the nearest 0.000001");
946 string strAccount = AccountFromValue(params[0]);
947 CBitcoinAddress address(params[1].get_str());
948 if (!address.IsValid())
949 throw JSONRPCError(-5, "Invalid novacoin address");
950 int64 nAmount = AmountFromValue(params[2]);
951 if (nAmount < MIN_TXOUT_AMOUNT)
952 throw JSONRPCError(-101, "Send amount too small");
954 if (params.size() > 3)
955 nMinDepth = params[3].get_int();
958 wtx.strFromAccount = strAccount;
959 if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
960 wtx.mapValue["comment"] = params[4].get_str();
961 if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
962 wtx.mapValue["to"] = params[5].get_str();
964 if (pwalletMain->IsLocked())
965 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
968 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
969 if (nAmount > nBalance)
970 throw JSONRPCError(-6, "Account has insufficient funds");
973 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
975 throw JSONRPCError(-4, strError);
977 return wtx.GetHash().GetHex();
981 Value sendmany(const Array& params, bool fHelp)
983 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
985 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
986 "amounts are double-precision floating point numbers\n"
987 "requires wallet passphrase to be set with walletpassphrase first");
988 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
990 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
991 "amounts are double-precision floating point numbers");
993 string strAccount = AccountFromValue(params[0]);
994 Object sendTo = params[1].get_obj();
996 if (params.size() > 2)
997 nMinDepth = params[2].get_int();
1000 wtx.strFromAccount = strAccount;
1001 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
1002 wtx.mapValue["comment"] = params[3].get_str();
1004 set<CBitcoinAddress> setAddress;
1005 vector<pair<CScript, int64> > vecSend;
1007 int64 totalAmount = 0;
1008 BOOST_FOREACH(const Pair& s, sendTo)
1010 CBitcoinAddress address(s.name_);
1011 if (!address.IsValid())
1012 throw JSONRPCError(-5, string("Invalid novacoin address:")+s.name_);
1014 if (setAddress.count(address))
1015 throw JSONRPCError(-8, string("Invalid parameter, duplicated address: ")+s.name_);
1016 setAddress.insert(address);
1018 CScript scriptPubKey;
1019 scriptPubKey.SetBitcoinAddress(address);
1020 int64 nAmount = AmountFromValue(s.value_);
1021 if (nAmount < MIN_TXOUT_AMOUNT)
1022 throw JSONRPCError(-101, "Send amount too small");
1023 totalAmount += nAmount;
1025 vecSend.push_back(make_pair(scriptPubKey, nAmount));
1028 if (pwalletMain->IsLocked())
1029 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
1030 if (fWalletUnlockMintOnly)
1031 throw JSONRPCError(-13, "Error: Wallet unlocked for block minting only.");
1034 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
1035 if (totalAmount > nBalance)
1036 throw JSONRPCError(-6, "Account has insufficient funds");
1039 CReserveKey keyChange(pwalletMain);
1040 int64 nFeeRequired = 0;
1041 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
1044 if (totalAmount + nFeeRequired > pwalletMain->GetBalance())
1045 throw JSONRPCError(-6, "Insufficient funds");
1046 throw JSONRPCError(-4, "Transaction creation failed");
1048 if (!pwalletMain->CommitTransaction(wtx, keyChange))
1049 throw JSONRPCError(-4, "Transaction commit failed");
1051 return wtx.GetHash().GetHex();
1054 Value addmultisigaddress(const Array& params, bool fHelp)
1056 if (fHelp || params.size() < 2 || params.size() > 3)
1058 string msg = "addmultisigaddress <nrequired> <'[\"key\",\"key\"]'> [account]\n"
1059 "Add a nrequired-to-sign multisignature address to the wallet\"\n"
1060 "each key is a bitcoin address or hex-encoded public key\n"
1061 "If [account] is specified, assign address to [account].";
1062 throw runtime_error(msg);
1065 int nRequired = params[0].get_int();
1066 const Array& keys = params[1].get_array();
1068 if (params.size() > 2)
1069 strAccount = AccountFromValue(params[2]);
1071 // Gather public keys
1073 throw runtime_error("a multisignature address must require at least one key to redeem");
1074 if ((int)keys.size() < nRequired)
1075 throw runtime_error(
1076 strprintf("not enough keys supplied "
1077 "(got %d keys, but need at least %d to redeem)", keys.size(), nRequired));
1078 std::vector<CKey> pubkeys;
1079 pubkeys.resize(keys.size());
1080 for (unsigned int i = 0; i < keys.size(); i++)
1082 const std::string& ks = keys[i].get_str();
1084 // Case 1: bitcoin address and we have full public key:
1085 CBitcoinAddress address(ks);
1086 if (address.IsValid())
1088 if (address.IsScript())
1089 throw runtime_error(
1090 strprintf("%s is a pay-to-script address",ks.c_str()));
1091 std::vector<unsigned char> vchPubKey;
1092 if (!pwalletMain->GetPubKey(address, vchPubKey))
1093 throw runtime_error(
1094 strprintf("no full public key for address %s",ks.c_str()));
1095 if (vchPubKey.empty() || !pubkeys[i].SetPubKey(vchPubKey))
1096 throw runtime_error(" Invalid public key: "+ks);
1099 // Case 2: hex public key
1102 vector<unsigned char> vchPubKey = ParseHex(ks);
1103 if (vchPubKey.empty() || !pubkeys[i].SetPubKey(vchPubKey))
1104 throw runtime_error(" Invalid public key: "+ks);
1108 throw runtime_error(" Invalid public key: "+ks);
1112 // Construct using pay-to-script-hash:
1114 inner.SetMultisig(nRequired, pubkeys);
1116 uint160 scriptHash = Hash160(inner);
1117 CScript scriptPubKey;
1118 scriptPubKey.SetPayToScriptHash(inner);
1119 pwalletMain->AddCScript(inner);
1120 CBitcoinAddress address;
1121 address.SetScriptHash160(scriptHash);
1123 pwalletMain->SetAddressBookName(address, strAccount);
1124 return address.ToString();
1135 nConf = std::numeric_limits<int>::max();
1139 Value ListReceived(const Array& params, bool fByAccounts)
1141 // Minimum confirmations
1143 if (params.size() > 0)
1144 nMinDepth = params[0].get_int();
1146 // Whether to include empty accounts
1147 bool fIncludeEmpty = false;
1148 if (params.size() > 1)
1149 fIncludeEmpty = params[1].get_bool();
1152 map<CBitcoinAddress, tallyitem> mapTally;
1153 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1155 const CWalletTx& wtx = (*it).second;
1157 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
1160 int nDepth = wtx.GetDepthInMainChain();
1161 if (nDepth < nMinDepth)
1164 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
1166 CBitcoinAddress address;
1167 if (!ExtractAddress(txout.scriptPubKey, address) || !pwalletMain->HaveKey(address) || !address.IsValid())
1170 tallyitem& item = mapTally[address];
1171 item.nAmount += txout.nValue;
1172 item.nConf = min(item.nConf, nDepth);
1178 map<string, tallyitem> mapAccountTally;
1179 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
1181 const CBitcoinAddress& address = item.first;
1182 const string& strAccount = item.second;
1183 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
1184 if (it == mapTally.end() && !fIncludeEmpty)
1188 int nConf = std::numeric_limits<int>::max();
1189 if (it != mapTally.end())
1191 nAmount = (*it).second.nAmount;
1192 nConf = (*it).second.nConf;
1197 tallyitem& item = mapAccountTally[strAccount];
1198 item.nAmount += nAmount;
1199 item.nConf = min(item.nConf, nConf);
1204 obj.push_back(Pair("address", address.ToString()));
1205 obj.push_back(Pair("account", strAccount));
1206 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1207 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1214 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
1216 int64 nAmount = (*it).second.nAmount;
1217 int nConf = (*it).second.nConf;
1219 obj.push_back(Pair("account", (*it).first));
1220 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1221 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1229 Value listreceivedbyaddress(const Array& params, bool fHelp)
1231 if (fHelp || params.size() > 2)
1232 throw runtime_error(
1233 "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
1234 "[minconf] is the minimum number of confirmations before payments are included.\n"
1235 "[includeempty] whether to include addresses that haven't received any payments.\n"
1236 "Returns an array of objects containing:\n"
1237 " \"address\" : receiving address\n"
1238 " \"account\" : the account of the receiving address\n"
1239 " \"amount\" : total amount received by the address\n"
1240 " \"confirmations\" : number of confirmations of the most recent transaction included");
1242 return ListReceived(params, false);
1245 Value listreceivedbyaccount(const Array& params, bool fHelp)
1247 if (fHelp || params.size() > 2)
1248 throw runtime_error(
1249 "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
1250 "[minconf] is the minimum number of confirmations before payments are included.\n"
1251 "[includeempty] whether to include accounts that haven't received any payments.\n"
1252 "Returns an array of objects containing:\n"
1253 " \"account\" : the account of the receiving addresses\n"
1254 " \"amount\" : total amount received by addresses with this account\n"
1255 " \"confirmations\" : number of confirmations of the most recent transaction included");
1257 return ListReceived(params, true);
1260 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret)
1262 int64 nGeneratedImmature, nGeneratedMature, nFee;
1263 string strSentAccount;
1264 list<pair<CBitcoinAddress, int64> > listReceived;
1265 list<pair<CBitcoinAddress, int64> > listSent;
1267 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1269 bool fAllAccounts = (strAccount == string("*"));
1271 // Generated blocks assigned to account ""
1272 if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == ""))
1275 entry.push_back(Pair("account", string("")));
1276 if (nGeneratedImmature)
1278 entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
1279 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
1283 entry.push_back(Pair("category", "generate"));
1284 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
1287 WalletTxToJSON(wtx, entry);
1288 ret.push_back(entry);
1292 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1294 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1297 entry.push_back(Pair("account", strSentAccount));
1298 entry.push_back(Pair("address", s.first.ToString()));
1299 entry.push_back(Pair("category", "send"));
1300 entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1301 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1303 WalletTxToJSON(wtx, entry);
1304 ret.push_back(entry);
1309 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1311 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1314 if (pwalletMain->mapAddressBook.count(r.first))
1315 account = pwalletMain->mapAddressBook[r.first];
1316 if (fAllAccounts || (account == strAccount))
1319 entry.push_back(Pair("account", account));
1320 entry.push_back(Pair("address", r.first.ToString()));
1321 entry.push_back(Pair("category", "receive"));
1322 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1324 WalletTxToJSON(wtx, entry);
1325 ret.push_back(entry);
1331 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1333 bool fAllAccounts = (strAccount == string("*"));
1335 if (fAllAccounts || acentry.strAccount == strAccount)
1338 entry.push_back(Pair("account", acentry.strAccount));
1339 entry.push_back(Pair("category", "move"));
1340 entry.push_back(Pair("time", (boost::int64_t)acentry.nTime));
1341 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1342 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1343 entry.push_back(Pair("comment", acentry.strComment));
1344 ret.push_back(entry);
1348 Value listtransactions(const Array& params, bool fHelp)
1350 if (fHelp || params.size() > 3)
1351 throw runtime_error(
1352 "listtransactions [account] [count=10] [from=0]\n"
1353 "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1355 string strAccount = "*";
1356 if (params.size() > 0)
1357 strAccount = params[0].get_str();
1359 if (params.size() > 1)
1360 nCount = params[1].get_int();
1362 if (params.size() > 2)
1363 nFrom = params[2].get_int();
1366 throw JSONRPCError(-8, "Negative count");
1368 throw JSONRPCError(-8, "Negative from");
1371 CWalletDB walletdb(pwalletMain->strWalletFile);
1373 // First: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap.
1374 typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
1375 typedef multimap<int64, TxPair > TxItems;
1378 // Note: maintaining indices in the database of (account,time) --> txid and (account, time) --> acentry
1379 // would make this much faster for applications that do this a lot.
1380 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1382 CWalletTx* wtx = &((*it).second);
1383 txByTime.insert(make_pair(wtx->GetTxTime(), TxPair(wtx, (CAccountingEntry*)0)));
1385 list<CAccountingEntry> acentries;
1386 walletdb.ListAccountCreditDebit(strAccount, acentries);
1387 BOOST_FOREACH(CAccountingEntry& entry, acentries)
1389 txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
1392 // iterate backwards until we have nCount items to return:
1393 for (TxItems::reverse_iterator it = txByTime.rbegin(); it != txByTime.rend(); ++it)
1395 CWalletTx *const pwtx = (*it).second.first;
1397 ListTransactions(*pwtx, strAccount, 0, true, ret);
1398 CAccountingEntry *const pacentry = (*it).second.second;
1400 AcentryToJSON(*pacentry, strAccount, ret);
1402 if (ret.size() >= (nCount+nFrom)) break;
1404 // ret is newest to oldest
1406 if (nFrom > (int)ret.size())
1408 if ((nFrom + nCount) > (int)ret.size())
1409 nCount = ret.size() - nFrom;
1410 Array::iterator first = ret.begin();
1411 std::advance(first, nFrom);
1412 Array::iterator last = ret.begin();
1413 std::advance(last, nFrom+nCount);
1415 if (last != ret.end()) ret.erase(last, ret.end());
1416 if (first != ret.begin()) ret.erase(ret.begin(), first);
1418 std::reverse(ret.begin(), ret.end()); // Return oldest to newest
1423 Value listaccounts(const Array& params, bool fHelp)
1425 if (fHelp || params.size() > 1)
1426 throw runtime_error(
1427 "listaccounts [minconf=1]\n"
1428 "Returns Object that has account names as keys, account balances as values.");
1431 if (params.size() > 0)
1432 nMinDepth = params[0].get_int();
1434 map<string, int64> mapAccountBalances;
1435 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& entry, pwalletMain->mapAddressBook) {
1436 if (pwalletMain->HaveKey(entry.first)) // This address belongs to me
1437 mapAccountBalances[entry.second] = 0;
1440 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1442 const CWalletTx& wtx = (*it).second;
1443 int64 nGeneratedImmature, nGeneratedMature, nFee;
1444 string strSentAccount;
1445 list<pair<CBitcoinAddress, int64> > listReceived;
1446 list<pair<CBitcoinAddress, int64> > listSent;
1447 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1448 mapAccountBalances[strSentAccount] -= nFee;
1449 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1450 mapAccountBalances[strSentAccount] -= s.second;
1451 if (wtx.GetDepthInMainChain() >= nMinDepth)
1453 mapAccountBalances[""] += nGeneratedMature;
1454 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1455 if (pwalletMain->mapAddressBook.count(r.first))
1456 mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1458 mapAccountBalances[""] += r.second;
1462 list<CAccountingEntry> acentries;
1463 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1464 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1465 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1468 BOOST_FOREACH(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) {
1469 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1474 Value listsinceblock(const Array& params, bool fHelp)
1477 throw runtime_error(
1478 "listsinceblock [blockhash] [target-confirmations]\n"
1479 "Get all transactions in blocks since block [blockhash], or all transactions if omitted");
1481 CBlockIndex *pindex = NULL;
1482 int target_confirms = 1;
1484 if (params.size() > 0)
1486 uint256 blockId = 0;
1488 blockId.SetHex(params[0].get_str());
1489 pindex = CBlockLocator(blockId).GetBlockIndex();
1492 if (params.size() > 1)
1494 target_confirms = params[1].get_int();
1496 if (target_confirms < 1)
1497 throw JSONRPCError(-8, "Invalid parameter");
1500 int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1;
1504 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1506 CWalletTx tx = (*it).second;
1508 if (depth == -1 || tx.GetDepthInMainChain() < depth)
1509 ListTransactions(tx, "*", 0, true, transactions);
1514 if (target_confirms == 1)
1516 lastblock = hashBestChain;
1520 int target_height = pindexBest->nHeight + 1 - target_confirms;
1523 for (block = pindexBest;
1524 block && block->nHeight > target_height;
1525 block = block->pprev) { }
1527 lastblock = block ? block->GetBlockHash() : 0;
1531 ret.push_back(Pair("transactions", transactions));
1532 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1537 Value gettransaction(const Array& params, bool fHelp)
1539 if (fHelp || params.size() != 1)
1540 throw runtime_error(
1541 "gettransaction <txid>\n"
1542 "Get detailed information about <txid>");
1545 hash.SetHex(params[0].get_str());
1549 if (!pwalletMain->mapWallet.count(hash))
1550 throw JSONRPCError(-5, "Invalid or non-wallet transaction id");
1551 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1553 int64 nCredit = wtx.GetCredit();
1554 int64 nDebit = wtx.GetDebit();
1555 int64 nNet = nCredit - nDebit;
1556 int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
1558 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1560 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1562 WalletTxToJSON(pwalletMain->mapWallet[hash], entry);
1565 ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
1566 entry.push_back(Pair("details", details));
1572 Value backupwallet(const Array& params, bool fHelp)
1574 if (fHelp || params.size() != 1)
1575 throw runtime_error(
1576 "backupwallet <destination>\n"
1577 "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1579 string strDest = params[0].get_str();
1580 BackupWallet(*pwalletMain, strDest);
1586 Value keypoolrefill(const Array& params, bool fHelp)
1588 if (pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1589 throw runtime_error(
1591 "Fills the keypool, requires wallet passphrase to be set.");
1592 if (!pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1593 throw runtime_error(
1595 "Fills the keypool.");
1597 if (pwalletMain->IsLocked())
1598 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
1600 pwalletMain->TopUpKeyPool();
1602 if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100))
1603 throw JSONRPCError(-4, "Error refreshing keypool.");
1609 void ThreadTopUpKeyPool(void* parg)
1611 pwalletMain->TopUpKeyPool();
1614 void ThreadCleanWalletPassphrase(void* parg)
1616 int64 nMyWakeTime = GetTimeMillis() + *((int64*)parg) * 1000;
1618 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1620 if (nWalletUnlockTime == 0)
1622 nWalletUnlockTime = nMyWakeTime;
1626 if (nWalletUnlockTime==0)
1628 int64 nToSleep = nWalletUnlockTime - GetTimeMillis();
1632 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1634 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1638 if (nWalletUnlockTime)
1640 nWalletUnlockTime = 0;
1641 pwalletMain->Lock();
1646 if (nWalletUnlockTime < nMyWakeTime)
1647 nWalletUnlockTime = nMyWakeTime;
1650 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1652 delete (int64*)parg;
1655 Value walletpassphrase(const Array& params, bool fHelp)
1657 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 3))
1658 throw runtime_error(
1659 "walletpassphrase <passphrase> <timeout> [mintonly]\n"
1660 "Stores the wallet decryption key in memory for <timeout> seconds.\n"
1661 "mintonly is optional true/false allowing only block minting.");
1664 if (!pwalletMain->IsCrypted())
1665 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1667 if (!pwalletMain->IsLocked())
1668 throw JSONRPCError(-17, "Error: Wallet is already unlocked, use walletlock first if need to change unlock settings.");
1670 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1671 SecureString strWalletPass;
1672 strWalletPass.reserve(100);
1673 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1674 // Alternately, find a way to make params[0] mlock()'d to begin with.
1675 strWalletPass = params[0].get_str().c_str();
1677 if (strWalletPass.length() > 0)
1679 if (!pwalletMain->Unlock(strWalletPass))
1680 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1683 throw runtime_error(
1684 "walletpassphrase <passphrase> <timeout>\n"
1685 "Stores the wallet decryption key in memory for <timeout> seconds.");
1687 CreateThread(ThreadTopUpKeyPool, NULL);
1688 int64* pnSleepTime = new int64(params[1].get_int64());
1689 CreateThread(ThreadCleanWalletPassphrase, pnSleepTime);
1691 // ppcoin: if user OS account compromised prevent trivial sendmoney commands
1692 if (params.size() > 2)
1693 fWalletUnlockMintOnly = params[2].get_bool();
1695 fWalletUnlockMintOnly = false;
1701 Value walletpassphrasechange(const Array& params, bool fHelp)
1703 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1704 throw runtime_error(
1705 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1706 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1709 if (!pwalletMain->IsCrypted())
1710 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1712 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1713 // Alternately, find a way to make params[0] mlock()'d to begin with.
1714 SecureString strOldWalletPass;
1715 strOldWalletPass.reserve(100);
1716 strOldWalletPass = params[0].get_str().c_str();
1718 SecureString strNewWalletPass;
1719 strNewWalletPass.reserve(100);
1720 strNewWalletPass = params[1].get_str().c_str();
1722 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1723 throw runtime_error(
1724 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1725 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1727 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1728 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1734 Value walletlock(const Array& params, bool fHelp)
1736 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1737 throw runtime_error(
1739 "Removes the wallet encryption key from memory, locking the wallet.\n"
1740 "After calling this method, you will need to call walletpassphrase again\n"
1741 "before being able to call any methods which require the wallet to be unlocked.");
1744 if (!pwalletMain->IsCrypted())
1745 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called.");
1748 LOCK(cs_nWalletUnlockTime);
1749 pwalletMain->Lock();
1750 nWalletUnlockTime = 0;
1757 Value encryptwallet(const Array& params, bool fHelp)
1759 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1760 throw runtime_error(
1761 "encryptwallet <passphrase>\n"
1762 "Encrypts the wallet with <passphrase>.");
1765 if (pwalletMain->IsCrypted())
1766 throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
1768 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1769 // Alternately, find a way to make params[0] mlock()'d to begin with.
1770 SecureString strWalletPass;
1771 strWalletPass.reserve(100);
1772 strWalletPass = params[0].get_str().c_str();
1774 if (strWalletPass.length() < 1)
1775 throw runtime_error(
1776 "encryptwallet <passphrase>\n"
1777 "Encrypts the wallet with <passphrase>.");
1779 if (!pwalletMain->EncryptWallet(strWalletPass))
1780 throw JSONRPCError(-16, "Error: Failed to encrypt the wallet.");
1782 // BDB seems to have a bad habit of writing old data into
1783 // slack space in .dat files; that is bad if the old data is
1784 // unencrypted private keys. So:
1786 return "wallet encrypted; novacoin server stopping, restart to run with encrypted wallet";
1790 Value validateaddress(const Array& params, bool fHelp)
1792 if (fHelp || params.size() != 1)
1793 throw runtime_error(
1794 "validateaddress <novacoinaddress>\n"
1795 "Return information about <novacoinaddress>.");
1797 CBitcoinAddress address(params[0].get_str());
1798 bool isValid = address.IsValid();
1801 ret.push_back(Pair("isvalid", isValid));
1804 // Call Hash160ToAddress() so we always return current ADDRESSVERSION
1805 // version of the address:
1806 string currentAddress = address.ToString();
1807 ret.push_back(Pair("address", currentAddress));
1808 if (pwalletMain->HaveKey(address))
1810 ret.push_back(Pair("ismine", true));
1811 std::vector<unsigned char> vchPubKey;
1812 pwalletMain->GetPubKey(address, vchPubKey);
1813 ret.push_back(Pair("pubkey", HexStr(vchPubKey)));
1815 key.SetPubKey(vchPubKey);
1816 ret.push_back(Pair("iscompressed", key.IsCompressed()));
1818 else if (pwalletMain->HaveCScript(address.GetHash160()))
1820 ret.push_back(Pair("isscript", true));
1822 pwalletMain->GetCScript(address.GetHash160(), subscript);
1823 ret.push_back(Pair("ismine", ::IsMine(*pwalletMain, subscript)));
1824 std::vector<CBitcoinAddress> addresses;
1825 txnouttype whichType;
1827 ExtractAddresses(subscript, whichType, addresses, nRequired);
1828 ret.push_back(Pair("script", GetTxnOutputType(whichType)));
1830 BOOST_FOREACH(const CBitcoinAddress& addr, addresses)
1831 a.push_back(addr.ToString());
1832 ret.push_back(Pair("addresses", a));
1833 if (whichType == TX_MULTISIG)
1834 ret.push_back(Pair("sigsrequired", nRequired));
1837 ret.push_back(Pair("ismine", false));
1838 if (pwalletMain->mapAddressBook.count(address))
1839 ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
1844 Value validatepubkey(const Array& params, bool fHelp)
1846 if (fHelp || !params.size() || params.size() > 2)
1847 throw runtime_error(
1848 "validatepubkey <novacoinpubkey>\n"
1849 "Return information about <novacoinpubkey>.");
1851 std::vector<unsigned char> vchPubKey = ParseHex(params[0].get_str());
1854 if(vchPubKey.size() == 33) // Compressed key
1855 isValid = (vchPubKey[0] == 0x02 || vchPubKey[0] == 0x03);
1856 else if(vchPubKey.size() == 65) // Uncompressed key
1857 isValid = vchPubKey[0] == 0x04;
1861 CBitcoinAddress address(vchPubKey);
1862 isValid = isValid ? address.IsValid() : false;
1865 ret.push_back(Pair("isvalid", isValid));
1868 // Call Hash160ToAddress() so we always return current ADDRESSVERSION
1869 // version of the address:
1870 string currentAddress = address.ToString();
1871 ret.push_back(Pair("address", currentAddress));
1872 if (pwalletMain->HaveKey(address))
1874 ret.push_back(Pair("ismine", true));
1876 key.SetPubKey(vchPubKey);
1877 ret.push_back(Pair("iscompressed", key.IsCompressed()));
1880 ret.push_back(Pair("ismine", false));
1881 if (pwalletMain->mapAddressBook.count(address))
1882 ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
1888 Value getwork(const Array& params, bool fHelp)
1890 if (fHelp || params.size() > 1)
1891 throw runtime_error(
1893 "If [data] is not specified, returns formatted hash data to work on:\n"
1894 " \"midstate\" : precomputed hash state after hashing the first half of the data (DEPRECATED)\n" // deprecated
1895 " \"data\" : block data\n"
1896 " \"hash1\" : formatted hash buffer for second hash (DEPRECATED)\n" // deprecated
1897 " \"target\" : little endian hash target\n"
1898 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1901 throw JSONRPCError(-9, "NovaCoin is not connected!");
1903 if (IsInitialBlockDownload())
1904 throw JSONRPCError(-10, "NovaCoin is downloading blocks...");
1906 typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
1907 static mapNewBlock_t mapNewBlock;
1908 static vector<CBlock*> vNewBlock;
1909 static CReserveKey reservekey(pwalletMain);
1911 if (params.size() == 0)
1914 static unsigned int nTransactionsUpdatedLast;
1915 static CBlockIndex* pindexPrev;
1916 static int64 nStart;
1917 static CBlock* pblock;
1918 if (pindexPrev != pindexBest ||
1919 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
1921 if (pindexPrev != pindexBest)
1923 // Deallocate old blocks since they're obsolete now
1924 mapNewBlock.clear();
1925 BOOST_FOREACH(CBlock* pblock, vNewBlock)
1929 nTransactionsUpdatedLast = nTransactionsUpdated;
1930 pindexPrev = pindexBest;
1934 pblock = CreateNewBlock(pwalletMain);
1936 throw JSONRPCError(-7, "Out of memory");
1937 vNewBlock.push_back(pblock);
1941 pblock->UpdateTime(pindexPrev);
1944 // Update nExtraNonce
1945 static unsigned int nExtraNonce = 0;
1946 IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
1949 mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
1951 // Prebuild hash buffers
1955 FormatHashBuffers(pblock, pmidstate, pdata, phash1);
1957 uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
1960 result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate)))); // deprecated
1961 result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata))));
1962 result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1)))); // deprecated
1963 result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
1969 vector<unsigned char> vchData = ParseHex(params[0].get_str());
1970 if (vchData.size() != 128)
1971 throw JSONRPCError(-8, "Invalid parameter");
1972 CBlock* pdata = (CBlock*)&vchData[0];
1975 for (int i = 0; i < 128/4; i++)
1976 ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]);
1979 if (!mapNewBlock.count(pdata->hashMerkleRoot))
1981 CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
1983 pblock->nTime = pdata->nTime;
1984 pblock->nNonce = pdata->nNonce;
1985 pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
1986 pblock->hashMerkleRoot = pblock->BuildMerkleTree();
1987 if (!pblock->SignBlock(*pwalletMain))
1988 throw JSONRPCError(-100, "Unable to sign block, wallet locked?");
1990 return CheckWork(pblock, *pwalletMain, reservekey);
1994 Value getblocktemplate(const Array& params, bool fHelp)
1996 if (fHelp || params.size() > 1)
1997 throw runtime_error(
1998 "getblocktemplate [params]\n"
1999 "Returns data needed to construct a block to work on:\n"
2000 " \"version\" : block version\n"
2001 " \"previousblockhash\" : hash of current highest block\n"
2002 " \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
2003 " \"coinbaseaux\" : data that should be included in coinbase\n"
2004 " \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
2005 " \"target\" : hash target\n"
2006 " \"mintime\" : minimum timestamp appropriate for next block\n"
2007 " \"curtime\" : current timestamp\n"
2008 " \"mutable\" : list of ways the block template may be changed\n"
2009 " \"noncerange\" : range of valid nonces\n"
2010 " \"sigoplimit\" : limit of sigops in blocks\n"
2011 " \"sizelimit\" : limit of block size\n"
2012 " \"bits\" : compressed target of next block\n"
2013 " \"height\" : height of the next block\n"
2014 "See https://en.bitcoin.it/wiki/BIP_0022 for full specification.");
2016 std::string strMode = "template";
2017 if (params.size() > 0)
2019 const Object& oparam = params[0].get_obj();
2020 const Value& modeval = find_value(oparam, "mode");
2021 if (modeval.type() == str_type)
2022 strMode = modeval.get_str();
2024 throw JSONRPCError(-8, "Invalid mode");
2027 if (strMode != "template")
2028 throw JSONRPCError(-8, "Invalid mode");
2031 throw JSONRPCError(-9, "NovaCoin is not connected!");
2033 if (IsInitialBlockDownload())
2034 throw JSONRPCError(-10, "NovaCoin is downloading blocks...");
2036 static CReserveKey reservekey(pwalletMain);
2039 static unsigned int nTransactionsUpdatedLast;
2040 static CBlockIndex* pindexPrev;
2041 static int64 nStart;
2042 static CBlock* pblock;
2043 if (pindexPrev != pindexBest ||
2044 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5))
2046 // Clear pindexPrev so future calls make a new block, despite any failures from here on
2049 // Store the pindexBest used before CreateNewBlock, to avoid races
2050 nTransactionsUpdatedLast = nTransactionsUpdated;
2051 CBlockIndex* pindexPrevNew = pindexBest;
2060 pblock = CreateNewBlock(pwalletMain);
2062 throw JSONRPCError(-7, "Out of memory");
2064 // Need to update only after we know CreateNewBlock succeeded
2065 pindexPrev = pindexPrevNew;
2069 pblock->UpdateTime(pindexPrev);
2073 map<uint256, int64_t> setTxIndex;
2076 BOOST_FOREACH (CTransaction& tx, pblock->vtx)
2078 uint256 txHash = tx.GetHash();
2079 setTxIndex[txHash] = i++;
2081 if (tx.IsCoinBase() || tx.IsCoinStake())
2086 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
2088 entry.push_back(Pair("data", HexStr(ssTx.begin(), ssTx.end())));
2090 entry.push_back(Pair("hash", txHash.GetHex()));
2092 MapPrevTx mapInputs;
2093 map<uint256, CTxIndex> mapUnused;
2094 bool fInvalid = false;
2095 if (tx.FetchInputs(txdb, mapUnused, false, false, mapInputs, fInvalid))
2097 entry.push_back(Pair("fee", (int64_t)(tx.GetValueIn(mapInputs) - tx.GetValueOut())));
2100 BOOST_FOREACH (MapPrevTx::value_type& inp, mapInputs)
2102 if (setTxIndex.count(inp.first))
2103 deps.push_back(setTxIndex[inp.first]);
2105 entry.push_back(Pair("depends", deps));
2107 int64_t nSigOps = tx.GetLegacySigOpCount();
2108 nSigOps += tx.GetP2SHSigOpCount(mapInputs);
2109 entry.push_back(Pair("sigops", nSigOps));
2112 transactions.push_back(entry);
2116 aux.push_back(Pair("flags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end())));
2118 uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
2120 static Array aMutable;
2121 if (aMutable.empty())
2123 aMutable.push_back("time");
2124 aMutable.push_back("transactions");
2125 aMutable.push_back("prevblock");
2129 result.push_back(Pair("version", pblock->nVersion));
2130 result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
2131 result.push_back(Pair("transactions", transactions));
2132 result.push_back(Pair("coinbaseaux", aux));
2133 result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
2134 result.push_back(Pair("target", hashTarget.GetHex()));
2135 result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1));
2136 result.push_back(Pair("mutable", aMutable));
2137 result.push_back(Pair("noncerange", "00000000ffffffff"));
2138 result.push_back(Pair("sigoplimit", (int64_t)MAX_BLOCK_SIGOPS));
2139 result.push_back(Pair("sizelimit", (int64_t)MAX_BLOCK_SIZE));
2140 result.push_back(Pair("curtime", (int64_t)pblock->nTime));
2141 result.push_back(Pair("bits", HexBits(pblock->nBits)));
2142 result.push_back(Pair("height", (int64_t)(pindexPrev->nHeight+1)));
2147 Value submitblock(const Array& params, bool fHelp)
2149 if (fHelp || params.size() < 1 || params.size() > 2)
2150 throw runtime_error(
2151 "submitblock <hex data> [optional-params-obj]\n"
2152 "[optional-params-obj] parameter is currently ignored.\n"
2153 "Attempts to submit new block to network.\n"
2154 "See https://en.bitcoin.it/wiki/BIP_0022 for full specification.");
2156 vector<unsigned char> blockData(ParseHex(params[0].get_str()));
2157 CDataStream ssBlock(blockData, SER_NETWORK, PROTOCOL_VERSION);
2162 catch (std::exception &e) {
2163 throw JSONRPCError(-22, "Block decode failed");
2166 static CReserveKey reservekey(pwalletMain);
2168 if(!block.SignBlock(*pwalletMain))
2169 throw JSONRPCError(-100, "Unable to sign block, wallet locked?");
2171 bool fAccepted = CheckWork(&block, *pwalletMain, reservekey);
2179 Value getmemorypool(const Array& params, bool fHelp)
2181 if (fHelp || params.size() > 1)
2182 throw runtime_error(
2183 "getmemorypool [data]\n"
2184 "If [data] is not specified, returns data needed to construct a block to work on:\n"
2185 " \"version\" : block version\n"
2186 " \"previousblockhash\" : hash of current highest block\n"
2187 " \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
2188 " \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
2189 " \"coinbaseflags\" : data that should be included in coinbase so support for new features can be judged\n"
2190 " \"time\" : timestamp appropriate for next block\n"
2191 " \"mintime\" : minimum timestamp appropriate for next block\n"
2192 " \"curtime\" : current timestamp\n"
2193 " \"bits\" : compressed target of next block\n"
2194 "If [data] is specified, tries to solve the block and returns true if it was successful.");
2196 if (params.size() == 0)
2199 throw JSONRPCError(-9, "NovaCoin is not connected!");
2201 if (IsInitialBlockDownload())
2202 throw JSONRPCError(-10, "NovaCoin is downloading blocks...");
2204 static CReserveKey reservekey(pwalletMain);
2207 static unsigned int nTransactionsUpdatedLast;
2208 static CBlockIndex* pindexPrev;
2209 static int64 nStart;
2210 static CBlock* pblock;
2211 if (pindexPrev != pindexBest ||
2212 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5))
2214 nTransactionsUpdatedLast = nTransactionsUpdated;
2215 pindexPrev = pindexBest;
2221 pblock = CreateNewBlock(pwalletMain);
2223 throw JSONRPCError(-7, "Out of memory");
2227 pblock->UpdateTime(pindexPrev);
2231 BOOST_FOREACH(CTransaction tx, pblock->vtx) {
2232 if(tx.IsCoinBase() || tx.IsCoinStake())
2235 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
2238 transactions.push_back(HexStr(ssTx.begin(), ssTx.end()));
2242 result.push_back(Pair("version", pblock->nVersion));
2243 result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
2244 result.push_back(Pair("transactions", transactions));
2245 result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
2246 result.push_back(Pair("coinbaseflags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end())));
2247 result.push_back(Pair("time", (int64_t)pblock->nTime));
2248 result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1));
2249 result.push_back(Pair("curtime", (int64_t)GetAdjustedTime()));
2250 result.push_back(Pair("bits", HexBits(pblock->nBits)));
2257 CDataStream ssBlock(ParseHex(params[0].get_str()), SER_NETWORK, PROTOCOL_VERSION);
2261 static CReserveKey reservekey(pwalletMain);
2263 if(!pblock.SignBlock(*pwalletMain))
2264 throw JSONRPCError(-100, "Unable to sign block, wallet locked?");
2266 return CheckWork(&pblock, *pwalletMain, reservekey);
2270 Value getnewpubkey(const Array& params, bool fHelp)
2272 if (fHelp || params.size() > 1)
2273 throw runtime_error(
2274 "getnewpubkey [account]\n"
2275 "Returns new public key for coinbase generation.");
2277 // Parse the account first so we don't generate a key if there's an error
2279 if (params.size() > 0)
2280 strAccount = AccountFromValue(params[0]);
2282 if (!pwalletMain->IsLocked())
2283 pwalletMain->TopUpKeyPool();
2285 // Generate a new key that is added to wallet
2286 std::vector<unsigned char> newKey = pwalletMain->GenerateNewKey(false);
2289 throw JSONRPCError(-12, "Error: Unable to create key");
2291 CBitcoinAddress address(newKey);
2292 pwalletMain->SetAddressBookName(address, strAccount);
2294 return HexStr(newKey.begin(), newKey.end());
2297 Value getblockhash(const Array& params, bool fHelp)
2299 if (fHelp || params.size() != 1)
2300 throw runtime_error(
2301 "getblockhash <index>\n"
2302 "Returns hash of block in best-block-chain at <index>.");
2304 int nHeight = params[0].get_int();
2305 if (nHeight < 0 || nHeight > nBestHeight)
2306 throw runtime_error("Block number out of range.");
2309 CBlockIndex* pblockindex = mapBlockIndex[hashBestChain];
2310 while (pblockindex->nHeight > nHeight)
2311 pblockindex = pblockindex->pprev;
2312 return pblockindex->phashBlock->GetHex();
2315 Value getblock(const Array& params, bool fHelp)
2317 if (fHelp || params.size() < 1 || params.size() > 2)
2318 throw runtime_error(
2319 "getblock <hash> [txinfo]\n"
2320 "txinfo optional to print more detailed tx info\n"
2321 "Returns details of a block with given block-hash.");
2323 std::string strHash = params[0].get_str();
2324 uint256 hash(strHash);
2326 if (mapBlockIndex.count(hash) == 0)
2327 throw JSONRPCError(-5, "Block not found");
2330 CBlockIndex* pblockindex = mapBlockIndex[hash];
2331 block.ReadFromDisk(pblockindex, true);
2333 return blockToJSON(block, pblockindex, params.size() > 1 ? params[1].get_bool() : false);
2336 Value getblockbynumber(const Array& params, bool fHelp)
2338 if (fHelp || params.size() < 1 || params.size() > 2)
2339 throw runtime_error(
2340 "getblock <number> [txinfo]\n"
2341 "txinfo optional to print more detailed tx info\n"
2342 "Returns details of a block with given block-number.");
2344 int nHeight = params[0].get_int();
2345 if (nHeight < 0 || nHeight > nBestHeight)
2346 throw runtime_error("Block number out of range.");
2349 CBlockIndex* pblockindex = mapBlockIndex[hashBestChain];
2350 while (pblockindex->nHeight > nHeight)
2351 pblockindex = pblockindex->pprev;
2353 uint256 hash = *pblockindex->phashBlock;
2355 pblockindex = mapBlockIndex[hash];
2356 block.ReadFromDisk(pblockindex, true);
2358 return blockToJSON(block, pblockindex, params.size() > 1 ? params[1].get_bool() : false);
2361 // ppcoin: get information of sync-checkpoint
2362 Value getcheckpoint(const Array& params, bool fHelp)
2364 if (fHelp || params.size() != 0)
2365 throw runtime_error(
2367 "Show info of synchronized checkpoint.\n");
2370 CBlockIndex* pindexCheckpoint;
2372 result.push_back(Pair("synccheckpoint", Checkpoints::hashSyncCheckpoint.ToString().c_str()));
2373 pindexCheckpoint = mapBlockIndex[Checkpoints::hashSyncCheckpoint];
2374 result.push_back(Pair("height", pindexCheckpoint->nHeight));
2375 result.push_back(Pair("timestamp", DateTimeStrFormat(pindexCheckpoint->GetBlockTime()).c_str()));
2376 if (mapArgs.count("-checkpointkey"))
2377 result.push_back(Pair("checkpointmaster", true));
2383 // ppcoin: reserve balance from being staked for network protection
2384 Value reservebalance(const Array& params, bool fHelp)
2386 if (fHelp || params.size() > 2)
2387 throw runtime_error(
2388 "reservebalance [<reserve> [amount]]\n"
2389 "<reserve> is true or false to turn balance reserve on or off.\n"
2390 "<amount> is a real and rounded to cent.\n"
2391 "Set reserve amount not participating in network protection.\n"
2392 "If no parameters provided current setting is printed.\n");
2394 if (params.size() > 0)
2396 bool fReserve = params[0].get_bool();
2399 if (params.size() == 1)
2400 throw runtime_error("must provide amount to reserve balance.\n");
2401 int64 nAmount = AmountFromValue(params[1]);
2402 nAmount = (nAmount / CENT) * CENT; // round to cent
2404 throw runtime_error("amount cannot be negative.\n");
2405 mapArgs["-reservebalance"] = FormatMoney(nAmount).c_str();
2409 if (params.size() > 1)
2410 throw runtime_error("cannot specify amount to turn off reserve.\n");
2411 mapArgs["-reservebalance"] = "0";
2416 int64 nReserveBalance = 0;
2417 if (mapArgs.count("-reservebalance") && !ParseMoney(mapArgs["-reservebalance"], nReserveBalance))
2418 throw runtime_error("invalid reserve balance amount\n");
2419 result.push_back(Pair("reserve", (nReserveBalance > 0)));
2420 result.push_back(Pair("amount", ValueFromAmount(nReserveBalance)));
2425 // ppcoin: check wallet integrity
2426 Value checkwallet(const Array& params, bool fHelp)
2428 if (fHelp || params.size() > 0)
2429 throw runtime_error(
2431 "Check wallet for integrity.\n");
2434 int64 nBalanceInQuestion;
2435 pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion, true);
2437 if (nMismatchSpent == 0)
2438 result.push_back(Pair("wallet check passed", true));
2441 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
2442 result.push_back(Pair("amount in question", ValueFromAmount(nBalanceInQuestion)));
2448 // ppcoin: repair wallet
2449 Value repairwallet(const Array& params, bool fHelp)
2451 if (fHelp || params.size() > 0)
2452 throw runtime_error(
2454 "Repair wallet if checkwallet reports any problem.\n");
2457 int64 nBalanceInQuestion;
2458 pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion);
2460 if (nMismatchSpent == 0)
2461 result.push_back(Pair("wallet check passed", true));
2464 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
2465 result.push_back(Pair("amount affected by repair", ValueFromAmount(nBalanceInQuestion)));
2470 // NovaCoin: resend unconfirmed wallet transactions
2471 Value resendtx(const Array& params, bool fHelp)
2473 if (fHelp || params.size() > 1)
2474 throw runtime_error(
2476 "Re-send unconfirmed transactions.\n"
2479 ResendWalletTransactions();
2485 // ppcoin: make a public-private key pair
2486 Value makekeypair(const Array& params, bool fHelp)
2488 if (fHelp || params.size() > 1)
2489 throw runtime_error(
2490 "makekeypair [prefix]\n"
2491 "Make a public/private key pair.\n"
2492 "[prefix] is optional preferred prefix for the public key.\n");
2494 string strPrefix = "";
2495 if (params.size() > 0)
2496 strPrefix = params[0].get_str();
2502 key.MakeNewKey(false);
2504 } while (nCount < 10000 && strPrefix != HexStr(key.GetPubKey()).substr(0, strPrefix.size()));
2506 if (strPrefix != HexStr(key.GetPubKey()).substr(0, strPrefix.size()))
2509 CPrivKey vchPrivKey = key.GetPrivKey();
2511 result.push_back(Pair("PrivateKey", HexStr<CPrivKey::iterator>(vchPrivKey.begin(), vchPrivKey.end())));
2512 result.push_back(Pair("PublicKey", HexStr(key.GetPubKey())));
2516 extern CCriticalSection cs_mapAlerts;
2517 extern map<uint256, CAlert> mapAlerts;
2519 // ppcoin: send alert.
2520 // There is a known deadlock situation with ThreadMessageHandler
2521 // ThreadMessageHandler: holds cs_vSend and acquiring cs_main in SendMessages()
2522 // ThreadRPCServer: holds cs_main and acquiring cs_vSend in alert.RelayTo()/PushMessage()/BeginMessage()
2523 Value sendalert(const Array& params, bool fHelp)
2525 if (fHelp || params.size() < 6)
2526 throw runtime_error(
2527 "sendalert <message> <privatekey> <minver> <maxver> <priority> <id> [cancelupto]\n"
2528 "<message> is the alert text message\n"
2529 "<privatekey> is hex string of alert master private key\n"
2530 "<minver> is the minimum applicable internal client version\n"
2531 "<maxver> is the maximum applicable internal client version\n"
2532 "<priority> is integer priority number\n"
2533 "<id> is the alert id\n"
2534 "[cancelupto] cancels all alert id's up to this number\n"
2535 "Returns true or false.");
2540 alert.strStatusBar = params[0].get_str();
2541 alert.nMinVer = params[2].get_int();
2542 alert.nMaxVer = params[3].get_int();
2543 alert.nPriority = params[4].get_int();
2544 alert.nID = params[5].get_int();
2545 if (params.size() > 6)
2546 alert.nCancel = params[6].get_int();
2547 alert.nVersion = PROTOCOL_VERSION;
2548 alert.nRelayUntil = GetAdjustedTime() + 365*24*60*60;
2549 alert.nExpiration = GetAdjustedTime() + 365*24*60*60;
2551 CDataStream sMsg(SER_NETWORK, PROTOCOL_VERSION);
2552 sMsg << (CUnsignedAlert)alert;
2553 alert.vchMsg = vector<unsigned char>(sMsg.begin(), sMsg.end());
2555 vector<unsigned char> vchPrivKey = ParseHex(params[1].get_str());
2556 key.SetPrivKey(CPrivKey(vchPrivKey.begin(), vchPrivKey.end())); // if key is not correct openssl may crash
2557 if (!key.Sign(Hash(alert.vchMsg.begin(), alert.vchMsg.end()), alert.vchSig))
2558 throw runtime_error(
2559 "Unable to sign alert, check private key?\n");
2560 if(!alert.ProcessAlert())
2561 throw runtime_error(
2562 "Failed to process alert.\n");
2566 BOOST_FOREACH(CNode* pnode, vNodes)
2567 alert.RelayTo(pnode);
2571 result.push_back(Pair("strStatusBar", alert.strStatusBar));
2572 result.push_back(Pair("nVersion", alert.nVersion));
2573 result.push_back(Pair("nMinVer", alert.nMinVer));
2574 result.push_back(Pair("nMaxVer", alert.nMaxVer));
2575 result.push_back(Pair("nPriority", alert.nPriority));
2576 result.push_back(Pair("nID", alert.nID));
2577 if (alert.nCancel > 0)
2578 result.push_back(Pair("nCancel", alert.nCancel));
2589 static const CRPCCommand vRPCCommands[] =
2590 { // name function safe mode?
2591 // ------------------------ ----------------------- ----------
2592 { "help", &help, true },
2593 { "stop", &stop, true },
2594 { "getblockcount", &getblockcount, true },
2595 { "getblocknumber", &getblocknumber, true },
2596 { "getconnectioncount", &getconnectioncount, true },
2597 { "getdifficulty", &getdifficulty, true },
2598 { "getpowreward", &getpowreward, true },
2599 { "getgenerate", &getgenerate, true },
2600 { "setgenerate", &setgenerate, true },
2601 { "gethashespersec", &gethashespersec, true },
2602 { "getinfo", &getinfo, true },
2603 { "getmininginfo", &getmininginfo, true },
2604 { "getnewaddress", &getnewaddress, true },
2605 { "getnewpubkey", &getnewpubkey, true },
2606 { "getaccountaddress", &getaccountaddress, true },
2607 { "setaccount", &setaccount, true },
2608 { "getaccount", &getaccount, false },
2609 { "getaddressesbyaccount", &getaddressesbyaccount, true },
2610 { "sendtoaddress", &sendtoaddress, false },
2611 { "getreceivedbyaddress", &getreceivedbyaddress, false },
2612 { "getreceivedbyaccount", &getreceivedbyaccount, false },
2613 { "listreceivedbyaddress", &listreceivedbyaddress, false },
2614 { "listreceivedbyaccount", &listreceivedbyaccount, false },
2615 { "backupwallet", &backupwallet, true },
2616 { "keypoolrefill", &keypoolrefill, true },
2617 { "walletpassphrase", &walletpassphrase, true },
2618 { "walletpassphrasechange", &walletpassphrasechange, false },
2619 { "walletlock", &walletlock, true },
2620 { "encryptwallet", &encryptwallet, false },
2621 { "validateaddress", &validateaddress, true },
2622 { "validatepubkey", &validatepubkey, true },
2623 { "getbalance", &getbalance, false },
2624 { "move", &movecmd, false },
2625 { "sendfrom", &sendfrom, false },
2626 { "sendmany", &sendmany, false },
2627 { "addmultisigaddress", &addmultisigaddress, false },
2628 { "getblock", &getblock, false },
2629 { "getblockhash", &getblockhash, false },
2630 { "getblockbynumber", &getblockbynumber, false },
2631 { "gettransaction", &gettransaction, false },
2632 { "listtransactions", &listtransactions, false },
2633 { "signmessage", &signmessage, false },
2634 { "verifymessage", &verifymessage, false },
2635 { "getwork", &getwork, true },
2636 { "listaccounts", &listaccounts, false },
2637 { "settxfee", &settxfee, false },
2638 { "getmemorypool", &getmemorypool, true },
2639 { "getblocktemplate", &getblocktemplate, true },
2640 { "submitblock", &submitblock, false },
2641 { "listsinceblock", &listsinceblock, false },
2642 { "dumpprivkey", &dumpprivkey, false },
2643 { "importprivkey", &importprivkey, false },
2644 { "getcheckpoint", &getcheckpoint, true },
2645 { "reservebalance", &reservebalance, false},
2646 { "checkwallet", &checkwallet, false},
2647 { "repairwallet", &repairwallet, false},
2648 { "resendtx", &resendtx, false},
2649 { "makekeypair", &makekeypair, false},
2650 { "sendalert", &sendalert, false},
2653 CRPCTable::CRPCTable()
2656 for (vcidx = 0; vcidx < (sizeof(vRPCCommands) / sizeof(vRPCCommands[0])); vcidx++)
2658 const CRPCCommand *pcmd;
2660 pcmd = &vRPCCommands[vcidx];
2661 mapCommands[pcmd->name] = pcmd;
2665 const CRPCCommand *CRPCTable::operator[](string name) const
2667 map<string, const CRPCCommand*>::const_iterator it = mapCommands.find(name);
2668 if (it == mapCommands.end())
2670 return (*it).second;
2676 // This ain't Apache. We're just using HTTP header for the length field
2677 // and to be compatible with other JSON-RPC implementations.
2680 string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
2683 s << "POST / HTTP/1.1\r\n"
2684 << "User-Agent: novacoin-json-rpc/" << FormatFullVersion() << "\r\n"
2685 << "Host: 127.0.0.1\r\n"
2686 << "Content-Type: application/json\r\n"
2687 << "Content-Length: " << strMsg.size() << "\r\n"
2688 << "Connection: close\r\n"
2689 << "Accept: application/json\r\n";
2690 BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
2691 s << item.first << ": " << item.second << "\r\n";
2692 s << "\r\n" << strMsg;
2697 string rfc1123Time()
2702 struct tm* now_gmt = gmtime(&now);
2703 string locale(setlocale(LC_TIME, NULL));
2704 setlocale(LC_TIME, "C"); // we want posix (aka "C") weekday/month strings
2705 strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt);
2706 setlocale(LC_TIME, locale.c_str());
2707 return string(buffer);
2710 static string HTTPReply(int nStatus, const string& strMsg)
2713 return strprintf("HTTP/1.0 401 Authorization Required\r\n"
2715 "Server: novacoin-json-rpc/%s\r\n"
2716 "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
2717 "Content-Type: text/html\r\n"
2718 "Content-Length: 296\r\n"
2720 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
2721 "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
2724 "<TITLE>Error</TITLE>\r\n"
2725 "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
2727 "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
2728 "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
2729 const char *cStatus;
2730 if (nStatus == 200) cStatus = "OK";
2731 else if (nStatus == 400) cStatus = "Bad Request";
2732 else if (nStatus == 403) cStatus = "Forbidden";
2733 else if (nStatus == 404) cStatus = "Not Found";
2734 else if (nStatus == 500) cStatus = "Internal Server Error";
2737 "HTTP/1.1 %d %s\r\n"
2739 "Connection: close\r\n"
2740 "Content-Length: %d\r\n"
2741 "Content-Type: application/json\r\n"
2742 "Server: novacoin-json-rpc/%s\r\n"
2747 rfc1123Time().c_str(),
2749 FormatFullVersion().c_str(),
2753 int ReadHTTPStatus(std::basic_istream<char>& stream)
2756 getline(stream, str);
2757 vector<string> vWords;
2758 boost::split(vWords, str, boost::is_any_of(" "));
2759 if (vWords.size() < 2)
2761 return atoi(vWords[1].c_str());
2764 int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
2770 std::getline(stream, str);
2771 if (str.empty() || str == "\r")
2773 string::size_type nColon = str.find(":");
2774 if (nColon != string::npos)
2776 string strHeader = str.substr(0, nColon);
2777 boost::trim(strHeader);
2778 boost::to_lower(strHeader);
2779 string strValue = str.substr(nColon+1);
2780 boost::trim(strValue);
2781 mapHeadersRet[strHeader] = strValue;
2782 if (strHeader == "content-length")
2783 nLen = atoi(strValue.c_str());
2789 int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
2791 mapHeadersRet.clear();
2795 int nStatus = ReadHTTPStatus(stream);
2798 int nLen = ReadHTTPHeader(stream, mapHeadersRet);
2799 if (nLen < 0 || nLen > (int)MAX_SIZE)
2805 vector<char> vch(nLen);
2806 stream.read(&vch[0], nLen);
2807 strMessageRet = string(vch.begin(), vch.end());
2813 bool HTTPAuthorized(map<string, string>& mapHeaders)
2815 string strAuth = mapHeaders["authorization"];
2816 if (strAuth.substr(0,6) != "Basic ")
2818 string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
2819 string strUserPass = DecodeBase64(strUserPass64);
2820 return strUserPass == strRPCUserColonPass;
2824 // JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
2825 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
2826 // unspecified (HTTP errors and contents of 'error').
2828 // 1.0 spec: http://json-rpc.org/wiki/specification
2829 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
2830 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
2833 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
2836 request.push_back(Pair("method", strMethod));
2837 request.push_back(Pair("params", params));
2838 request.push_back(Pair("id", id));
2839 return write_string(Value(request), false) + "\n";
2842 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
2845 if (error.type() != null_type)
2846 reply.push_back(Pair("result", Value::null));
2848 reply.push_back(Pair("result", result));
2849 reply.push_back(Pair("error", error));
2850 reply.push_back(Pair("id", id));
2851 return write_string(Value(reply), false) + "\n";
2854 void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
2856 // Send error reply from json-rpc error object
2858 int code = find_value(objError, "code").get_int();
2859 if (code == -32600) nStatus = 400;
2860 else if (code == -32601) nStatus = 404;
2861 string strReply = JSONRPCReply(Value::null, objError, id);
2862 stream << HTTPReply(nStatus, strReply) << std::flush;
2865 bool ClientAllowed(const string& strAddress)
2867 if (strAddress == asio::ip::address_v4::loopback().to_string())
2869 const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
2870 BOOST_FOREACH(string strAllow, vAllow)
2871 if (WildcardMatch(strAddress, strAllow))
2877 // IOStream device that speaks SSL but can also speak non-SSL
2879 class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
2881 SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
2883 fUseSSL = fUseSSLIn;
2884 fNeedHandshake = fUseSSLIn;
2887 void handshake(ssl::stream_base::handshake_type role)
2889 if (!fNeedHandshake) return;
2890 fNeedHandshake = false;
2891 stream.handshake(role);
2893 std::streamsize read(char* s, std::streamsize n)
2895 handshake(ssl::stream_base::server); // HTTPS servers read first
2896 if (fUseSSL) return stream.read_some(asio::buffer(s, n));
2897 return stream.next_layer().read_some(asio::buffer(s, n));
2899 std::streamsize write(const char* s, std::streamsize n)
2901 handshake(ssl::stream_base::client); // HTTPS clients write first
2902 if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
2903 return asio::write(stream.next_layer(), asio::buffer(s, n));
2905 bool connect(const std::string& server, const std::string& port)
2907 ip::tcp::resolver resolver(stream.get_io_service());
2908 ip::tcp::resolver::query query(server.c_str(), port.c_str());
2909 ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
2910 ip::tcp::resolver::iterator end;
2911 boost::system::error_code error = asio::error::host_not_found;
2912 while (error && endpoint_iterator != end)
2914 stream.lowest_layer().close();
2915 stream.lowest_layer().connect(*endpoint_iterator++, error);
2923 bool fNeedHandshake;
2928 void ThreadRPCServer(void* parg)
2930 IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
2933 vnThreadsRunning[THREAD_RPCSERVER]++;
2934 ThreadRPCServer2(parg);
2935 vnThreadsRunning[THREAD_RPCSERVER]--;
2937 catch (std::exception& e) {
2938 vnThreadsRunning[THREAD_RPCSERVER]--;
2939 PrintException(&e, "ThreadRPCServer()");
2941 vnThreadsRunning[THREAD_RPCSERVER]--;
2942 PrintException(NULL, "ThreadRPCServer()");
2944 printf("ThreadRPCServer exiting\n");
2947 void ThreadRPCServer2(void* parg)
2949 printf("ThreadRPCServer started\n");
2951 strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
2952 if (mapArgs["-rpcpassword"] == "")
2954 unsigned char rand_pwd[32];
2955 RAND_bytes(rand_pwd, 32);
2956 string strWhatAmI = "To use novacoind";
2957 if (mapArgs.count("-server"))
2958 strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
2959 else if (mapArgs.count("-daemon"))
2960 strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
2961 ThreadSafeMessageBox(strprintf(
2962 _("%s, you must set a rpcpassword in the configuration file:\n %s\n"
2963 "It is recommended you use the following random password:\n"
2966 "(you do not need to remember this password)\n"
2967 "If the file does not exist, create it with owner-readable-only file permissions.\n"),
2969 GetConfigFile().string().c_str(),
2970 EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str()),
2971 _("Error"), wxOK | wxMODAL);
2976 bool fUseSSL = GetBoolArg("-rpcssl");
2977 asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
2979 asio::io_service io_service;
2980 ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", RPC_PORT));
2981 ip::tcp::acceptor acceptor(io_service);
2984 acceptor.open(endpoint.protocol());
2985 acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
2986 acceptor.bind(endpoint);
2987 acceptor.listen(socket_base::max_connections);
2989 catch(boost::system::system_error &e)
2991 ThreadSafeMessageBox(strprintf(_("An error occured while setting up the RPC port %i for listening: %s"), endpoint.port(), e.what()),
2992 _("Error"), wxOK | wxMODAL);
2997 ssl::context context(io_service, ssl::context::sslv23);
3000 context.set_options(ssl::context::no_sslv2);
3002 filesystem::path pathCertFile(GetArg("-rpcsslcertificatechainfile", "server.cert"));
3003 if (!pathCertFile.is_complete()) pathCertFile = filesystem::path(GetDataDir()) / pathCertFile;
3004 if (filesystem::exists(pathCertFile)) context.use_certificate_chain_file(pathCertFile.string());
3005 else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", pathCertFile.string().c_str());
3007 filesystem::path pathPKFile(GetArg("-rpcsslprivatekeyfile", "server.pem"));
3008 if (!pathPKFile.is_complete()) pathPKFile = filesystem::path(GetDataDir()) / pathPKFile;
3009 if (filesystem::exists(pathPKFile)) context.use_private_key_file(pathPKFile.string(), ssl::context::pem);
3010 else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pathPKFile.string().c_str());
3012 string strCiphers = GetArg("-rpcsslciphers", "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
3013 SSL_CTX_set_cipher_list(context.impl(), strCiphers.c_str());
3018 // Accept connection
3019 SSLStream sslStream(io_service, context);
3020 SSLIOStreamDevice d(sslStream, fUseSSL);
3021 iostreams::stream<SSLIOStreamDevice> stream(d);
3023 ip::tcp::endpoint peer;
3024 vnThreadsRunning[THREAD_RPCSERVER]--;
3025 acceptor.accept(sslStream.lowest_layer(), peer);
3026 vnThreadsRunning[4]++;
3030 // Restrict callers by IP
3031 if (!ClientAllowed(peer.address().to_string()))
3033 // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
3035 stream << HTTPReply(403, "") << std::flush;
3039 map<string, string> mapHeaders;
3042 boost::thread api_caller(ReadHTTP, boost::ref(stream), boost::ref(mapHeaders), boost::ref(strRequest));
3043 if (!api_caller.timed_join(boost::posix_time::seconds(GetArg("-rpctimeout", 30))))
3046 printf("ThreadRPCServer ReadHTTP timeout\n");
3050 // Check authorization
3051 if (mapHeaders.count("authorization") == 0)
3053 stream << HTTPReply(401, "") << std::flush;
3056 if (!HTTPAuthorized(mapHeaders))
3058 printf("ThreadRPCServer incorrect password attempt from %s\n",peer.address().to_string().c_str());
3059 /* Deter brute-forcing short passwords.
3060 If this results in a DOS the user really
3061 shouldn't have their RPC port exposed.*/
3062 if (mapArgs["-rpcpassword"].size() < 20)
3065 stream << HTTPReply(401, "") << std::flush;
3069 Value id = Value::null;
3074 if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
3075 throw JSONRPCError(-32700, "Parse error");
3076 const Object& request = valRequest.get_obj();
3078 // Parse id now so errors from here on will have the id
3079 id = find_value(request, "id");
3082 Value valMethod = find_value(request, "method");
3083 if (valMethod.type() == null_type)
3084 throw JSONRPCError(-32600, "Missing method");
3085 if (valMethod.type() != str_type)
3086 throw JSONRPCError(-32600, "Method must be a string");
3087 string strMethod = valMethod.get_str();
3088 if (strMethod != "getwork" && strMethod != "getmemorypool")
3089 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
3092 Value valParams = find_value(request, "params");
3094 if (valParams.type() == array_type)
3095 params = valParams.get_array();
3096 else if (valParams.type() == null_type)
3099 throw JSONRPCError(-32600, "Params must be an array");
3102 const CRPCCommand *pcmd = tableRPC[strMethod];
3104 throw JSONRPCError(-32601, "Method not found");
3106 // Observe safe mode
3107 string strWarning = GetWarnings("rpc");
3108 if (strWarning != "" && !GetBoolArg("-disablesafemode") &&
3110 throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
3117 LOCK2(cs_main, pwalletMain->cs_wallet);
3118 result = pcmd->actor(params, false);
3122 string strReply = JSONRPCReply(result, Value::null, id);
3123 stream << HTTPReply(200, strReply) << std::flush;
3125 catch (std::exception& e)
3127 ErrorReply(stream, JSONRPCError(-1, e.what()), id);
3130 catch (Object& objError)
3132 ErrorReply(stream, objError, id);
3134 catch (std::exception& e)
3136 ErrorReply(stream, JSONRPCError(-32700, e.what()), id);
3144 Object CallRPC(const string& strMethod, const Array& params)
3146 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
3147 throw runtime_error(strprintf(
3148 _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
3149 "If the file does not exist, create it with owner-readable-only file permissions."),
3150 GetConfigFile().string().c_str()));
3152 // Connect to localhost
3153 bool fUseSSL = GetBoolArg("-rpcssl");
3154 asio::io_service io_service;
3155 ssl::context context(io_service, ssl::context::sslv23);
3156 context.set_options(ssl::context::no_sslv2);
3157 SSLStream sslStream(io_service, context);
3158 SSLIOStreamDevice d(sslStream, fUseSSL);
3159 iostreams::stream<SSLIOStreamDevice> stream(d);
3160 if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", CBigNum(RPC_PORT).ToString().c_str())))
3161 throw runtime_error("couldn't connect to server");
3163 // HTTP basic authentication
3164 string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
3165 map<string, string> mapRequestHeaders;
3166 mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
3169 string strRequest = JSONRPCRequest(strMethod, params, 1);
3170 string strPost = HTTPPost(strRequest, mapRequestHeaders);
3171 stream << strPost << std::flush;
3174 map<string, string> mapHeaders;
3176 int nStatus = ReadHTTP(stream, mapHeaders, strReply);
3178 throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
3179 else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
3180 throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
3181 else if (strReply.empty())
3182 throw runtime_error("no response from server");
3186 if (!read_string(strReply, valReply))
3187 throw runtime_error("couldn't parse reply from server");
3188 const Object& reply = valReply.get_obj();
3190 throw runtime_error("expected reply to have result, error and id properties");
3198 template<typename T>
3199 void ConvertTo(Value& value)
3201 if (value.type() == str_type)
3203 // reinterpret string as unquoted json value
3205 if (!read_string(value.get_str(), value2))
3206 throw runtime_error("type mismatch");
3207 value = value2.get_value<T>();
3211 value = value.get_value<T>();
3215 int CommandLineRPC(int argc, char *argv[])
3222 while (argc > 1 && IsSwitchChar(argv[1][0]))
3230 throw runtime_error("too few parameters");
3231 string strMethod = argv[1];
3233 // Parameters default to strings
3235 for (int i = 2; i < argc; i++)
3236 params.push_back(argv[i]);
3237 int n = params.size();
3240 // Special case non-string parameter types
3242 if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
3243 if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
3244 if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
3245 if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]);
3246 if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
3247 if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]);
3248 if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
3249 if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
3250 if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]);
3251 if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
3252 if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]);
3253 if (strMethod == "getblockhash" && n > 0) ConvertTo<boost::int64_t>(params[0]);
3254 if (strMethod == "getblockbynumber" && n > 0) ConvertTo<boost::int64_t>(params[0]);
3255 if (strMethod == "getblockbynumber" && n > 1) ConvertTo<bool>(params[1]);
3256 if (strMethod == "getblock" && n > 1) ConvertTo<bool>(params[1]);
3257 if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]);
3258 if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]);
3259 if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]);
3260 if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]);
3261 if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
3262 if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]);
3263 if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]);
3264 if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]);
3265 if (strMethod == "walletpassphrase" && n > 2) ConvertTo<bool>(params[2]);
3266 if (strMethod == "listsinceblock" && n > 1) ConvertTo<boost::int64_t>(params[1]);
3267 if (strMethod == "sendalert" && n > 2) ConvertTo<boost::int64_t>(params[2]);
3268 if (strMethod == "sendalert" && n > 3) ConvertTo<boost::int64_t>(params[3]);
3269 if (strMethod == "sendalert" && n > 4) ConvertTo<boost::int64_t>(params[4]);
3270 if (strMethod == "sendalert" && n > 5) ConvertTo<boost::int64_t>(params[5]);
3271 if (strMethod == "sendalert" && n > 6) ConvertTo<boost::int64_t>(params[6]);
3272 if (strMethod == "sendmany" && n > 1)
3274 string s = params[1].get_str();
3276 if (!read_string(s, v) || v.type() != obj_type)
3277 throw runtime_error("type mismatch");
3278 params[1] = v.get_obj();
3280 if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]);
3281 if (strMethod == "reservebalance" && n > 0) ConvertTo<bool>(params[0]);
3282 if (strMethod == "reservebalance" && n > 1) ConvertTo<double>(params[1]);
3283 if (strMethod == "addmultisigaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
3284 if (strMethod == "addmultisigaddress" && n > 1)
3286 string s = params[1].get_str();
3288 if (!read_string(s, v) || v.type() != array_type)
3289 throw runtime_error("type mismatch "+s);
3290 params[1] = v.get_array();
3294 Object reply = CallRPC(strMethod, params);
3297 const Value& result = find_value(reply, "result");
3298 const Value& error = find_value(reply, "error");
3300 if (error.type() != null_type)
3303 strPrint = "error: " + write_string(error, false);
3304 int code = find_value(error.get_obj(), "code").get_int();
3310 if (result.type() == null_type)
3312 else if (result.type() == str_type)
3313 strPrint = result.get_str();
3315 strPrint = write_string(result, true);
3318 catch (std::exception& e)
3320 strPrint = string("error: ") + e.what();
3325 PrintException(NULL, "CommandLineRPC()");
3330 fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
3339 int main(int argc, char *argv[])
3342 // Turn off microsoft heap dump noise
3343 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
3344 _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
3346 setbuf(stdin, NULL);
3347 setbuf(stdout, NULL);
3348 setbuf(stderr, NULL);
3352 if (argc >= 2 && string(argv[1]) == "-server")
3354 printf("server ready\n");
3355 ThreadRPCServer(NULL);
3359 return CommandLineRPC(argc, argv);
3362 catch (std::exception& e) {
3363 PrintException(&e, "main()");
3365 PrintException(NULL, "main()");
3371 const CRPCTable tableRPC;