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 TxToJSON(const CTransaction &tx, Object& entry)
132 entry.push_back(Pair("version", tx.nVersion));
133 entry.push_back(Pair("locktime", (boost::int64_t)tx.nLockTime));
134 entry.push_back(Pair("size", (boost::int64_t)::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION)));
136 BOOST_FOREACH(const CTxIn& txin, tx.vin)
140 in.push_back(Pair("coinbase", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
144 prevout.push_back(Pair("hash", txin.prevout.hash.GetHex()));
145 prevout.push_back(Pair("n", (boost::int64_t)txin.prevout.n));
146 in.push_back(Pair("prevout", prevout));
147 in.push_back(Pair("scriptSig", txin.scriptSig.ToString()));
149 in.push_back(Pair("sequence", (boost::int64_t)txin.nSequence));
152 entry.push_back(Pair("vin", vin));
154 BOOST_FOREACH(const CTxOut& txout, tx.vout)
157 out.push_back(Pair("value", ValueFromAmount(txout.nValue)));
158 out.push_back(Pair("scriptPubKey", txout.scriptPubKey.ToString()));
161 entry.push_back(Pair("vout", vout));
164 void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
166 int confirms = wtx.GetDepthInMainChain();
167 entry.push_back(Pair("confirmations", confirms));
170 entry.push_back(Pair("blockhash", wtx.hashBlock.GetHex()));
171 entry.push_back(Pair("blockindex", wtx.nIndex));
173 entry.push_back(Pair("txid", wtx.GetHash().GetHex()));
174 entry.push_back(Pair("time", (boost::int64_t)wtx.GetTxTime()));
175 BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
176 entry.push_back(Pair(item.first, item.second));
179 string AccountFromValue(const Value& value)
181 string strAccount = value.get_str();
182 if (strAccount == "*")
183 throw JSONRPCError(-11, "Invalid account name");
187 Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool fPrintTransactionDetail)
190 result.push_back(Pair("hash", block.GetHash().GetHex()));
191 result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION)));
192 result.push_back(Pair("height", blockindex->nHeight));
193 result.push_back(Pair("version", block.nVersion));
194 result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex()));
195 result.push_back(Pair("time", DateTimeStrFormat(block.GetBlockTime())));
196 result.push_back(Pair("nonce", (boost::uint64_t)block.nNonce));
197 result.push_back(Pair("bits", HexBits(block.nBits)));
198 result.push_back(Pair("difficulty", GetDifficulty(blockindex)));
199 result.push_back(Pair("mint", ValueFromAmount(blockindex->nMint)));
200 if (blockindex->pprev)
201 result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex()));
202 if (blockindex->pnext)
203 result.push_back(Pair("nextblockhash", blockindex->pnext->GetBlockHash().GetHex()));
204 result.push_back(Pair("flags", strprintf("%s%s", blockindex->IsProofOfStake()? "proof-of-stake" : "proof-of-work", blockindex->GeneratedStakeModifier()? " stake-modifier": "")));
205 result.push_back(Pair("proofhash", blockindex->IsProofOfStake()? blockindex->hashProofOfStake.GetHex() : blockindex->GetBlockHash().GetHex()));
206 result.push_back(Pair("entropybit", (int)blockindex->GetStakeEntropyBit()));
207 result.push_back(Pair("modifier", strprintf("%016"PRI64x, blockindex->nStakeModifier)));
208 result.push_back(Pair("modifierchecksum", strprintf("%08x", blockindex->nStakeModifierChecksum)));
210 BOOST_FOREACH (const CTransaction& tx, block.vtx)
212 if (fPrintTransactionDetail)
214 txinfo.push_back(tx.ToStringShort());
215 txinfo.push_back(DateTimeStrFormat(tx.nTime));
216 BOOST_FOREACH(const CTxIn& txin, tx.vin)
217 txinfo.push_back(txin.ToStringShort());
218 BOOST_FOREACH(const CTxOut& txout, tx.vout)
219 txinfo.push_back(txout.ToStringShort());
222 txinfo.push_back(tx.GetHash().GetHex());
224 result.push_back(Pair("tx", txinfo));
231 /// Note: This interface may still be subject to change.
234 string CRPCTable::help(string strCommand) const
237 set<rpcfn_type> setDone;
238 for (map<string, const CRPCCommand*>::const_iterator mi = mapCommands.begin(); mi != mapCommands.end(); ++mi)
240 const CRPCCommand *pcmd = mi->second;
241 string strMethod = mi->first;
242 // We already filter duplicates, but these deprecated screw up the sort order
243 if (strMethod == "getamountreceived" ||
244 strMethod == "getallreceived" ||
245 strMethod == "getblocknumber" || // deprecated
246 (strMethod.find("label") != string::npos))
248 if (strCommand != "" && strMethod != strCommand)
253 rpcfn_type pfn = pcmd->actor;
254 if (setDone.insert(pfn).second)
255 (*pfn)(params, true);
257 catch (std::exception& e)
259 // Help text is returned in an exception
260 string strHelp = string(e.what());
261 if (strCommand == "")
262 if (strHelp.find('\n') != string::npos)
263 strHelp = strHelp.substr(0, strHelp.find('\n'));
264 strRet += strHelp + "\n";
268 strRet = strprintf("help: unknown command: %s\n", strCommand.c_str());
269 strRet = strRet.substr(0,strRet.size()-1);
273 Value help(const Array& params, bool fHelp)
275 if (fHelp || params.size() > 1)
278 "List commands, or get help for a command.");
281 if (params.size() > 0)
282 strCommand = params[0].get_str();
284 return tableRPC.help(strCommand);
288 Value stop(const Array& params, bool fHelp)
290 if (fHelp || params.size() != 0)
293 "Stop novacoin server.");
294 // Shutdown will take long enough that the response should get back
296 return "novacoin server stopping";
300 Value getblockcount(const Array& params, bool fHelp)
302 if (fHelp || params.size() != 0)
305 "Returns the number of blocks in the longest block chain.");
312 Value getblocknumber(const Array& params, bool fHelp)
314 if (fHelp || params.size() != 0)
317 "Deprecated. Use getblockcount.");
323 Value getconnectioncount(const Array& params, bool fHelp)
325 if (fHelp || params.size() != 0)
327 "getconnectioncount\n"
328 "Returns the number of connections to other nodes.");
330 return (int)vNodes.size();
334 Value getdifficulty(const Array& params, bool fHelp)
336 if (fHelp || params.size() != 0)
339 "Returns difficulty as a multiple of the minimum difficulty.");
342 obj.push_back(Pair("proof-of-work", GetDifficulty()));
343 obj.push_back(Pair("proof-of-stake", GetDifficulty(GetLastBlockIndex(pindexBest, true))));
344 obj.push_back(Pair("search-interval", (int)nLastCoinStakeSearchInterval));
349 Value getgenerate(const Array& params, bool fHelp)
351 if (fHelp || params.size() != 0)
354 "Returns true or false.");
356 return GetBoolArg("-gen");
360 Value setgenerate(const Array& params, bool fHelp)
362 if (fHelp || params.size() < 1 || params.size() > 2)
364 "setgenerate <generate> [genproclimit]\n"
365 "<generate> is true or false to turn generation on or off.\n"
366 "Generation is limited to [genproclimit] processors, -1 is unlimited.");
368 bool fGenerate = true;
369 if (params.size() > 0)
370 fGenerate = params[0].get_bool();
372 if (params.size() > 1)
374 int nGenProcLimit = params[1].get_int();
375 mapArgs["-genproclimit"] = itostr(nGenProcLimit);
376 if (nGenProcLimit == 0)
379 mapArgs["-gen"] = (fGenerate ? "1" : "0");
381 GenerateBitcoins(fGenerate, pwalletMain);
386 Value gethashespersec(const Array& params, bool fHelp)
388 if (fHelp || params.size() != 0)
391 "Returns a recent hashes per second performance measurement while generating.");
393 if (GetTimeMillis() - nHPSTimerStart > 8000)
394 return (boost::int64_t)0;
395 return (boost::int64_t)dHashesPerSec;
399 Value getinfo(const Array& params, bool fHelp)
401 if (fHelp || params.size() != 0)
404 "Returns an object containing various state info.");
407 obj.push_back(Pair("version", FormatFullVersion()));
408 obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION));
409 obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
410 obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
411 obj.push_back(Pair("newmint", ValueFromAmount(pwalletMain->GetNewMint())));
412 obj.push_back(Pair("stake", ValueFromAmount(pwalletMain->GetStake())));
413 obj.push_back(Pair("blocks", (int)nBestHeight));
414 obj.push_back(Pair("moneysupply", ValueFromAmount(pindexBest->nMoneySupply)));
415 obj.push_back(Pair("connections", (int)vNodes.size()));
416 obj.push_back(Pair("proxy", (fUseProxy ? addrProxy.ToStringIPPort() : string())));
417 obj.push_back(Pair("ip", addrSeenByPeer.ToStringIP()));
418 obj.push_back(Pair("difficulty", (double)GetDifficulty()));
419 obj.push_back(Pair("testnet", fTestNet));
420 obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));
421 obj.push_back(Pair("keypoolsize", pwalletMain->GetKeyPoolSize()));
422 obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee)));
423 if (pwalletMain->IsCrypted())
424 obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime / 1000));
425 obj.push_back(Pair("errors", GetWarnings("statusbar")));
430 Value getmininginfo(const Array& params, bool fHelp)
432 if (fHelp || params.size() != 0)
435 "Returns an object containing mining-related information.");
438 obj.push_back(Pair("blocks", (int)nBestHeight));
439 obj.push_back(Pair("currentblocksize",(uint64_t)nLastBlockSize));
440 obj.push_back(Pair("currentblocktx",(uint64_t)nLastBlockTx));
441 obj.push_back(Pair("difficulty", (double)GetDifficulty()));
442 obj.push_back(Pair("errors", GetWarnings("statusbar")));
443 obj.push_back(Pair("generate", GetBoolArg("-gen")));
444 obj.push_back(Pair("genproclimit", (int)GetArg("-genproclimit", -1)));
445 obj.push_back(Pair("hashespersec", gethashespersec(params, false)));
446 obj.push_back(Pair("pooledtx", (uint64_t)mempool.size()));
447 obj.push_back(Pair("testnet", fTestNet));
452 Value getnewaddress(const Array& params, bool fHelp)
454 if (fHelp || params.size() > 1)
456 "getnewaddress [account]\n"
457 "Returns a new novacoin address for receiving payments. "
458 "If [account] is specified (recommended), it is added to the address book "
459 "so payments received with the address will be credited to [account].");
461 // Parse the account first so we don't generate a key if there's an error
463 if (params.size() > 0)
464 strAccount = AccountFromValue(params[0]);
466 if (!pwalletMain->IsLocked())
467 pwalletMain->TopUpKeyPool();
469 // Generate a new key that is added to wallet
470 std::vector<unsigned char> newKey;
471 if (!pwalletMain->GetKeyFromPool(newKey, false))
472 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
473 CBitcoinAddress address(newKey);
475 pwalletMain->SetAddressBookName(address, strAccount);
477 return address.ToString();
481 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
483 CWalletDB walletdb(pwalletMain->strWalletFile);
486 walletdb.ReadAccount(strAccount, account);
488 bool bKeyUsed = false;
490 // Check if the current key has been used
491 if (!account.vchPubKey.empty())
493 CScript scriptPubKey;
494 scriptPubKey.SetBitcoinAddress(account.vchPubKey);
495 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
496 it != pwalletMain->mapWallet.end() && !account.vchPubKey.empty();
499 const CWalletTx& wtx = (*it).second;
500 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
501 if (txout.scriptPubKey == scriptPubKey)
506 // Generate a new key
507 if (account.vchPubKey.empty() || bForceNew || bKeyUsed)
509 if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false))
510 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
512 pwalletMain->SetAddressBookName(CBitcoinAddress(account.vchPubKey), strAccount);
513 walletdb.WriteAccount(strAccount, account);
516 return CBitcoinAddress(account.vchPubKey);
519 Value getaccountaddress(const Array& params, bool fHelp)
521 if (fHelp || params.size() != 1)
523 "getaccountaddress <account>\n"
524 "Returns the current novacoin address for receiving payments to this account.");
526 // Parse the account first so we don't generate a key if there's an error
527 string strAccount = AccountFromValue(params[0]);
531 ret = GetAccountAddress(strAccount).ToString();
538 Value setaccount(const Array& params, bool fHelp)
540 if (fHelp || params.size() < 1 || params.size() > 2)
542 "setaccount <novacoinaddress> <account>\n"
543 "Sets the account associated with the given address.");
545 CBitcoinAddress address(params[0].get_str());
546 if (!address.IsValid())
547 throw JSONRPCError(-5, "Invalid novacoin address");
551 if (params.size() > 1)
552 strAccount = AccountFromValue(params[1]);
554 // Detect when changing the account of an address that is the 'unused current key' of another account:
555 if (pwalletMain->mapAddressBook.count(address))
557 string strOldAccount = pwalletMain->mapAddressBook[address];
558 if (address == GetAccountAddress(strOldAccount))
559 GetAccountAddress(strOldAccount, true);
562 pwalletMain->SetAddressBookName(address, strAccount);
568 Value getaccount(const Array& params, bool fHelp)
570 if (fHelp || params.size() != 1)
572 "getaccount <novacoinaddress>\n"
573 "Returns the account associated with the given address.");
575 CBitcoinAddress address(params[0].get_str());
576 if (!address.IsValid())
577 throw JSONRPCError(-5, "Invalid novacoin address");
580 map<CBitcoinAddress, string>::iterator mi = pwalletMain->mapAddressBook.find(address);
581 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
582 strAccount = (*mi).second;
587 Value getaddressesbyaccount(const Array& params, bool fHelp)
589 if (fHelp || params.size() != 1)
591 "getaddressesbyaccount <account>\n"
592 "Returns the list of addresses for the given account.");
594 string strAccount = AccountFromValue(params[0]);
596 // Find all addresses that have the given account
598 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
600 const CBitcoinAddress& address = item.first;
601 const string& strName = item.second;
602 if (strName == strAccount)
603 ret.push_back(address.ToString());
608 Value settxfee(const Array& params, bool fHelp)
610 if (fHelp || params.size() < 1 || params.size() > 1 || AmountFromValue(params[0]) < MIN_TX_FEE)
612 "settxfee <amount>\n"
613 "<amount> is a real and is rounded to 0.01 (cent)\n"
614 "Minimum and default transaction fee per KB is 1 cent");
616 nTransactionFee = AmountFromValue(params[0]);
617 nTransactionFee = (nTransactionFee / CENT) * CENT; // round to cent
621 Value sendtoaddress(const Array& params, bool fHelp)
623 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
625 "sendtoaddress <novacoinaddress> <amount> [comment] [comment-to]\n"
626 "<amount> is a real and is rounded to the nearest 0.000001\n"
627 "requires wallet passphrase to be set with walletpassphrase first");
628 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
630 "sendtoaddress <novacoinaddress> <amount> [comment] [comment-to]\n"
631 "<amount> is a real and is rounded to the nearest 0.000001");
633 CBitcoinAddress address(params[0].get_str());
634 if (!address.IsValid())
635 throw JSONRPCError(-5, "Invalid novacoin address");
638 int64 nAmount = AmountFromValue(params[1]);
639 if (nAmount < MIN_TXOUT_AMOUNT)
640 throw JSONRPCError(-101, "Send amount too small");
644 if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
645 wtx.mapValue["comment"] = params[2].get_str();
646 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
647 wtx.mapValue["to"] = params[3].get_str();
649 if (pwalletMain->IsLocked())
650 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
652 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
654 throw JSONRPCError(-4, strError);
656 return wtx.GetHash().GetHex();
659 Value signmessage(const Array& params, bool fHelp)
661 if (fHelp || params.size() != 2)
663 "signmessage <novacoinaddress> <message>\n"
664 "Sign a message with the private key of an address");
666 if (pwalletMain->IsLocked())
667 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
669 string strAddress = params[0].get_str();
670 string strMessage = params[1].get_str();
672 CBitcoinAddress addr(strAddress);
674 throw JSONRPCError(-3, "Invalid address");
677 if (!pwalletMain->GetKey(addr, key))
678 throw JSONRPCError(-4, "Private key not available");
680 CDataStream ss(SER_GETHASH, 0);
681 ss << strMessageMagic;
684 vector<unsigned char> vchSig;
685 if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig))
686 throw JSONRPCError(-5, "Sign failed");
688 return EncodeBase64(&vchSig[0], vchSig.size());
691 Value verifymessage(const Array& params, bool fHelp)
693 if (fHelp || params.size() != 3)
695 "verifymessage <novacoinaddress> <signature> <message>\n"
696 "Verify a signed message");
698 string strAddress = params[0].get_str();
699 string strSign = params[1].get_str();
700 string strMessage = params[2].get_str();
702 CBitcoinAddress addr(strAddress);
704 throw JSONRPCError(-3, "Invalid address");
706 bool fInvalid = false;
707 vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
710 throw JSONRPCError(-5, "Malformed base64 encoding");
712 CDataStream ss(SER_GETHASH, 0);
713 ss << strMessageMagic;
717 if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
720 return (CBitcoinAddress(key.GetPubKey()) == addr);
724 Value getreceivedbyaddress(const Array& params, bool fHelp)
726 if (fHelp || params.size() < 1 || params.size() > 2)
728 "getreceivedbyaddress <novacoinaddress> [minconf=1]\n"
729 "Returns the total amount received by <novacoinaddress> in transactions with at least [minconf] confirmations.");
732 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
733 CScript scriptPubKey;
734 if (!address.IsValid())
735 throw JSONRPCError(-5, "Invalid novacoin address");
736 scriptPubKey.SetBitcoinAddress(address);
737 if (!IsMine(*pwalletMain,scriptPubKey))
740 // Minimum confirmations
742 if (params.size() > 1)
743 nMinDepth = params[1].get_int();
747 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
749 const CWalletTx& wtx = (*it).second;
750 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
753 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
754 if (txout.scriptPubKey == scriptPubKey)
755 if (wtx.GetDepthInMainChain() >= nMinDepth)
756 nAmount += txout.nValue;
759 return ValueFromAmount(nAmount);
763 void GetAccountAddresses(string strAccount, set<CBitcoinAddress>& setAddress)
765 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
767 const CBitcoinAddress& address = item.first;
768 const string& strName = item.second;
769 if (strName == strAccount)
770 setAddress.insert(address);
775 Value getreceivedbyaccount(const Array& params, bool fHelp)
777 if (fHelp || params.size() < 1 || params.size() > 2)
779 "getreceivedbyaccount <account> [minconf=1]\n"
780 "Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.");
782 // Minimum confirmations
784 if (params.size() > 1)
785 nMinDepth = params[1].get_int();
787 // Get the set of pub keys assigned to account
788 string strAccount = AccountFromValue(params[0]);
789 set<CBitcoinAddress> setAddress;
790 GetAccountAddresses(strAccount, setAddress);
794 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
796 const CWalletTx& wtx = (*it).second;
797 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
800 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
802 CBitcoinAddress address;
803 if (ExtractAddress(txout.scriptPubKey, address) && pwalletMain->HaveKey(address) && setAddress.count(address))
804 if (wtx.GetDepthInMainChain() >= nMinDepth)
805 nAmount += txout.nValue;
809 return (double)nAmount / (double)COIN;
813 int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth)
817 // Tally wallet transactions
818 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
820 const CWalletTx& wtx = (*it).second;
824 int64 nGenerated, nReceived, nSent, nFee;
825 wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee);
827 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
828 nBalance += nReceived;
829 nBalance += nGenerated - nSent - nFee;
832 // Tally internal accounting entries
833 nBalance += walletdb.GetAccountCreditDebit(strAccount);
838 int64 GetAccountBalance(const string& strAccount, int nMinDepth)
840 CWalletDB walletdb(pwalletMain->strWalletFile);
841 return GetAccountBalance(walletdb, strAccount, nMinDepth);
845 Value getbalance(const Array& params, bool fHelp)
847 if (fHelp || params.size() > 2)
849 "getbalance [account] [minconf=1]\n"
850 "If [account] is not specified, returns the server's total available balance.\n"
851 "If [account] is specified, returns the balance in the account.");
853 if (params.size() == 0)
854 return ValueFromAmount(pwalletMain->GetBalance());
857 if (params.size() > 1)
858 nMinDepth = params[1].get_int();
860 if (params[0].get_str() == "*") {
861 // Calculate total balance a different way from GetBalance()
862 // (GetBalance() sums up all unspent TxOuts)
863 // getbalance and getbalance '*' should always return the same number.
865 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
867 const CWalletTx& wtx = (*it).second;
871 int64 allGeneratedImmature, allGeneratedMature, allFee;
872 allGeneratedImmature = allGeneratedMature = allFee = 0;
873 string strSentAccount;
874 list<pair<CBitcoinAddress, int64> > listReceived;
875 list<pair<CBitcoinAddress, int64> > listSent;
876 wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
877 if (wtx.GetDepthInMainChain() >= nMinDepth)
879 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listReceived)
880 nBalance += r.second;
882 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listSent)
883 nBalance -= r.second;
885 nBalance += allGeneratedMature;
887 return ValueFromAmount(nBalance);
890 string strAccount = AccountFromValue(params[0]);
892 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
894 return ValueFromAmount(nBalance);
898 Value getpowreward(const Array& params, bool fHelp)
900 if (fHelp || params.size() > 1)
902 "getpowreward [nBits]\n"
903 "Returns PoW reward for block with provided difficulty.");
905 if (params.size() == 0)
906 throw JSONRPCError(-200, "no bits provided");
908 std::string sBits = params[0].get_str();
910 if (sBits.length() != 8)
911 throw JSONRPCError(-201, "incorrect bits provided");
913 unsigned int nBits = BitsHex(sBits);
915 return (int)GetProofOfWorkReward(nBits);
920 Value movecmd(const Array& params, bool fHelp)
922 if (fHelp || params.size() < 3 || params.size() > 5)
924 "move <fromaccount> <toaccount> <amount> [minconf=1] [comment]\n"
925 "Move from one account in your wallet to another.");
927 string strFrom = AccountFromValue(params[0]);
928 string strTo = AccountFromValue(params[1]);
929 int64 nAmount = AmountFromValue(params[2]);
930 if (params.size() > 3)
931 // unused parameter, used to be nMinDepth, keep type-checking it though
932 (void)params[3].get_int();
934 if (params.size() > 4)
935 strComment = params[4].get_str();
937 CWalletDB walletdb(pwalletMain->strWalletFile);
938 if (!walletdb.TxnBegin())
939 throw JSONRPCError(-20, "database error");
941 int64 nNow = GetAdjustedTime();
944 CAccountingEntry debit;
945 debit.strAccount = strFrom;
946 debit.nCreditDebit = -nAmount;
948 debit.strOtherAccount = strTo;
949 debit.strComment = strComment;
950 walletdb.WriteAccountingEntry(debit);
953 CAccountingEntry credit;
954 credit.strAccount = strTo;
955 credit.nCreditDebit = nAmount;
957 credit.strOtherAccount = strFrom;
958 credit.strComment = strComment;
959 walletdb.WriteAccountingEntry(credit);
961 if (!walletdb.TxnCommit())
962 throw JSONRPCError(-20, "database error");
968 Value sendfrom(const Array& params, bool fHelp)
970 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
972 "sendfrom <fromaccount> <tonovacoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
973 "<amount> is a real and is rounded to the nearest 0.000001\n"
974 "requires wallet passphrase to be set with walletpassphrase first");
975 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
977 "sendfrom <fromaccount> <tonovacoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
978 "<amount> is a real and is rounded to the nearest 0.000001");
980 string strAccount = AccountFromValue(params[0]);
981 CBitcoinAddress address(params[1].get_str());
982 if (!address.IsValid())
983 throw JSONRPCError(-5, "Invalid novacoin address");
984 int64 nAmount = AmountFromValue(params[2]);
985 if (nAmount < MIN_TXOUT_AMOUNT)
986 throw JSONRPCError(-101, "Send amount too small");
988 if (params.size() > 3)
989 nMinDepth = params[3].get_int();
992 wtx.strFromAccount = strAccount;
993 if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
994 wtx.mapValue["comment"] = params[4].get_str();
995 if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
996 wtx.mapValue["to"] = params[5].get_str();
998 if (pwalletMain->IsLocked())
999 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
1002 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
1003 if (nAmount > nBalance)
1004 throw JSONRPCError(-6, "Account has insufficient funds");
1007 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
1009 throw JSONRPCError(-4, strError);
1011 return wtx.GetHash().GetHex();
1015 Value sendmany(const Array& params, bool fHelp)
1017 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
1018 throw runtime_error(
1019 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
1020 "amounts are double-precision floating point numbers\n"
1021 "requires wallet passphrase to be set with walletpassphrase first");
1022 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
1023 throw runtime_error(
1024 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
1025 "amounts are double-precision floating point numbers");
1027 string strAccount = AccountFromValue(params[0]);
1028 Object sendTo = params[1].get_obj();
1030 if (params.size() > 2)
1031 nMinDepth = params[2].get_int();
1034 wtx.strFromAccount = strAccount;
1035 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
1036 wtx.mapValue["comment"] = params[3].get_str();
1038 set<CBitcoinAddress> setAddress;
1039 vector<pair<CScript, int64> > vecSend;
1041 int64 totalAmount = 0;
1042 BOOST_FOREACH(const Pair& s, sendTo)
1044 CBitcoinAddress address(s.name_);
1045 if (!address.IsValid())
1046 throw JSONRPCError(-5, string("Invalid novacoin address:")+s.name_);
1048 if (setAddress.count(address))
1049 throw JSONRPCError(-8, string("Invalid parameter, duplicated address: ")+s.name_);
1050 setAddress.insert(address);
1052 CScript scriptPubKey;
1053 scriptPubKey.SetBitcoinAddress(address);
1054 int64 nAmount = AmountFromValue(s.value_);
1055 if (nAmount < MIN_TXOUT_AMOUNT)
1056 throw JSONRPCError(-101, "Send amount too small");
1057 totalAmount += nAmount;
1059 vecSend.push_back(make_pair(scriptPubKey, nAmount));
1062 if (pwalletMain->IsLocked())
1063 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
1064 if (fWalletUnlockMintOnly)
1065 throw JSONRPCError(-13, "Error: Wallet unlocked for block minting only.");
1068 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
1069 if (totalAmount > nBalance)
1070 throw JSONRPCError(-6, "Account has insufficient funds");
1073 CReserveKey keyChange(pwalletMain);
1074 int64 nFeeRequired = 0;
1075 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
1078 if (totalAmount + nFeeRequired > pwalletMain->GetBalance())
1079 throw JSONRPCError(-6, "Insufficient funds");
1080 throw JSONRPCError(-4, "Transaction creation failed");
1082 if (!pwalletMain->CommitTransaction(wtx, keyChange))
1083 throw JSONRPCError(-4, "Transaction commit failed");
1085 return wtx.GetHash().GetHex();
1088 Value addmultisigaddress(const Array& params, bool fHelp)
1090 if (fHelp || params.size() < 2 || params.size() > 3)
1092 string msg = "addmultisigaddress <nrequired> <'[\"key\",\"key\"]'> [account]\n"
1093 "Add a nrequired-to-sign multisignature address to the wallet\"\n"
1094 "each key is a bitcoin address or hex-encoded public key\n"
1095 "If [account] is specified, assign address to [account].";
1096 throw runtime_error(msg);
1099 int nRequired = params[0].get_int();
1100 const Array& keys = params[1].get_array();
1102 if (params.size() > 2)
1103 strAccount = AccountFromValue(params[2]);
1105 // Gather public keys
1107 throw runtime_error("a multisignature address must require at least one key to redeem");
1108 if ((int)keys.size() < nRequired)
1109 throw runtime_error(
1110 strprintf("not enough keys supplied "
1111 "(got %d keys, but need at least %d to redeem)", keys.size(), nRequired));
1112 std::vector<CKey> pubkeys;
1113 pubkeys.resize(keys.size());
1114 for (unsigned int i = 0; i < keys.size(); i++)
1116 const std::string& ks = keys[i].get_str();
1118 // Case 1: bitcoin address and we have full public key:
1119 CBitcoinAddress address(ks);
1120 if (address.IsValid())
1122 if (address.IsScript())
1123 throw runtime_error(
1124 strprintf("%s is a pay-to-script address",ks.c_str()));
1125 std::vector<unsigned char> vchPubKey;
1126 if (!pwalletMain->GetPubKey(address, vchPubKey))
1127 throw runtime_error(
1128 strprintf("no full public key for address %s",ks.c_str()));
1129 if (vchPubKey.empty() || !pubkeys[i].SetPubKey(vchPubKey))
1130 throw runtime_error(" Invalid public key: "+ks);
1133 // Case 2: hex public key
1136 vector<unsigned char> vchPubKey = ParseHex(ks);
1137 if (vchPubKey.empty() || !pubkeys[i].SetPubKey(vchPubKey))
1138 throw runtime_error(" Invalid public key: "+ks);
1142 throw runtime_error(" Invalid public key: "+ks);
1146 // Construct using pay-to-script-hash:
1148 inner.SetMultisig(nRequired, pubkeys);
1150 uint160 scriptHash = Hash160(inner);
1151 CScript scriptPubKey;
1152 scriptPubKey.SetPayToScriptHash(inner);
1153 pwalletMain->AddCScript(inner);
1154 CBitcoinAddress address;
1155 address.SetScriptHash160(scriptHash);
1157 pwalletMain->SetAddressBookName(address, strAccount);
1158 return address.ToString();
1169 nConf = std::numeric_limits<int>::max();
1173 Value ListReceived(const Array& params, bool fByAccounts)
1175 // Minimum confirmations
1177 if (params.size() > 0)
1178 nMinDepth = params[0].get_int();
1180 // Whether to include empty accounts
1181 bool fIncludeEmpty = false;
1182 if (params.size() > 1)
1183 fIncludeEmpty = params[1].get_bool();
1186 map<CBitcoinAddress, tallyitem> mapTally;
1187 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1189 const CWalletTx& wtx = (*it).second;
1191 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
1194 int nDepth = wtx.GetDepthInMainChain();
1195 if (nDepth < nMinDepth)
1198 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
1200 CBitcoinAddress address;
1201 if (!ExtractAddress(txout.scriptPubKey, address) || !pwalletMain->HaveKey(address) || !address.IsValid())
1204 tallyitem& item = mapTally[address];
1205 item.nAmount += txout.nValue;
1206 item.nConf = min(item.nConf, nDepth);
1212 map<string, tallyitem> mapAccountTally;
1213 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
1215 const CBitcoinAddress& address = item.first;
1216 const string& strAccount = item.second;
1217 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
1218 if (it == mapTally.end() && !fIncludeEmpty)
1222 int nConf = std::numeric_limits<int>::max();
1223 if (it != mapTally.end())
1225 nAmount = (*it).second.nAmount;
1226 nConf = (*it).second.nConf;
1231 tallyitem& item = mapAccountTally[strAccount];
1232 item.nAmount += nAmount;
1233 item.nConf = min(item.nConf, nConf);
1238 obj.push_back(Pair("address", address.ToString()));
1239 obj.push_back(Pair("account", strAccount));
1240 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1241 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1248 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
1250 int64 nAmount = (*it).second.nAmount;
1251 int nConf = (*it).second.nConf;
1253 obj.push_back(Pair("account", (*it).first));
1254 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1255 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1263 Value listreceivedbyaddress(const Array& params, bool fHelp)
1265 if (fHelp || params.size() > 2)
1266 throw runtime_error(
1267 "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
1268 "[minconf] is the minimum number of confirmations before payments are included.\n"
1269 "[includeempty] whether to include addresses that haven't received any payments.\n"
1270 "Returns an array of objects containing:\n"
1271 " \"address\" : receiving address\n"
1272 " \"account\" : the account of the receiving address\n"
1273 " \"amount\" : total amount received by the address\n"
1274 " \"confirmations\" : number of confirmations of the most recent transaction included");
1276 return ListReceived(params, false);
1279 Value listreceivedbyaccount(const Array& params, bool fHelp)
1281 if (fHelp || params.size() > 2)
1282 throw runtime_error(
1283 "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
1284 "[minconf] is the minimum number of confirmations before payments are included.\n"
1285 "[includeempty] whether to include accounts that haven't received any payments.\n"
1286 "Returns an array of objects containing:\n"
1287 " \"account\" : the account of the receiving addresses\n"
1288 " \"amount\" : total amount received by addresses with this account\n"
1289 " \"confirmations\" : number of confirmations of the most recent transaction included");
1291 return ListReceived(params, true);
1294 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret)
1296 int64 nGeneratedImmature, nGeneratedMature, nFee;
1297 string strSentAccount;
1298 list<pair<CBitcoinAddress, int64> > listReceived;
1299 list<pair<CBitcoinAddress, int64> > listSent;
1301 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1303 bool fAllAccounts = (strAccount == string("*"));
1305 // Generated blocks assigned to account ""
1306 if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == ""))
1309 entry.push_back(Pair("account", string("")));
1310 if (nGeneratedImmature)
1312 entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
1313 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
1317 entry.push_back(Pair("category", "generate"));
1318 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
1321 WalletTxToJSON(wtx, entry);
1322 ret.push_back(entry);
1326 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1328 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1331 entry.push_back(Pair("account", strSentAccount));
1332 entry.push_back(Pair("address", s.first.ToString()));
1333 entry.push_back(Pair("category", "send"));
1334 entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1335 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1337 WalletTxToJSON(wtx, entry);
1338 ret.push_back(entry);
1343 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1345 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1348 if (pwalletMain->mapAddressBook.count(r.first))
1349 account = pwalletMain->mapAddressBook[r.first];
1350 if (fAllAccounts || (account == strAccount))
1353 entry.push_back(Pair("account", account));
1354 entry.push_back(Pair("address", r.first.ToString()));
1355 entry.push_back(Pair("category", "receive"));
1356 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1358 WalletTxToJSON(wtx, entry);
1359 ret.push_back(entry);
1365 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1367 bool fAllAccounts = (strAccount == string("*"));
1369 if (fAllAccounts || acentry.strAccount == strAccount)
1372 entry.push_back(Pair("account", acentry.strAccount));
1373 entry.push_back(Pair("category", "move"));
1374 entry.push_back(Pair("time", (boost::int64_t)acentry.nTime));
1375 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1376 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1377 entry.push_back(Pair("comment", acentry.strComment));
1378 ret.push_back(entry);
1382 Value listtransactions(const Array& params, bool fHelp)
1384 if (fHelp || params.size() > 3)
1385 throw runtime_error(
1386 "listtransactions [account] [count=10] [from=0]\n"
1387 "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1389 string strAccount = "*";
1390 if (params.size() > 0)
1391 strAccount = params[0].get_str();
1393 if (params.size() > 1)
1394 nCount = params[1].get_int();
1396 if (params.size() > 2)
1397 nFrom = params[2].get_int();
1400 throw JSONRPCError(-8, "Negative count");
1402 throw JSONRPCError(-8, "Negative from");
1405 CWalletDB walletdb(pwalletMain->strWalletFile);
1407 // First: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap.
1408 typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
1409 typedef multimap<int64, TxPair > TxItems;
1412 // Note: maintaining indices in the database of (account,time) --> txid and (account, time) --> acentry
1413 // would make this much faster for applications that do this a lot.
1414 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1416 CWalletTx* wtx = &((*it).second);
1417 txByTime.insert(make_pair(wtx->GetTxTime(), TxPair(wtx, (CAccountingEntry*)0)));
1419 list<CAccountingEntry> acentries;
1420 walletdb.ListAccountCreditDebit(strAccount, acentries);
1421 BOOST_FOREACH(CAccountingEntry& entry, acentries)
1423 txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
1426 // iterate backwards until we have nCount items to return:
1427 for (TxItems::reverse_iterator it = txByTime.rbegin(); it != txByTime.rend(); ++it)
1429 CWalletTx *const pwtx = (*it).second.first;
1431 ListTransactions(*pwtx, strAccount, 0, true, ret);
1432 CAccountingEntry *const pacentry = (*it).second.second;
1434 AcentryToJSON(*pacentry, strAccount, ret);
1436 if (ret.size() >= (nCount+nFrom)) break;
1438 // ret is newest to oldest
1440 if (nFrom > (int)ret.size())
1442 if ((nFrom + nCount) > (int)ret.size())
1443 nCount = ret.size() - nFrom;
1444 Array::iterator first = ret.begin();
1445 std::advance(first, nFrom);
1446 Array::iterator last = ret.begin();
1447 std::advance(last, nFrom+nCount);
1449 if (last != ret.end()) ret.erase(last, ret.end());
1450 if (first != ret.begin()) ret.erase(ret.begin(), first);
1452 std::reverse(ret.begin(), ret.end()); // Return oldest to newest
1457 Value listaccounts(const Array& params, bool fHelp)
1459 if (fHelp || params.size() > 1)
1460 throw runtime_error(
1461 "listaccounts [minconf=1]\n"
1462 "Returns Object that has account names as keys, account balances as values.");
1465 if (params.size() > 0)
1466 nMinDepth = params[0].get_int();
1468 map<string, int64> mapAccountBalances;
1469 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& entry, pwalletMain->mapAddressBook) {
1470 if (pwalletMain->HaveKey(entry.first)) // This address belongs to me
1471 mapAccountBalances[entry.second] = 0;
1474 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1476 const CWalletTx& wtx = (*it).second;
1477 int64 nGeneratedImmature, nGeneratedMature, nFee;
1478 string strSentAccount;
1479 list<pair<CBitcoinAddress, int64> > listReceived;
1480 list<pair<CBitcoinAddress, int64> > listSent;
1481 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1482 mapAccountBalances[strSentAccount] -= nFee;
1483 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1484 mapAccountBalances[strSentAccount] -= s.second;
1485 if (wtx.GetDepthInMainChain() >= nMinDepth)
1487 mapAccountBalances[""] += nGeneratedMature;
1488 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1489 if (pwalletMain->mapAddressBook.count(r.first))
1490 mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1492 mapAccountBalances[""] += r.second;
1496 list<CAccountingEntry> acentries;
1497 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1498 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1499 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1502 BOOST_FOREACH(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) {
1503 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1508 Value listsinceblock(const Array& params, bool fHelp)
1511 throw runtime_error(
1512 "listsinceblock [blockhash] [target-confirmations]\n"
1513 "Get all transactions in blocks since block [blockhash], or all transactions if omitted");
1515 CBlockIndex *pindex = NULL;
1516 int target_confirms = 1;
1518 if (params.size() > 0)
1520 uint256 blockId = 0;
1522 blockId.SetHex(params[0].get_str());
1523 pindex = CBlockLocator(blockId).GetBlockIndex();
1526 if (params.size() > 1)
1528 target_confirms = params[1].get_int();
1530 if (target_confirms < 1)
1531 throw JSONRPCError(-8, "Invalid parameter");
1534 int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1;
1538 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1540 CWalletTx tx = (*it).second;
1542 if (depth == -1 || tx.GetDepthInMainChain() < depth)
1543 ListTransactions(tx, "*", 0, true, transactions);
1548 if (target_confirms == 1)
1550 lastblock = hashBestChain;
1554 int target_height = pindexBest->nHeight + 1 - target_confirms;
1557 for (block = pindexBest;
1558 block && block->nHeight > target_height;
1559 block = block->pprev) { }
1561 lastblock = block ? block->GetBlockHash() : 0;
1565 ret.push_back(Pair("transactions", transactions));
1566 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1571 Value gettransaction(const Array& params, bool fHelp)
1573 if (fHelp || params.size() != 1)
1574 throw runtime_error(
1575 "gettransaction <txid>\n"
1576 "Get detailed information about <txid>");
1579 hash.SetHex(params[0].get_str());
1583 if (pwalletMain->mapWallet.count(hash))
1585 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1587 TxToJSON(wtx, entry);
1589 int64 nCredit = wtx.GetCredit();
1590 int64 nDebit = wtx.GetDebit();
1591 int64 nNet = nCredit - nDebit;
1592 int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
1594 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1596 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1598 WalletTxToJSON(wtx, entry);
1601 ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
1602 entry.push_back(Pair("details", details));
1607 uint256 hashBlock = 0;
1608 if (GetTransaction(hash, tx, hashBlock))
1610 entry.push_back(Pair("txid", hash.GetHex()));
1611 TxToJSON(tx, entry);
1613 entry.push_back(Pair("confirmations", 0));
1616 entry.push_back(Pair("blockhash", hashBlock.GetHex()));
1617 map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
1618 if (mi != mapBlockIndex.end() && (*mi).second)
1620 CBlockIndex* pindex = (*mi).second;
1621 if (pindex->IsInMainChain())
1623 entry.push_back(Pair("confirmations", 1 + nBestHeight - pindex->nHeight));
1624 entry.push_back(Pair("time", (boost::int64_t)pindex->nTime));
1627 entry.push_back(Pair("confirmations", 0));
1632 throw JSONRPCError(-5, "No information available about transaction");
1639 Value backupwallet(const Array& params, bool fHelp)
1641 if (fHelp || params.size() != 1)
1642 throw runtime_error(
1643 "backupwallet <destination>\n"
1644 "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1646 string strDest = params[0].get_str();
1647 BackupWallet(*pwalletMain, strDest);
1653 Value keypoolrefill(const Array& params, bool fHelp)
1655 if (pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1656 throw runtime_error(
1658 "Fills the keypool, requires wallet passphrase to be set.");
1659 if (!pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1660 throw runtime_error(
1662 "Fills the keypool.");
1664 if (pwalletMain->IsLocked())
1665 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
1667 pwalletMain->TopUpKeyPool();
1669 if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100))
1670 throw JSONRPCError(-4, "Error refreshing keypool.");
1676 void ThreadTopUpKeyPool(void* parg)
1678 pwalletMain->TopUpKeyPool();
1681 void ThreadCleanWalletPassphrase(void* parg)
1683 int64 nMyWakeTime = GetTimeMillis() + *((int64*)parg) * 1000;
1685 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1687 if (nWalletUnlockTime == 0)
1689 nWalletUnlockTime = nMyWakeTime;
1693 if (nWalletUnlockTime==0)
1695 int64 nToSleep = nWalletUnlockTime - GetTimeMillis();
1699 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1701 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1705 if (nWalletUnlockTime)
1707 nWalletUnlockTime = 0;
1708 pwalletMain->Lock();
1713 if (nWalletUnlockTime < nMyWakeTime)
1714 nWalletUnlockTime = nMyWakeTime;
1717 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1719 delete (int64*)parg;
1722 Value walletpassphrase(const Array& params, bool fHelp)
1724 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 3))
1725 throw runtime_error(
1726 "walletpassphrase <passphrase> <timeout> [mintonly]\n"
1727 "Stores the wallet decryption key in memory for <timeout> seconds.\n"
1728 "mintonly is optional true/false allowing only block minting.");
1731 if (!pwalletMain->IsCrypted())
1732 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1734 if (!pwalletMain->IsLocked())
1735 throw JSONRPCError(-17, "Error: Wallet is already unlocked, use walletlock first if need to change unlock settings.");
1737 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1738 SecureString strWalletPass;
1739 strWalletPass.reserve(100);
1740 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1741 // Alternately, find a way to make params[0] mlock()'d to begin with.
1742 strWalletPass = params[0].get_str().c_str();
1744 if (strWalletPass.length() > 0)
1746 if (!pwalletMain->Unlock(strWalletPass))
1747 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1750 throw runtime_error(
1751 "walletpassphrase <passphrase> <timeout>\n"
1752 "Stores the wallet decryption key in memory for <timeout> seconds.");
1754 CreateThread(ThreadTopUpKeyPool, NULL);
1755 int64* pnSleepTime = new int64(params[1].get_int64());
1756 CreateThread(ThreadCleanWalletPassphrase, pnSleepTime);
1758 // ppcoin: if user OS account compromised prevent trivial sendmoney commands
1759 if (params.size() > 2)
1760 fWalletUnlockMintOnly = params[2].get_bool();
1762 fWalletUnlockMintOnly = false;
1768 Value walletpassphrasechange(const Array& params, bool fHelp)
1770 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1771 throw runtime_error(
1772 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1773 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1776 if (!pwalletMain->IsCrypted())
1777 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1779 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1780 // Alternately, find a way to make params[0] mlock()'d to begin with.
1781 SecureString strOldWalletPass;
1782 strOldWalletPass.reserve(100);
1783 strOldWalletPass = params[0].get_str().c_str();
1785 SecureString strNewWalletPass;
1786 strNewWalletPass.reserve(100);
1787 strNewWalletPass = params[1].get_str().c_str();
1789 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1790 throw runtime_error(
1791 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1792 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1794 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1795 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1801 Value walletlock(const Array& params, bool fHelp)
1803 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1804 throw runtime_error(
1806 "Removes the wallet encryption key from memory, locking the wallet.\n"
1807 "After calling this method, you will need to call walletpassphrase again\n"
1808 "before being able to call any methods which require the wallet to be unlocked.");
1811 if (!pwalletMain->IsCrypted())
1812 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called.");
1815 LOCK(cs_nWalletUnlockTime);
1816 pwalletMain->Lock();
1817 nWalletUnlockTime = 0;
1824 Value encryptwallet(const Array& params, bool fHelp)
1826 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1827 throw runtime_error(
1828 "encryptwallet <passphrase>\n"
1829 "Encrypts the wallet with <passphrase>.");
1832 if (pwalletMain->IsCrypted())
1833 throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
1835 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1836 // Alternately, find a way to make params[0] mlock()'d to begin with.
1837 SecureString strWalletPass;
1838 strWalletPass.reserve(100);
1839 strWalletPass = params[0].get_str().c_str();
1841 if (strWalletPass.length() < 1)
1842 throw runtime_error(
1843 "encryptwallet <passphrase>\n"
1844 "Encrypts the wallet with <passphrase>.");
1846 if (!pwalletMain->EncryptWallet(strWalletPass))
1847 throw JSONRPCError(-16, "Error: Failed to encrypt the wallet.");
1849 // BDB seems to have a bad habit of writing old data into
1850 // slack space in .dat files; that is bad if the old data is
1851 // unencrypted private keys. So:
1853 return "wallet encrypted; novacoin server stopping, restart to run with encrypted wallet";
1857 Value validateaddress(const Array& params, bool fHelp)
1859 if (fHelp || params.size() != 1)
1860 throw runtime_error(
1861 "validateaddress <novacoinaddress>\n"
1862 "Return information about <novacoinaddress>.");
1864 CBitcoinAddress address(params[0].get_str());
1865 bool isValid = address.IsValid();
1868 ret.push_back(Pair("isvalid", isValid));
1871 // Call Hash160ToAddress() so we always return current ADDRESSVERSION
1872 // version of the address:
1873 string currentAddress = address.ToString();
1874 ret.push_back(Pair("address", currentAddress));
1875 if (pwalletMain->HaveKey(address))
1877 ret.push_back(Pair("ismine", true));
1878 std::vector<unsigned char> vchPubKey;
1879 pwalletMain->GetPubKey(address, vchPubKey);
1880 ret.push_back(Pair("pubkey", HexStr(vchPubKey)));
1882 key.SetPubKey(vchPubKey);
1883 ret.push_back(Pair("iscompressed", key.IsCompressed()));
1885 else if (pwalletMain->HaveCScript(address.GetHash160()))
1887 ret.push_back(Pair("isscript", true));
1889 pwalletMain->GetCScript(address.GetHash160(), subscript);
1890 ret.push_back(Pair("ismine", ::IsMine(*pwalletMain, subscript)));
1891 std::vector<CBitcoinAddress> addresses;
1892 txnouttype whichType;
1894 ExtractAddresses(subscript, whichType, addresses, nRequired);
1895 ret.push_back(Pair("script", GetTxnOutputType(whichType)));
1897 BOOST_FOREACH(const CBitcoinAddress& addr, addresses)
1898 a.push_back(addr.ToString());
1899 ret.push_back(Pair("addresses", a));
1900 if (whichType == TX_MULTISIG)
1901 ret.push_back(Pair("sigsrequired", nRequired));
1904 ret.push_back(Pair("ismine", false));
1905 if (pwalletMain->mapAddressBook.count(address))
1906 ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
1911 Value validatepubkey(const Array& params, bool fHelp)
1913 if (fHelp || !params.size() || params.size() > 2)
1914 throw runtime_error(
1915 "validatepubkey <novacoinpubkey>\n"
1916 "Return information about <novacoinpubkey>.");
1918 std::vector<unsigned char> vchPubKey = ParseHex(params[0].get_str());
1921 if(vchPubKey.size() == 33) // Compressed key
1922 isValid = (vchPubKey[0] == 0x02 || vchPubKey[0] == 0x03);
1923 else if(vchPubKey.size() == 65) // Uncompressed key
1924 isValid = vchPubKey[0] == 0x04;
1928 CBitcoinAddress address(vchPubKey);
1929 isValid = isValid ? address.IsValid() : false;
1932 ret.push_back(Pair("isvalid", isValid));
1935 // Call Hash160ToAddress() so we always return current ADDRESSVERSION
1936 // version of the address:
1937 string currentAddress = address.ToString();
1938 ret.push_back(Pair("address", currentAddress));
1939 if (pwalletMain->HaveKey(address))
1941 ret.push_back(Pair("ismine", true));
1943 key.SetPubKey(vchPubKey);
1944 ret.push_back(Pair("iscompressed", key.IsCompressed()));
1947 ret.push_back(Pair("ismine", false));
1948 if (pwalletMain->mapAddressBook.count(address))
1949 ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
1954 Value getworkex(const Array& params, bool fHelp)
1956 if (fHelp || params.size() > 2)
1957 throw runtime_error(
1958 "getworkex [data, coinbase]\n"
1959 "If [data, coinbase] is not specified, returns extended work data.\n"
1963 throw JSONRPCError(-9, "NovaCoin is not connected!");
1965 if (IsInitialBlockDownload())
1966 throw JSONRPCError(-10, "NovaCoin is downloading blocks...");
1968 typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
1969 static mapNewBlock_t mapNewBlock;
1970 static vector<CBlock*> vNewBlock;
1971 static CReserveKey reservekey(pwalletMain);
1973 if (params.size() == 0)
1976 static unsigned int nTransactionsUpdatedLast;
1977 static CBlockIndex* pindexPrev;
1978 static int64 nStart;
1979 static CBlock* pblock;
1980 if (pindexPrev != pindexBest ||
1981 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
1983 if (pindexPrev != pindexBest)
1985 // Deallocate old blocks since they're obsolete now
1986 mapNewBlock.clear();
1987 BOOST_FOREACH(CBlock* pblock, vNewBlock)
1991 nTransactionsUpdatedLast = nTransactionsUpdated;
1992 pindexPrev = pindexBest;
1996 pblock = CreateNewBlock(pwalletMain);
1998 throw JSONRPCError(-7, "Out of memory");
1999 vNewBlock.push_back(pblock);
2003 pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
2006 // Update nExtraNonce
2007 static unsigned int nExtraNonce = 0;
2008 IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
2011 mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
2013 // Prebuild hash buffers
2017 FormatHashBuffers(pblock, pmidstate, pdata, phash1);
2019 uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
2021 CTransaction coinbaseTx = pblock->vtx[0];
2022 std::vector<uint256> merkle = pblock->GetMerkleBranch(0);
2025 result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata))));
2026 result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
2028 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
2030 result.push_back(Pair("coinbase", HexStr(ssTx.begin(), ssTx.end())));
2033 printf("DEBUG: merkle size %i\n", merkle.size());
2035 BOOST_FOREACH(uint256 merkleh, merkle) {
2036 printf("%s\n", merkleh.ToString().c_str());
2037 merkle_arr.push_back(HexStr(BEGIN(merkleh), END(merkleh)));
2040 result.push_back(Pair("merkle", merkle_arr));
2048 vector<unsigned char> vchData = ParseHex(params[0].get_str());
2049 vector<unsigned char> coinbase;
2051 if(params.size() == 2)
2052 coinbase = ParseHex(params[1].get_str());
2054 if (vchData.size() != 128)
2055 throw JSONRPCError(-8, "Invalid parameter");
2057 CBlock* pdata = (CBlock*)&vchData[0];
2060 for (int i = 0; i < 128/4; i++)
2061 ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]);
2064 if (!mapNewBlock.count(pdata->hashMerkleRoot))
2066 CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
2068 pblock->nTime = pdata->nTime;
2069 pblock->nNonce = pdata->nNonce;
2071 if(coinbase.size() == 0)
2072 pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
2074 CDataStream(coinbase, SER_NETWORK, PROTOCOL_VERSION) >> pblock->vtx[0]; // FIXME - HACK!
2076 pblock->hashMerkleRoot = pblock->BuildMerkleTree();
2078 if (!pblock->SignBlock(*pwalletMain))
2079 throw JSONRPCError(-100, "Unable to sign block, wallet locked?");
2081 return CheckWork(pblock, *pwalletMain, reservekey);
2086 Value getwork(const Array& params, bool fHelp)
2088 if (fHelp || params.size() > 1)
2089 throw runtime_error(
2091 "If [data] is not specified, returns formatted hash data to work on:\n"
2092 " \"midstate\" : precomputed hash state after hashing the first half of the data (DEPRECATED)\n" // deprecated
2093 " \"data\" : block data\n"
2094 " \"hash1\" : formatted hash buffer for second hash (DEPRECATED)\n" // deprecated
2095 " \"target\" : little endian hash target\n"
2096 "If [data] is specified, tries to solve the block and returns true if it was successful.");
2099 throw JSONRPCError(-9, "NovaCoin is not connected!");
2101 if (IsInitialBlockDownload())
2102 throw JSONRPCError(-10, "NovaCoin is downloading blocks...");
2104 typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
2105 static mapNewBlock_t mapNewBlock;
2106 static vector<CBlock*> vNewBlock;
2107 static CReserveKey reservekey(pwalletMain);
2109 if (params.size() == 0)
2112 static unsigned int nTransactionsUpdatedLast;
2113 static CBlockIndex* pindexPrev;
2114 static int64 nStart;
2115 static CBlock* pblock;
2116 if (pindexPrev != pindexBest ||
2117 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
2119 if (pindexPrev != pindexBest)
2121 // Deallocate old blocks since they're obsolete now
2122 mapNewBlock.clear();
2123 BOOST_FOREACH(CBlock* pblock, vNewBlock)
2127 nTransactionsUpdatedLast = nTransactionsUpdated;
2128 pindexPrev = pindexBest;
2132 pblock = CreateNewBlock(pwalletMain);
2134 throw JSONRPCError(-7, "Out of memory");
2135 vNewBlock.push_back(pblock);
2139 pblock->UpdateTime(pindexPrev);
2142 // Update nExtraNonce
2143 static unsigned int nExtraNonce = 0;
2144 IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
2147 mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
2149 // Prebuild hash buffers
2153 FormatHashBuffers(pblock, pmidstate, pdata, phash1);
2155 uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
2158 result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate)))); // deprecated
2159 result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata))));
2160 result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1)))); // deprecated
2161 result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
2167 vector<unsigned char> vchData = ParseHex(params[0].get_str());
2168 if (vchData.size() != 128)
2169 throw JSONRPCError(-8, "Invalid parameter");
2170 CBlock* pdata = (CBlock*)&vchData[0];
2173 for (int i = 0; i < 128/4; i++)
2174 ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]);
2177 if (!mapNewBlock.count(pdata->hashMerkleRoot))
2179 CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
2181 pblock->nTime = pdata->nTime;
2182 pblock->nNonce = pdata->nNonce;
2183 pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
2184 pblock->hashMerkleRoot = pblock->BuildMerkleTree();
2185 if (!pblock->SignBlock(*pwalletMain))
2186 throw JSONRPCError(-100, "Unable to sign block, wallet locked?");
2188 return CheckWork(pblock, *pwalletMain, reservekey);
2192 Value getblocktemplate(const Array& params, bool fHelp)
2194 if (fHelp || params.size() > 1)
2195 throw runtime_error(
2196 "getblocktemplate [params]\n"
2197 "Returns data needed to construct a block to work on:\n"
2198 " \"version\" : block version\n"
2199 " \"previousblockhash\" : hash of current highest block\n"
2200 " \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
2201 " \"coinbaseaux\" : data that should be included in coinbase\n"
2202 " \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
2203 " \"target\" : hash target\n"
2204 " \"mintime\" : minimum timestamp appropriate for next block\n"
2205 " \"curtime\" : current timestamp\n"
2206 " \"mutable\" : list of ways the block template may be changed\n"
2207 " \"noncerange\" : range of valid nonces\n"
2208 " \"sigoplimit\" : limit of sigops in blocks\n"
2209 " \"sizelimit\" : limit of block size\n"
2210 " \"bits\" : compressed target of next block\n"
2211 " \"height\" : height of the next block\n"
2212 "See https://en.bitcoin.it/wiki/BIP_0022 for full specification.");
2214 std::string strMode = "template";
2215 if (params.size() > 0)
2217 const Object& oparam = params[0].get_obj();
2218 const Value& modeval = find_value(oparam, "mode");
2219 if (modeval.type() == str_type)
2220 strMode = modeval.get_str();
2222 throw JSONRPCError(-8, "Invalid mode");
2225 if (strMode != "template")
2226 throw JSONRPCError(-8, "Invalid mode");
2229 throw JSONRPCError(-9, "NovaCoin is not connected!");
2231 if (IsInitialBlockDownload())
2232 throw JSONRPCError(-10, "NovaCoin is downloading blocks...");
2234 static CReserveKey reservekey(pwalletMain);
2237 static unsigned int nTransactionsUpdatedLast;
2238 static CBlockIndex* pindexPrev;
2239 static int64 nStart;
2240 static CBlock* pblock;
2241 if (pindexPrev != pindexBest ||
2242 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5))
2244 // Clear pindexPrev so future calls make a new block, despite any failures from here on
2247 // Store the pindexBest used before CreateNewBlock, to avoid races
2248 nTransactionsUpdatedLast = nTransactionsUpdated;
2249 CBlockIndex* pindexPrevNew = pindexBest;
2258 pblock = CreateNewBlock(pwalletMain);
2260 throw JSONRPCError(-7, "Out of memory");
2262 // Need to update only after we know CreateNewBlock succeeded
2263 pindexPrev = pindexPrevNew;
2267 pblock->UpdateTime(pindexPrev);
2271 map<uint256, int64_t> setTxIndex;
2274 BOOST_FOREACH (CTransaction& tx, pblock->vtx)
2276 uint256 txHash = tx.GetHash();
2277 setTxIndex[txHash] = i++;
2279 if (tx.IsCoinBase() || tx.IsCoinStake())
2284 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
2286 entry.push_back(Pair("data", HexStr(ssTx.begin(), ssTx.end())));
2288 entry.push_back(Pair("hash", txHash.GetHex()));
2290 MapPrevTx mapInputs;
2291 map<uint256, CTxIndex> mapUnused;
2292 bool fInvalid = false;
2293 if (tx.FetchInputs(txdb, mapUnused, false, false, mapInputs, fInvalid))
2295 entry.push_back(Pair("fee", (int64_t)(tx.GetValueIn(mapInputs) - tx.GetValueOut())));
2298 BOOST_FOREACH (MapPrevTx::value_type& inp, mapInputs)
2300 if (setTxIndex.count(inp.first))
2301 deps.push_back(setTxIndex[inp.first]);
2303 entry.push_back(Pair("depends", deps));
2305 int64_t nSigOps = tx.GetLegacySigOpCount();
2306 nSigOps += tx.GetP2SHSigOpCount(mapInputs);
2307 entry.push_back(Pair("sigops", nSigOps));
2310 transactions.push_back(entry);
2314 aux.push_back(Pair("flags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end())));
2316 uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
2318 static Array aMutable;
2319 if (aMutable.empty())
2321 aMutable.push_back("time");
2322 aMutable.push_back("transactions");
2323 aMutable.push_back("prevblock");
2327 result.push_back(Pair("version", pblock->nVersion));
2328 result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
2329 result.push_back(Pair("transactions", transactions));
2330 result.push_back(Pair("coinbaseaux", aux));
2331 result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
2332 result.push_back(Pair("target", hashTarget.GetHex()));
2333 result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1));
2334 result.push_back(Pair("mutable", aMutable));
2335 result.push_back(Pair("noncerange", "00000000ffffffff"));
2336 result.push_back(Pair("sigoplimit", (int64_t)MAX_BLOCK_SIGOPS));
2337 result.push_back(Pair("sizelimit", (int64_t)MAX_BLOCK_SIZE));
2338 result.push_back(Pair("curtime", (int64_t)pblock->nTime));
2339 result.push_back(Pair("bits", HexBits(pblock->nBits)));
2340 result.push_back(Pair("height", (int64_t)(pindexPrev->nHeight+1)));
2345 Value submitblock(const Array& params, bool fHelp)
2347 if (fHelp || params.size() < 1 || params.size() > 2)
2348 throw runtime_error(
2349 "submitblock <hex data> [optional-params-obj]\n"
2350 "[optional-params-obj] parameter is currently ignored.\n"
2351 "Attempts to submit new block to network.\n"
2352 "See https://en.bitcoin.it/wiki/BIP_0022 for full specification.");
2354 vector<unsigned char> blockData(ParseHex(params[0].get_str()));
2355 CDataStream ssBlock(blockData, SER_NETWORK, PROTOCOL_VERSION);
2360 catch (std::exception &e) {
2361 throw JSONRPCError(-22, "Block decode failed");
2364 static CReserveKey reservekey(pwalletMain);
2366 if(!block.SignBlock(*pwalletMain))
2367 throw JSONRPCError(-100, "Unable to sign block, wallet locked?");
2369 bool fAccepted = CheckWork(&block, *pwalletMain, reservekey);
2377 Value getmemorypool(const Array& params, bool fHelp)
2379 if (fHelp || params.size() > 1)
2380 throw runtime_error(
2381 "getmemorypool [data]\n"
2382 "If [data] is not specified, returns data needed to construct a block to work on:\n"
2383 " \"version\" : block version\n"
2384 " \"previousblockhash\" : hash of current highest block\n"
2385 " \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
2386 " \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
2387 " \"coinbaseflags\" : data that should be included in coinbase so support for new features can be judged\n"
2388 " \"time\" : timestamp appropriate for next block\n"
2389 " \"mintime\" : minimum timestamp appropriate for next block\n"
2390 " \"curtime\" : current timestamp\n"
2391 " \"bits\" : compressed target of next block\n"
2392 "If [data] is specified, tries to solve the block and returns true if it was successful.");
2394 if (params.size() == 0)
2397 throw JSONRPCError(-9, "NovaCoin is not connected!");
2399 if (IsInitialBlockDownload())
2400 throw JSONRPCError(-10, "NovaCoin is downloading blocks...");
2402 static CReserveKey reservekey(pwalletMain);
2405 static unsigned int nTransactionsUpdatedLast;
2406 static CBlockIndex* pindexPrev;
2407 static int64 nStart;
2408 static CBlock* pblock;
2409 if (pindexPrev != pindexBest ||
2410 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5))
2412 nTransactionsUpdatedLast = nTransactionsUpdated;
2413 pindexPrev = pindexBest;
2419 pblock = CreateNewBlock(pwalletMain);
2421 throw JSONRPCError(-7, "Out of memory");
2425 pblock->UpdateTime(pindexPrev);
2429 BOOST_FOREACH(CTransaction tx, pblock->vtx) {
2430 if(tx.IsCoinBase() || tx.IsCoinStake())
2433 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
2436 transactions.push_back(HexStr(ssTx.begin(), ssTx.end()));
2440 result.push_back(Pair("version", pblock->nVersion));
2441 result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
2442 result.push_back(Pair("transactions", transactions));
2443 result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
2444 result.push_back(Pair("coinbaseflags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end())));
2445 result.push_back(Pair("time", (int64_t)pblock->nTime));
2446 result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1));
2447 result.push_back(Pair("curtime", (int64_t)GetAdjustedTime()));
2448 result.push_back(Pair("bits", HexBits(pblock->nBits)));
2455 CDataStream ssBlock(ParseHex(params[0].get_str()), SER_NETWORK, PROTOCOL_VERSION);
2459 static CReserveKey reservekey(pwalletMain);
2461 if(!pblock.SignBlock(*pwalletMain))
2462 throw JSONRPCError(-100, "Unable to sign block, wallet locked?");
2464 return CheckWork(&pblock, *pwalletMain, reservekey);
2468 Value getnewpubkey(const Array& params, bool fHelp)
2470 if (fHelp || params.size() > 1)
2471 throw runtime_error(
2472 "getnewpubkey [account]\n"
2473 "Returns new public key for coinbase generation.");
2475 // Parse the account first so we don't generate a key if there's an error
2477 if (params.size() > 0)
2478 strAccount = AccountFromValue(params[0]);
2480 if (!pwalletMain->IsLocked())
2481 pwalletMain->TopUpKeyPool();
2483 // Generate a new key that is added to wallet
2484 std::vector<unsigned char> newKey = pwalletMain->GenerateNewKey(false);
2487 throw JSONRPCError(-12, "Error: Unable to create key");
2489 CBitcoinAddress address(newKey);
2490 pwalletMain->SetAddressBookName(address, strAccount);
2492 return HexStr(newKey.begin(), newKey.end());
2495 Value getblockhash(const Array& params, bool fHelp)
2497 if (fHelp || params.size() != 1)
2498 throw runtime_error(
2499 "getblockhash <index>\n"
2500 "Returns hash of block in best-block-chain at <index>.");
2502 int nHeight = params[0].get_int();
2503 if (nHeight < 0 || nHeight > nBestHeight)
2504 throw runtime_error("Block number out of range.");
2507 CBlockIndex* pblockindex = mapBlockIndex[hashBestChain];
2508 while (pblockindex->nHeight > nHeight)
2509 pblockindex = pblockindex->pprev;
2510 return pblockindex->phashBlock->GetHex();
2513 Value getblock(const Array& params, bool fHelp)
2515 if (fHelp || params.size() < 1 || params.size() > 2)
2516 throw runtime_error(
2517 "getblock <hash> [txinfo]\n"
2518 "txinfo optional to print more detailed tx info\n"
2519 "Returns details of a block with given block-hash.");
2521 std::string strHash = params[0].get_str();
2522 uint256 hash(strHash);
2524 if (mapBlockIndex.count(hash) == 0)
2525 throw JSONRPCError(-5, "Block not found");
2528 CBlockIndex* pblockindex = mapBlockIndex[hash];
2529 block.ReadFromDisk(pblockindex, true);
2531 return blockToJSON(block, pblockindex, params.size() > 1 ? params[1].get_bool() : false);
2534 Value getblockbynumber(const Array& params, bool fHelp)
2536 if (fHelp || params.size() < 1 || params.size() > 2)
2537 throw runtime_error(
2538 "getblock <number> [txinfo]\n"
2539 "txinfo optional to print more detailed tx info\n"
2540 "Returns details of a block with given block-number.");
2542 int nHeight = params[0].get_int();
2543 if (nHeight < 0 || nHeight > nBestHeight)
2544 throw runtime_error("Block number out of range.");
2547 CBlockIndex* pblockindex = mapBlockIndex[hashBestChain];
2548 while (pblockindex->nHeight > nHeight)
2549 pblockindex = pblockindex->pprev;
2551 uint256 hash = *pblockindex->phashBlock;
2553 pblockindex = mapBlockIndex[hash];
2554 block.ReadFromDisk(pblockindex, true);
2556 return blockToJSON(block, pblockindex, params.size() > 1 ? params[1].get_bool() : false);
2559 // ppcoin: get information of sync-checkpoint
2560 Value getcheckpoint(const Array& params, bool fHelp)
2562 if (fHelp || params.size() != 0)
2563 throw runtime_error(
2565 "Show info of synchronized checkpoint.\n");
2568 CBlockIndex* pindexCheckpoint;
2570 result.push_back(Pair("synccheckpoint", Checkpoints::hashSyncCheckpoint.ToString().c_str()));
2571 pindexCheckpoint = mapBlockIndex[Checkpoints::hashSyncCheckpoint];
2572 result.push_back(Pair("height", pindexCheckpoint->nHeight));
2573 result.push_back(Pair("timestamp", DateTimeStrFormat(pindexCheckpoint->GetBlockTime()).c_str()));
2574 if (mapArgs.count("-checkpointkey"))
2575 result.push_back(Pair("checkpointmaster", true));
2581 // ppcoin: reserve balance from being staked for network protection
2582 Value reservebalance(const Array& params, bool fHelp)
2584 if (fHelp || params.size() > 2)
2585 throw runtime_error(
2586 "reservebalance [<reserve> [amount]]\n"
2587 "<reserve> is true or false to turn balance reserve on or off.\n"
2588 "<amount> is a real and rounded to cent.\n"
2589 "Set reserve amount not participating in network protection.\n"
2590 "If no parameters provided current setting is printed.\n");
2592 if (params.size() > 0)
2594 bool fReserve = params[0].get_bool();
2597 if (params.size() == 1)
2598 throw runtime_error("must provide amount to reserve balance.\n");
2599 int64 nAmount = AmountFromValue(params[1]);
2600 nAmount = (nAmount / CENT) * CENT; // round to cent
2602 throw runtime_error("amount cannot be negative.\n");
2603 mapArgs["-reservebalance"] = FormatMoney(nAmount).c_str();
2607 if (params.size() > 1)
2608 throw runtime_error("cannot specify amount to turn off reserve.\n");
2609 mapArgs["-reservebalance"] = "0";
2614 int64 nReserveBalance = 0;
2615 if (mapArgs.count("-reservebalance") && !ParseMoney(mapArgs["-reservebalance"], nReserveBalance))
2616 throw runtime_error("invalid reserve balance amount\n");
2617 result.push_back(Pair("reserve", (nReserveBalance > 0)));
2618 result.push_back(Pair("amount", ValueFromAmount(nReserveBalance)));
2623 // ppcoin: check wallet integrity
2624 Value checkwallet(const Array& params, bool fHelp)
2626 if (fHelp || params.size() > 0)
2627 throw runtime_error(
2629 "Check wallet for integrity.\n");
2632 int64 nBalanceInQuestion;
2633 pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion, true);
2635 if (nMismatchSpent == 0)
2636 result.push_back(Pair("wallet check passed", true));
2639 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
2640 result.push_back(Pair("amount in question", ValueFromAmount(nBalanceInQuestion)));
2646 // ppcoin: repair wallet
2647 Value repairwallet(const Array& params, bool fHelp)
2649 if (fHelp || params.size() > 0)
2650 throw runtime_error(
2652 "Repair wallet if checkwallet reports any problem.\n");
2655 int64 nBalanceInQuestion;
2656 pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion);
2658 if (nMismatchSpent == 0)
2659 result.push_back(Pair("wallet check passed", true));
2662 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
2663 result.push_back(Pair("amount affected by repair", ValueFromAmount(nBalanceInQuestion)));
2668 // NovaCoin: resend unconfirmed wallet transactions
2669 Value resendtx(const Array& params, bool fHelp)
2671 if (fHelp || params.size() > 1)
2672 throw runtime_error(
2674 "Re-send unconfirmed transactions.\n"
2677 ResendWalletTransactions();
2683 // ppcoin: make a public-private key pair
2684 Value makekeypair(const Array& params, bool fHelp)
2686 if (fHelp || params.size() > 1)
2687 throw runtime_error(
2688 "makekeypair [prefix]\n"
2689 "Make a public/private key pair.\n"
2690 "[prefix] is optional preferred prefix for the public key.\n");
2692 string strPrefix = "";
2693 if (params.size() > 0)
2694 strPrefix = params[0].get_str();
2700 key.MakeNewKey(false);
2702 } while (nCount < 10000 && strPrefix != HexStr(key.GetPubKey()).substr(0, strPrefix.size()));
2704 if (strPrefix != HexStr(key.GetPubKey()).substr(0, strPrefix.size()))
2707 CPrivKey vchPrivKey = key.GetPrivKey();
2709 result.push_back(Pair("PrivateKey", HexStr<CPrivKey::iterator>(vchPrivKey.begin(), vchPrivKey.end())));
2710 result.push_back(Pair("PublicKey", HexStr(key.GetPubKey())));
2714 extern CCriticalSection cs_mapAlerts;
2715 extern map<uint256, CAlert> mapAlerts;
2717 // ppcoin: send alert.
2718 // There is a known deadlock situation with ThreadMessageHandler
2719 // ThreadMessageHandler: holds cs_vSend and acquiring cs_main in SendMessages()
2720 // ThreadRPCServer: holds cs_main and acquiring cs_vSend in alert.RelayTo()/PushMessage()/BeginMessage()
2721 Value sendalert(const Array& params, bool fHelp)
2723 if (fHelp || params.size() < 6)
2724 throw runtime_error(
2725 "sendalert <message> <privatekey> <minver> <maxver> <priority> <id> [cancelupto]\n"
2726 "<message> is the alert text message\n"
2727 "<privatekey> is hex string of alert master private key\n"
2728 "<minver> is the minimum applicable internal client version\n"
2729 "<maxver> is the maximum applicable internal client version\n"
2730 "<priority> is integer priority number\n"
2731 "<id> is the alert id\n"
2732 "[cancelupto] cancels all alert id's up to this number\n"
2733 "Returns true or false.");
2738 alert.strStatusBar = params[0].get_str();
2739 alert.nMinVer = params[2].get_int();
2740 alert.nMaxVer = params[3].get_int();
2741 alert.nPriority = params[4].get_int();
2742 alert.nID = params[5].get_int();
2743 if (params.size() > 6)
2744 alert.nCancel = params[6].get_int();
2745 alert.nVersion = PROTOCOL_VERSION;
2746 alert.nRelayUntil = GetAdjustedTime() + 365*24*60*60;
2747 alert.nExpiration = GetAdjustedTime() + 365*24*60*60;
2749 CDataStream sMsg(SER_NETWORK, PROTOCOL_VERSION);
2750 sMsg << (CUnsignedAlert)alert;
2751 alert.vchMsg = vector<unsigned char>(sMsg.begin(), sMsg.end());
2753 vector<unsigned char> vchPrivKey = ParseHex(params[1].get_str());
2754 key.SetPrivKey(CPrivKey(vchPrivKey.begin(), vchPrivKey.end())); // if key is not correct openssl may crash
2755 if (!key.Sign(Hash(alert.vchMsg.begin(), alert.vchMsg.end()), alert.vchSig))
2756 throw runtime_error(
2757 "Unable to sign alert, check private key?\n");
2758 if(!alert.ProcessAlert())
2759 throw runtime_error(
2760 "Failed to process alert.\n");
2764 BOOST_FOREACH(CNode* pnode, vNodes)
2765 alert.RelayTo(pnode);
2769 result.push_back(Pair("strStatusBar", alert.strStatusBar));
2770 result.push_back(Pair("nVersion", alert.nVersion));
2771 result.push_back(Pair("nMinVer", alert.nMinVer));
2772 result.push_back(Pair("nMaxVer", alert.nMaxVer));
2773 result.push_back(Pair("nPriority", alert.nPriority));
2774 result.push_back(Pair("nID", alert.nID));
2775 if (alert.nCancel > 0)
2776 result.push_back(Pair("nCancel", alert.nCancel));
2787 static const CRPCCommand vRPCCommands[] =
2788 { // name function safe mode?
2789 // ------------------------ ----------------------- ----------
2790 { "help", &help, true },
2791 { "stop", &stop, true },
2792 { "getblockcount", &getblockcount, true },
2793 { "getblocknumber", &getblocknumber, true },
2794 { "getconnectioncount", &getconnectioncount, true },
2795 { "getdifficulty", &getdifficulty, true },
2796 { "getpowreward", &getpowreward, true },
2797 { "getgenerate", &getgenerate, true },
2798 { "setgenerate", &setgenerate, true },
2799 { "gethashespersec", &gethashespersec, true },
2800 { "getinfo", &getinfo, true },
2801 { "getmininginfo", &getmininginfo, true },
2802 { "getnewaddress", &getnewaddress, true },
2803 { "getnewpubkey", &getnewpubkey, true },
2804 { "getaccountaddress", &getaccountaddress, true },
2805 { "setaccount", &setaccount, true },
2806 { "getaccount", &getaccount, false },
2807 { "getaddressesbyaccount", &getaddressesbyaccount, true },
2808 { "sendtoaddress", &sendtoaddress, false },
2809 { "getreceivedbyaddress", &getreceivedbyaddress, false },
2810 { "getreceivedbyaccount", &getreceivedbyaccount, false },
2811 { "listreceivedbyaddress", &listreceivedbyaddress, false },
2812 { "listreceivedbyaccount", &listreceivedbyaccount, false },
2813 { "backupwallet", &backupwallet, true },
2814 { "keypoolrefill", &keypoolrefill, true },
2815 { "walletpassphrase", &walletpassphrase, true },
2816 { "walletpassphrasechange", &walletpassphrasechange, false },
2817 { "walletlock", &walletlock, true },
2818 { "encryptwallet", &encryptwallet, false },
2819 { "validateaddress", &validateaddress, true },
2820 { "validatepubkey", &validatepubkey, true },
2821 { "getbalance", &getbalance, false },
2822 { "move", &movecmd, false },
2823 { "sendfrom", &sendfrom, false },
2824 { "sendmany", &sendmany, false },
2825 { "addmultisigaddress", &addmultisigaddress, false },
2826 { "getblock", &getblock, false },
2827 { "getblockhash", &getblockhash, false },
2828 { "getblockbynumber", &getblockbynumber, false },
2829 { "gettransaction", &gettransaction, false },
2830 { "listtransactions", &listtransactions, false },
2831 { "signmessage", &signmessage, false },
2832 { "verifymessage", &verifymessage, false },
2833 { "getwork", &getwork, true },
2834 { "getworkex", &getworkex, true },
2835 { "listaccounts", &listaccounts, false },
2836 { "settxfee", &settxfee, false },
2837 { "getmemorypool", &getmemorypool, true },
2838 { "getblocktemplate", &getblocktemplate, true },
2839 { "submitblock", &submitblock, false },
2840 { "listsinceblock", &listsinceblock, false },
2841 { "dumpprivkey", &dumpprivkey, false },
2842 { "importprivkey", &importprivkey, false },
2843 { "getcheckpoint", &getcheckpoint, true },
2844 { "reservebalance", &reservebalance, false},
2845 { "checkwallet", &checkwallet, false},
2846 { "repairwallet", &repairwallet, false},
2847 { "resendtx", &resendtx, false},
2848 { "makekeypair", &makekeypair, false},
2849 { "sendalert", &sendalert, false},
2852 CRPCTable::CRPCTable()
2855 for (vcidx = 0; vcidx < (sizeof(vRPCCommands) / sizeof(vRPCCommands[0])); vcidx++)
2857 const CRPCCommand *pcmd;
2859 pcmd = &vRPCCommands[vcidx];
2860 mapCommands[pcmd->name] = pcmd;
2864 const CRPCCommand *CRPCTable::operator[](string name) const
2866 map<string, const CRPCCommand*>::const_iterator it = mapCommands.find(name);
2867 if (it == mapCommands.end())
2869 return (*it).second;
2875 // This ain't Apache. We're just using HTTP header for the length field
2876 // and to be compatible with other JSON-RPC implementations.
2879 string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
2882 s << "POST / HTTP/1.1\r\n"
2883 << "User-Agent: novacoin-json-rpc/" << FormatFullVersion() << "\r\n"
2884 << "Host: 127.0.0.1\r\n"
2885 << "Content-Type: application/json\r\n"
2886 << "Content-Length: " << strMsg.size() << "\r\n"
2887 << "Connection: close\r\n"
2888 << "Accept: application/json\r\n";
2889 BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
2890 s << item.first << ": " << item.second << "\r\n";
2891 s << "\r\n" << strMsg;
2896 string rfc1123Time()
2901 struct tm* now_gmt = gmtime(&now);
2902 string locale(setlocale(LC_TIME, NULL));
2903 setlocale(LC_TIME, "C"); // we want posix (aka "C") weekday/month strings
2904 strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt);
2905 setlocale(LC_TIME, locale.c_str());
2906 return string(buffer);
2909 static string HTTPReply(int nStatus, const string& strMsg)
2912 return strprintf("HTTP/1.0 401 Authorization Required\r\n"
2914 "Server: novacoin-json-rpc/%s\r\n"
2915 "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
2916 "Content-Type: text/html\r\n"
2917 "Content-Length: 296\r\n"
2919 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
2920 "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
2923 "<TITLE>Error</TITLE>\r\n"
2924 "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
2926 "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
2927 "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
2928 const char *cStatus;
2929 if (nStatus == 200) cStatus = "OK";
2930 else if (nStatus == 400) cStatus = "Bad Request";
2931 else if (nStatus == 403) cStatus = "Forbidden";
2932 else if (nStatus == 404) cStatus = "Not Found";
2933 else if (nStatus == 500) cStatus = "Internal Server Error";
2936 "HTTP/1.1 %d %s\r\n"
2938 "Connection: close\r\n"
2939 "Content-Length: %d\r\n"
2940 "Content-Type: application/json\r\n"
2941 "Server: novacoin-json-rpc/%s\r\n"
2946 rfc1123Time().c_str(),
2948 FormatFullVersion().c_str(),
2952 int ReadHTTPStatus(std::basic_istream<char>& stream)
2955 getline(stream, str);
2956 vector<string> vWords;
2957 boost::split(vWords, str, boost::is_any_of(" "));
2958 if (vWords.size() < 2)
2960 return atoi(vWords[1].c_str());
2963 int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
2969 std::getline(stream, str);
2970 if (str.empty() || str == "\r")
2972 string::size_type nColon = str.find(":");
2973 if (nColon != string::npos)
2975 string strHeader = str.substr(0, nColon);
2976 boost::trim(strHeader);
2977 boost::to_lower(strHeader);
2978 string strValue = str.substr(nColon+1);
2979 boost::trim(strValue);
2980 mapHeadersRet[strHeader] = strValue;
2981 if (strHeader == "content-length")
2982 nLen = atoi(strValue.c_str());
2988 int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
2990 mapHeadersRet.clear();
2994 int nStatus = ReadHTTPStatus(stream);
2997 int nLen = ReadHTTPHeader(stream, mapHeadersRet);
2998 if (nLen < 0 || nLen > (int)MAX_SIZE)
3004 vector<char> vch(nLen);
3005 stream.read(&vch[0], nLen);
3006 strMessageRet = string(vch.begin(), vch.end());
3012 bool HTTPAuthorized(map<string, string>& mapHeaders)
3014 string strAuth = mapHeaders["authorization"];
3015 if (strAuth.substr(0,6) != "Basic ")
3017 string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
3018 string strUserPass = DecodeBase64(strUserPass64);
3019 return strUserPass == strRPCUserColonPass;
3023 // JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
3024 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
3025 // unspecified (HTTP errors and contents of 'error').
3027 // 1.0 spec: http://json-rpc.org/wiki/specification
3028 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
3029 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
3032 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
3035 request.push_back(Pair("method", strMethod));
3036 request.push_back(Pair("params", params));
3037 request.push_back(Pair("id", id));
3038 return write_string(Value(request), false) + "\n";
3041 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
3044 if (error.type() != null_type)
3045 reply.push_back(Pair("result", Value::null));
3047 reply.push_back(Pair("result", result));
3048 reply.push_back(Pair("error", error));
3049 reply.push_back(Pair("id", id));
3050 return write_string(Value(reply), false) + "\n";
3053 void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
3055 // Send error reply from json-rpc error object
3057 int code = find_value(objError, "code").get_int();
3058 if (code == -32600) nStatus = 400;
3059 else if (code == -32601) nStatus = 404;
3060 string strReply = JSONRPCReply(Value::null, objError, id);
3061 stream << HTTPReply(nStatus, strReply) << std::flush;
3064 bool ClientAllowed(const string& strAddress)
3066 if (strAddress == asio::ip::address_v4::loopback().to_string())
3068 const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
3069 BOOST_FOREACH(string strAllow, vAllow)
3070 if (WildcardMatch(strAddress, strAllow))
3076 // IOStream device that speaks SSL but can also speak non-SSL
3078 class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
3080 SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
3082 fUseSSL = fUseSSLIn;
3083 fNeedHandshake = fUseSSLIn;
3086 void handshake(ssl::stream_base::handshake_type role)
3088 if (!fNeedHandshake) return;
3089 fNeedHandshake = false;
3090 stream.handshake(role);
3092 std::streamsize read(char* s, std::streamsize n)
3094 handshake(ssl::stream_base::server); // HTTPS servers read first
3095 if (fUseSSL) return stream.read_some(asio::buffer(s, n));
3096 return stream.next_layer().read_some(asio::buffer(s, n));
3098 std::streamsize write(const char* s, std::streamsize n)
3100 handshake(ssl::stream_base::client); // HTTPS clients write first
3101 if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
3102 return asio::write(stream.next_layer(), asio::buffer(s, n));
3104 bool connect(const std::string& server, const std::string& port)
3106 ip::tcp::resolver resolver(stream.get_io_service());
3107 ip::tcp::resolver::query query(server.c_str(), port.c_str());
3108 ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
3109 ip::tcp::resolver::iterator end;
3110 boost::system::error_code error = asio::error::host_not_found;
3111 while (error && endpoint_iterator != end)
3113 stream.lowest_layer().close();
3114 stream.lowest_layer().connect(*endpoint_iterator++, error);
3122 bool fNeedHandshake;
3127 void ThreadRPCServer(void* parg)
3129 IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
3132 vnThreadsRunning[THREAD_RPCSERVER]++;
3133 ThreadRPCServer2(parg);
3134 vnThreadsRunning[THREAD_RPCSERVER]--;
3136 catch (std::exception& e) {
3137 vnThreadsRunning[THREAD_RPCSERVER]--;
3138 PrintException(&e, "ThreadRPCServer()");
3140 vnThreadsRunning[THREAD_RPCSERVER]--;
3141 PrintException(NULL, "ThreadRPCServer()");
3143 printf("ThreadRPCServer exiting\n");
3146 void ThreadRPCServer2(void* parg)
3148 printf("ThreadRPCServer started\n");
3150 strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
3151 if (mapArgs["-rpcpassword"] == "")
3153 unsigned char rand_pwd[32];
3154 RAND_bytes(rand_pwd, 32);
3155 string strWhatAmI = "To use novacoind";
3156 if (mapArgs.count("-server"))
3157 strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
3158 else if (mapArgs.count("-daemon"))
3159 strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
3160 ThreadSafeMessageBox(strprintf(
3161 _("%s, you must set a rpcpassword in the configuration file:\n %s\n"
3162 "It is recommended you use the following random password:\n"
3165 "(you do not need to remember this password)\n"
3166 "If the file does not exist, create it with owner-readable-only file permissions.\n"),
3168 GetConfigFile().string().c_str(),
3169 EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str()),
3170 _("Error"), wxOK | wxMODAL);
3175 bool fUseSSL = GetBoolArg("-rpcssl");
3176 asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
3178 asio::io_service io_service;
3179 ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", RPC_PORT));
3180 ip::tcp::acceptor acceptor(io_service);
3183 acceptor.open(endpoint.protocol());
3184 acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
3185 acceptor.bind(endpoint);
3186 acceptor.listen(socket_base::max_connections);
3188 catch(boost::system::system_error &e)
3190 ThreadSafeMessageBox(strprintf(_("An error occured while setting up the RPC port %i for listening: %s"), endpoint.port(), e.what()),
3191 _("Error"), wxOK | wxMODAL);
3196 ssl::context context(io_service, ssl::context::sslv23);
3199 context.set_options(ssl::context::no_sslv2);
3201 filesystem::path pathCertFile(GetArg("-rpcsslcertificatechainfile", "server.cert"));
3202 if (!pathCertFile.is_complete()) pathCertFile = filesystem::path(GetDataDir()) / pathCertFile;
3203 if (filesystem::exists(pathCertFile)) context.use_certificate_chain_file(pathCertFile.string());
3204 else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", pathCertFile.string().c_str());
3206 filesystem::path pathPKFile(GetArg("-rpcsslprivatekeyfile", "server.pem"));
3207 if (!pathPKFile.is_complete()) pathPKFile = filesystem::path(GetDataDir()) / pathPKFile;
3208 if (filesystem::exists(pathPKFile)) context.use_private_key_file(pathPKFile.string(), ssl::context::pem);
3209 else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pathPKFile.string().c_str());
3211 string strCiphers = GetArg("-rpcsslciphers", "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
3212 SSL_CTX_set_cipher_list(context.impl(), strCiphers.c_str());
3217 // Accept connection
3218 SSLStream sslStream(io_service, context);
3219 SSLIOStreamDevice d(sslStream, fUseSSL);
3220 iostreams::stream<SSLIOStreamDevice> stream(d);
3222 ip::tcp::endpoint peer;
3223 vnThreadsRunning[THREAD_RPCSERVER]--;
3224 acceptor.accept(sslStream.lowest_layer(), peer);
3225 vnThreadsRunning[4]++;
3229 // Restrict callers by IP
3230 if (!ClientAllowed(peer.address().to_string()))
3232 // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
3234 stream << HTTPReply(403, "") << std::flush;
3238 map<string, string> mapHeaders;
3241 boost::thread api_caller(ReadHTTP, boost::ref(stream), boost::ref(mapHeaders), boost::ref(strRequest));
3242 if (!api_caller.timed_join(boost::posix_time::seconds(GetArg("-rpctimeout", 30))))
3245 printf("ThreadRPCServer ReadHTTP timeout\n");
3249 // Check authorization
3250 if (mapHeaders.count("authorization") == 0)
3252 stream << HTTPReply(401, "") << std::flush;
3255 if (!HTTPAuthorized(mapHeaders))
3257 printf("ThreadRPCServer incorrect password attempt from %s\n",peer.address().to_string().c_str());
3258 /* Deter brute-forcing short passwords.
3259 If this results in a DOS the user really
3260 shouldn't have their RPC port exposed.*/
3261 if (mapArgs["-rpcpassword"].size() < 20)
3264 stream << HTTPReply(401, "") << std::flush;
3268 Value id = Value::null;
3273 if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
3274 throw JSONRPCError(-32700, "Parse error");
3275 const Object& request = valRequest.get_obj();
3277 // Parse id now so errors from here on will have the id
3278 id = find_value(request, "id");
3281 Value valMethod = find_value(request, "method");
3282 if (valMethod.type() == null_type)
3283 throw JSONRPCError(-32600, "Missing method");
3284 if (valMethod.type() != str_type)
3285 throw JSONRPCError(-32600, "Method must be a string");
3286 string strMethod = valMethod.get_str();
3287 if (strMethod != "getwork" && strMethod != "getmemorypool")
3288 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
3291 Value valParams = find_value(request, "params");
3293 if (valParams.type() == array_type)
3294 params = valParams.get_array();
3295 else if (valParams.type() == null_type)
3298 throw JSONRPCError(-32600, "Params must be an array");
3301 const CRPCCommand *pcmd = tableRPC[strMethod];
3303 throw JSONRPCError(-32601, "Method not found");
3305 // Observe safe mode
3306 string strWarning = GetWarnings("rpc");
3307 if (strWarning != "" && !GetBoolArg("-disablesafemode") &&
3309 throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
3316 LOCK2(cs_main, pwalletMain->cs_wallet);
3317 result = pcmd->actor(params, false);
3321 string strReply = JSONRPCReply(result, Value::null, id);
3322 stream << HTTPReply(200, strReply) << std::flush;
3324 catch (std::exception& e)
3326 ErrorReply(stream, JSONRPCError(-1, e.what()), id);
3329 catch (Object& objError)
3331 ErrorReply(stream, objError, id);
3333 catch (std::exception& e)
3335 ErrorReply(stream, JSONRPCError(-32700, e.what()), id);
3343 Object CallRPC(const string& strMethod, const Array& params)
3345 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
3346 throw runtime_error(strprintf(
3347 _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
3348 "If the file does not exist, create it with owner-readable-only file permissions."),
3349 GetConfigFile().string().c_str()));
3351 // Connect to localhost
3352 bool fUseSSL = GetBoolArg("-rpcssl");
3353 asio::io_service io_service;
3354 ssl::context context(io_service, ssl::context::sslv23);
3355 context.set_options(ssl::context::no_sslv2);
3356 SSLStream sslStream(io_service, context);
3357 SSLIOStreamDevice d(sslStream, fUseSSL);
3358 iostreams::stream<SSLIOStreamDevice> stream(d);
3359 if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", CBigNum(RPC_PORT).ToString().c_str())))
3360 throw runtime_error("couldn't connect to server");
3362 // HTTP basic authentication
3363 string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
3364 map<string, string> mapRequestHeaders;
3365 mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
3368 string strRequest = JSONRPCRequest(strMethod, params, 1);
3369 string strPost = HTTPPost(strRequest, mapRequestHeaders);
3370 stream << strPost << std::flush;
3373 map<string, string> mapHeaders;
3375 int nStatus = ReadHTTP(stream, mapHeaders, strReply);
3377 throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
3378 else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
3379 throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
3380 else if (strReply.empty())
3381 throw runtime_error("no response from server");
3385 if (!read_string(strReply, valReply))
3386 throw runtime_error("couldn't parse reply from server");
3387 const Object& reply = valReply.get_obj();
3389 throw runtime_error("expected reply to have result, error and id properties");
3397 template<typename T>
3398 void ConvertTo(Value& value)
3400 if (value.type() == str_type)
3402 // reinterpret string as unquoted json value
3404 if (!read_string(value.get_str(), value2))
3405 throw runtime_error("type mismatch");
3406 value = value2.get_value<T>();
3410 value = value.get_value<T>();
3414 int CommandLineRPC(int argc, char *argv[])
3421 while (argc > 1 && IsSwitchChar(argv[1][0]))
3429 throw runtime_error("too few parameters");
3430 string strMethod = argv[1];
3432 // Parameters default to strings
3434 for (int i = 2; i < argc; i++)
3435 params.push_back(argv[i]);
3436 int n = params.size();
3439 // Special case non-string parameter types
3441 if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
3442 if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
3443 if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
3444 if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]);
3445 if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
3446 if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]);
3447 if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
3448 if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
3449 if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]);
3450 if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
3451 if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]);
3452 if (strMethod == "getblockhash" && n > 0) ConvertTo<boost::int64_t>(params[0]);
3453 if (strMethod == "getblockbynumber" && n > 0) ConvertTo<boost::int64_t>(params[0]);
3454 if (strMethod == "getblockbynumber" && n > 1) ConvertTo<bool>(params[1]);
3455 if (strMethod == "getblock" && n > 1) ConvertTo<bool>(params[1]);
3456 if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]);
3457 if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]);
3458 if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]);
3459 if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]);
3460 if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
3461 if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]);
3462 if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]);
3463 if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]);
3464 if (strMethod == "walletpassphrase" && n > 2) ConvertTo<bool>(params[2]);
3465 if (strMethod == "listsinceblock" && n > 1) ConvertTo<boost::int64_t>(params[1]);
3466 if (strMethod == "sendalert" && n > 2) ConvertTo<boost::int64_t>(params[2]);
3467 if (strMethod == "sendalert" && n > 3) ConvertTo<boost::int64_t>(params[3]);
3468 if (strMethod == "sendalert" && n > 4) ConvertTo<boost::int64_t>(params[4]);
3469 if (strMethod == "sendalert" && n > 5) ConvertTo<boost::int64_t>(params[5]);
3470 if (strMethod == "sendalert" && n > 6) ConvertTo<boost::int64_t>(params[6]);
3471 if (strMethod == "sendmany" && n > 1)
3473 string s = params[1].get_str();
3475 if (!read_string(s, v) || v.type() != obj_type)
3476 throw runtime_error("type mismatch");
3477 params[1] = v.get_obj();
3479 if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]);
3480 if (strMethod == "reservebalance" && n > 0) ConvertTo<bool>(params[0]);
3481 if (strMethod == "reservebalance" && n > 1) ConvertTo<double>(params[1]);
3482 if (strMethod == "addmultisigaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
3483 if (strMethod == "addmultisigaddress" && n > 1)
3485 string s = params[1].get_str();
3487 if (!read_string(s, v) || v.type() != array_type)
3488 throw runtime_error("type mismatch "+s);
3489 params[1] = v.get_array();
3493 Object reply = CallRPC(strMethod, params);
3496 const Value& result = find_value(reply, "result");
3497 const Value& error = find_value(reply, "error");
3499 if (error.type() != null_type)
3502 strPrint = "error: " + write_string(error, false);
3503 int code = find_value(error.get_obj(), "code").get_int();
3509 if (result.type() == null_type)
3511 else if (result.type() == str_type)
3512 strPrint = result.get_str();
3514 strPrint = write_string(result, true);
3517 catch (std::exception& e)
3519 strPrint = string("error: ") + e.what();
3524 PrintException(NULL, "CommandLineRPC()");
3529 fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
3538 int main(int argc, char *argv[])
3541 // Turn off microsoft heap dump noise
3542 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
3543 _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
3545 setbuf(stdin, NULL);
3546 setbuf(stdout, NULL);
3547 setbuf(stderr, NULL);
3551 if (argc >= 2 && string(argv[1]) == "-server")
3553 printf("server ready\n");
3554 ThreadRPCServer(NULL);
3558 return CommandLineRPC(argc, argv);
3561 catch (std::exception& e) {
3562 PrintException(&e, "main()");
3564 PrintException(NULL, "main()");
3570 const CRPCTable tableRPC;