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)
216 entry.push_back(Pair("txid", tx.GetHash().GetHex()));
218 entry.push_back(Pair("time", DateTimeStrFormat(tx.nTime)));
220 txinfo.push_back(entry);
223 txinfo.push_back(tx.GetHash().GetHex());
225 result.push_back(Pair("tx", txinfo));
233 /// Note: This interface may still be subject to change.
236 string CRPCTable::help(string strCommand) const
239 set<rpcfn_type> setDone;
240 for (map<string, const CRPCCommand*>::const_iterator mi = mapCommands.begin(); mi != mapCommands.end(); ++mi)
242 const CRPCCommand *pcmd = mi->second;
243 string strMethod = mi->first;
244 // We already filter duplicates, but these deprecated screw up the sort order
245 if (strMethod == "getamountreceived" ||
246 strMethod == "getallreceived" ||
247 strMethod == "getblocknumber" || // deprecated
248 (strMethod.find("label") != string::npos))
250 if (strCommand != "" && strMethod != strCommand)
255 rpcfn_type pfn = pcmd->actor;
256 if (setDone.insert(pfn).second)
257 (*pfn)(params, true);
259 catch (std::exception& e)
261 // Help text is returned in an exception
262 string strHelp = string(e.what());
263 if (strCommand == "")
264 if (strHelp.find('\n') != string::npos)
265 strHelp = strHelp.substr(0, strHelp.find('\n'));
266 strRet += strHelp + "\n";
270 strRet = strprintf("help: unknown command: %s\n", strCommand.c_str());
271 strRet = strRet.substr(0,strRet.size()-1);
275 Value help(const Array& params, bool fHelp)
277 if (fHelp || params.size() > 1)
280 "List commands, or get help for a command.");
283 if (params.size() > 0)
284 strCommand = params[0].get_str();
286 return tableRPC.help(strCommand);
290 Value stop(const Array& params, bool fHelp)
292 if (fHelp || params.size() != 0)
295 "Stop novacoin server.");
296 // Shutdown will take long enough that the response should get back
298 return "novacoin server stopping";
302 Value getblockcount(const Array& params, bool fHelp)
304 if (fHelp || params.size() != 0)
307 "Returns the number of blocks in the longest block chain.");
314 Value getblocknumber(const Array& params, bool fHelp)
316 if (fHelp || params.size() != 0)
319 "Deprecated. Use getblockcount.");
325 Value getconnectioncount(const Array& params, bool fHelp)
327 if (fHelp || params.size() != 0)
329 "getconnectioncount\n"
330 "Returns the number of connections to other nodes.");
332 return (int)vNodes.size();
336 Value getdifficulty(const Array& params, bool fHelp)
338 if (fHelp || params.size() != 0)
341 "Returns difficulty as a multiple of the minimum difficulty.");
344 obj.push_back(Pair("proof-of-work", GetDifficulty()));
345 obj.push_back(Pair("proof-of-stake", GetDifficulty(GetLastBlockIndex(pindexBest, true))));
346 obj.push_back(Pair("search-interval", (int)nLastCoinStakeSearchInterval));
351 Value getgenerate(const Array& params, bool fHelp)
353 if (fHelp || params.size() != 0)
356 "Returns true or false.");
358 return GetBoolArg("-gen");
362 Value setgenerate(const Array& params, bool fHelp)
364 if (fHelp || params.size() < 1 || params.size() > 2)
366 "setgenerate <generate> [genproclimit]\n"
367 "<generate> is true or false to turn generation on or off.\n"
368 "Generation is limited to [genproclimit] processors, -1 is unlimited.");
370 bool fGenerate = true;
371 if (params.size() > 0)
372 fGenerate = params[0].get_bool();
374 if (params.size() > 1)
376 int nGenProcLimit = params[1].get_int();
377 mapArgs["-genproclimit"] = itostr(nGenProcLimit);
378 if (nGenProcLimit == 0)
381 mapArgs["-gen"] = (fGenerate ? "1" : "0");
383 GenerateBitcoins(fGenerate, pwalletMain);
388 Value gethashespersec(const Array& params, bool fHelp)
390 if (fHelp || params.size() != 0)
393 "Returns a recent hashes per second performance measurement while generating.");
395 if (GetTimeMillis() - nHPSTimerStart > 8000)
396 return (boost::int64_t)0;
397 return (boost::int64_t)dHashesPerSec;
401 Value getinfo(const Array& params, bool fHelp)
403 if (fHelp || params.size() != 0)
406 "Returns an object containing various state info.");
409 obj.push_back(Pair("version", FormatFullVersion()));
410 obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION));
411 obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
412 obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
413 obj.push_back(Pair("newmint", ValueFromAmount(pwalletMain->GetNewMint())));
414 obj.push_back(Pair("stake", ValueFromAmount(pwalletMain->GetStake())));
415 obj.push_back(Pair("blocks", (int)nBestHeight));
416 obj.push_back(Pair("moneysupply", ValueFromAmount(pindexBest->nMoneySupply)));
417 obj.push_back(Pair("connections", (int)vNodes.size()));
418 obj.push_back(Pair("proxy", (fUseProxy ? addrProxy.ToStringIPPort() : string())));
419 obj.push_back(Pair("ip", addrSeenByPeer.ToStringIP()));
420 obj.push_back(Pair("difficulty", (double)GetDifficulty()));
421 obj.push_back(Pair("testnet", fTestNet));
422 obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));
423 obj.push_back(Pair("keypoolsize", pwalletMain->GetKeyPoolSize()));
424 obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee)));
425 if (pwalletMain->IsCrypted())
426 obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime / 1000));
427 obj.push_back(Pair("errors", GetWarnings("statusbar")));
432 Value getmininginfo(const Array& params, bool fHelp)
434 if (fHelp || params.size() != 0)
437 "Returns an object containing mining-related information.");
440 obj.push_back(Pair("blocks", (int)nBestHeight));
441 obj.push_back(Pair("currentblocksize",(uint64_t)nLastBlockSize));
442 obj.push_back(Pair("currentblocktx",(uint64_t)nLastBlockTx));
443 obj.push_back(Pair("difficulty", (double)GetDifficulty()));
444 obj.push_back(Pair("errors", GetWarnings("statusbar")));
445 obj.push_back(Pair("generate", GetBoolArg("-gen")));
446 obj.push_back(Pair("genproclimit", (int)GetArg("-genproclimit", -1)));
447 obj.push_back(Pair("hashespersec", gethashespersec(params, false)));
448 obj.push_back(Pair("pooledtx", (uint64_t)mempool.size()));
449 obj.push_back(Pair("testnet", fTestNet));
454 Value getnewaddress(const Array& params, bool fHelp)
456 if (fHelp || params.size() > 1)
458 "getnewaddress [account]\n"
459 "Returns a new novacoin address for receiving payments. "
460 "If [account] is specified (recommended), it is added to the address book "
461 "so payments received with the address will be credited to [account].");
463 // Parse the account first so we don't generate a key if there's an error
465 if (params.size() > 0)
466 strAccount = AccountFromValue(params[0]);
468 if (!pwalletMain->IsLocked())
469 pwalletMain->TopUpKeyPool();
471 // Generate a new key that is added to wallet
472 std::vector<unsigned char> newKey;
473 if (!pwalletMain->GetKeyFromPool(newKey, false))
474 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
475 CBitcoinAddress address(newKey);
477 pwalletMain->SetAddressBookName(address, strAccount);
479 return address.ToString();
483 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
485 CWalletDB walletdb(pwalletMain->strWalletFile);
488 walletdb.ReadAccount(strAccount, account);
490 bool bKeyUsed = false;
492 // Check if the current key has been used
493 if (!account.vchPubKey.empty())
495 CScript scriptPubKey;
496 scriptPubKey.SetBitcoinAddress(account.vchPubKey);
497 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
498 it != pwalletMain->mapWallet.end() && !account.vchPubKey.empty();
501 const CWalletTx& wtx = (*it).second;
502 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
503 if (txout.scriptPubKey == scriptPubKey)
508 // Generate a new key
509 if (account.vchPubKey.empty() || bForceNew || bKeyUsed)
511 if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false))
512 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
514 pwalletMain->SetAddressBookName(CBitcoinAddress(account.vchPubKey), strAccount);
515 walletdb.WriteAccount(strAccount, account);
518 return CBitcoinAddress(account.vchPubKey);
521 Value getaccountaddress(const Array& params, bool fHelp)
523 if (fHelp || params.size() != 1)
525 "getaccountaddress <account>\n"
526 "Returns the current novacoin address for receiving payments to this account.");
528 // Parse the account first so we don't generate a key if there's an error
529 string strAccount = AccountFromValue(params[0]);
533 ret = GetAccountAddress(strAccount).ToString();
540 Value setaccount(const Array& params, bool fHelp)
542 if (fHelp || params.size() < 1 || params.size() > 2)
544 "setaccount <novacoinaddress> <account>\n"
545 "Sets the account associated with the given address.");
547 CBitcoinAddress address(params[0].get_str());
548 if (!address.IsValid())
549 throw JSONRPCError(-5, "Invalid novacoin address");
553 if (params.size() > 1)
554 strAccount = AccountFromValue(params[1]);
556 // Detect when changing the account of an address that is the 'unused current key' of another account:
557 if (pwalletMain->mapAddressBook.count(address))
559 string strOldAccount = pwalletMain->mapAddressBook[address];
560 if (address == GetAccountAddress(strOldAccount))
561 GetAccountAddress(strOldAccount, true);
564 pwalletMain->SetAddressBookName(address, strAccount);
570 Value getaccount(const Array& params, bool fHelp)
572 if (fHelp || params.size() != 1)
574 "getaccount <novacoinaddress>\n"
575 "Returns the account associated with the given address.");
577 CBitcoinAddress address(params[0].get_str());
578 if (!address.IsValid())
579 throw JSONRPCError(-5, "Invalid novacoin address");
582 map<CBitcoinAddress, string>::iterator mi = pwalletMain->mapAddressBook.find(address);
583 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
584 strAccount = (*mi).second;
589 Value getaddressesbyaccount(const Array& params, bool fHelp)
591 if (fHelp || params.size() != 1)
593 "getaddressesbyaccount <account>\n"
594 "Returns the list of addresses for the given account.");
596 string strAccount = AccountFromValue(params[0]);
598 // Find all addresses that have the given account
600 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
602 const CBitcoinAddress& address = item.first;
603 const string& strName = item.second;
604 if (strName == strAccount)
605 ret.push_back(address.ToString());
610 Value settxfee(const Array& params, bool fHelp)
612 if (fHelp || params.size() < 1 || params.size() > 1 || AmountFromValue(params[0]) < MIN_TX_FEE)
614 "settxfee <amount>\n"
615 "<amount> is a real and is rounded to 0.01 (cent)\n"
616 "Minimum and default transaction fee per KB is 1 cent");
618 nTransactionFee = AmountFromValue(params[0]);
619 nTransactionFee = (nTransactionFee / CENT) * CENT; // round to cent
623 Value sendtoaddress(const Array& params, bool fHelp)
625 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
627 "sendtoaddress <novacoinaddress> <amount> [comment] [comment-to]\n"
628 "<amount> is a real and is rounded to the nearest 0.000001\n"
629 "requires wallet passphrase to be set with walletpassphrase first");
630 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
632 "sendtoaddress <novacoinaddress> <amount> [comment] [comment-to]\n"
633 "<amount> is a real and is rounded to the nearest 0.000001");
635 CBitcoinAddress address(params[0].get_str());
636 if (!address.IsValid())
637 throw JSONRPCError(-5, "Invalid novacoin address");
640 int64 nAmount = AmountFromValue(params[1]);
641 if (nAmount < MIN_TXOUT_AMOUNT)
642 throw JSONRPCError(-101, "Send amount too small");
646 if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
647 wtx.mapValue["comment"] = params[2].get_str();
648 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
649 wtx.mapValue["to"] = params[3].get_str();
651 if (pwalletMain->IsLocked())
652 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
654 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
656 throw JSONRPCError(-4, strError);
658 return wtx.GetHash().GetHex();
661 Value signmessage(const Array& params, bool fHelp)
663 if (fHelp || params.size() != 2)
665 "signmessage <novacoinaddress> <message>\n"
666 "Sign a message with the private key of an address");
668 if (pwalletMain->IsLocked())
669 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
671 string strAddress = params[0].get_str();
672 string strMessage = params[1].get_str();
674 CBitcoinAddress addr(strAddress);
676 throw JSONRPCError(-3, "Invalid address");
679 if (!pwalletMain->GetKey(addr, key))
680 throw JSONRPCError(-4, "Private key not available");
682 CDataStream ss(SER_GETHASH, 0);
683 ss << strMessageMagic;
686 vector<unsigned char> vchSig;
687 if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig))
688 throw JSONRPCError(-5, "Sign failed");
690 return EncodeBase64(&vchSig[0], vchSig.size());
693 Value verifymessage(const Array& params, bool fHelp)
695 if (fHelp || params.size() != 3)
697 "verifymessage <novacoinaddress> <signature> <message>\n"
698 "Verify a signed message");
700 string strAddress = params[0].get_str();
701 string strSign = params[1].get_str();
702 string strMessage = params[2].get_str();
704 CBitcoinAddress addr(strAddress);
706 throw JSONRPCError(-3, "Invalid address");
708 bool fInvalid = false;
709 vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
712 throw JSONRPCError(-5, "Malformed base64 encoding");
714 CDataStream ss(SER_GETHASH, 0);
715 ss << strMessageMagic;
719 if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
722 return (CBitcoinAddress(key.GetPubKey()) == addr);
726 Value getreceivedbyaddress(const Array& params, bool fHelp)
728 if (fHelp || params.size() < 1 || params.size() > 2)
730 "getreceivedbyaddress <novacoinaddress> [minconf=1]\n"
731 "Returns the total amount received by <novacoinaddress> in transactions with at least [minconf] confirmations.");
734 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
735 CScript scriptPubKey;
736 if (!address.IsValid())
737 throw JSONRPCError(-5, "Invalid novacoin address");
738 scriptPubKey.SetBitcoinAddress(address);
739 if (!IsMine(*pwalletMain,scriptPubKey))
742 // Minimum confirmations
744 if (params.size() > 1)
745 nMinDepth = params[1].get_int();
749 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
751 const CWalletTx& wtx = (*it).second;
752 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
755 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
756 if (txout.scriptPubKey == scriptPubKey)
757 if (wtx.GetDepthInMainChain() >= nMinDepth)
758 nAmount += txout.nValue;
761 return ValueFromAmount(nAmount);
765 void GetAccountAddresses(string strAccount, set<CBitcoinAddress>& setAddress)
767 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
769 const CBitcoinAddress& address = item.first;
770 const string& strName = item.second;
771 if (strName == strAccount)
772 setAddress.insert(address);
777 Value getreceivedbyaccount(const Array& params, bool fHelp)
779 if (fHelp || params.size() < 1 || params.size() > 2)
781 "getreceivedbyaccount <account> [minconf=1]\n"
782 "Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.");
784 // Minimum confirmations
786 if (params.size() > 1)
787 nMinDepth = params[1].get_int();
789 // Get the set of pub keys assigned to account
790 string strAccount = AccountFromValue(params[0]);
791 set<CBitcoinAddress> setAddress;
792 GetAccountAddresses(strAccount, setAddress);
796 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
798 const CWalletTx& wtx = (*it).second;
799 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
802 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
804 CBitcoinAddress address;
805 if (ExtractAddress(txout.scriptPubKey, address) && pwalletMain->HaveKey(address) && setAddress.count(address))
806 if (wtx.GetDepthInMainChain() >= nMinDepth)
807 nAmount += txout.nValue;
811 return (double)nAmount / (double)COIN;
815 int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth)
819 // Tally wallet transactions
820 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
822 const CWalletTx& wtx = (*it).second;
826 int64 nGenerated, nReceived, nSent, nFee;
827 wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee);
829 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
830 nBalance += nReceived;
831 nBalance += nGenerated - nSent - nFee;
834 // Tally internal accounting entries
835 nBalance += walletdb.GetAccountCreditDebit(strAccount);
840 int64 GetAccountBalance(const string& strAccount, int nMinDepth)
842 CWalletDB walletdb(pwalletMain->strWalletFile);
843 return GetAccountBalance(walletdb, strAccount, nMinDepth);
847 Value getbalance(const Array& params, bool fHelp)
849 if (fHelp || params.size() > 2)
851 "getbalance [account] [minconf=1]\n"
852 "If [account] is not specified, returns the server's total available balance.\n"
853 "If [account] is specified, returns the balance in the account.");
855 if (params.size() == 0)
856 return ValueFromAmount(pwalletMain->GetBalance());
859 if (params.size() > 1)
860 nMinDepth = params[1].get_int();
862 if (params[0].get_str() == "*") {
863 // Calculate total balance a different way from GetBalance()
864 // (GetBalance() sums up all unspent TxOuts)
865 // getbalance and getbalance '*' should always return the same number.
867 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
869 const CWalletTx& wtx = (*it).second;
873 int64 allGeneratedImmature, allGeneratedMature, allFee;
874 allGeneratedImmature = allGeneratedMature = allFee = 0;
875 string strSentAccount;
876 list<pair<CBitcoinAddress, int64> > listReceived;
877 list<pair<CBitcoinAddress, int64> > listSent;
878 wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
879 if (wtx.GetDepthInMainChain() >= nMinDepth)
881 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listReceived)
882 nBalance += r.second;
884 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listSent)
885 nBalance -= r.second;
887 nBalance += allGeneratedMature;
889 return ValueFromAmount(nBalance);
892 string strAccount = AccountFromValue(params[0]);
894 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
896 return ValueFromAmount(nBalance);
900 Value getpowreward(const Array& params, bool fHelp)
902 if (fHelp || params.size() > 1)
904 "getpowreward [nBits]\n"
905 "Returns PoW reward for block with provided difficulty.");
907 if (params.size() == 0)
908 throw JSONRPCError(-200, "no bits provided");
910 std::string sBits = params[0].get_str();
912 if (sBits.length() != 8)
913 throw JSONRPCError(-201, "incorrect bits provided");
915 unsigned int nBits = BitsHex(sBits);
917 return (int)GetProofOfWorkReward(nBits);
922 Value movecmd(const Array& params, bool fHelp)
924 if (fHelp || params.size() < 3 || params.size() > 5)
926 "move <fromaccount> <toaccount> <amount> [minconf=1] [comment]\n"
927 "Move from one account in your wallet to another.");
929 string strFrom = AccountFromValue(params[0]);
930 string strTo = AccountFromValue(params[1]);
931 int64 nAmount = AmountFromValue(params[2]);
932 if (params.size() > 3)
933 // unused parameter, used to be nMinDepth, keep type-checking it though
934 (void)params[3].get_int();
936 if (params.size() > 4)
937 strComment = params[4].get_str();
939 CWalletDB walletdb(pwalletMain->strWalletFile);
940 if (!walletdb.TxnBegin())
941 throw JSONRPCError(-20, "database error");
943 int64 nNow = GetAdjustedTime();
946 CAccountingEntry debit;
947 debit.strAccount = strFrom;
948 debit.nCreditDebit = -nAmount;
950 debit.strOtherAccount = strTo;
951 debit.strComment = strComment;
952 walletdb.WriteAccountingEntry(debit);
955 CAccountingEntry credit;
956 credit.strAccount = strTo;
957 credit.nCreditDebit = nAmount;
959 credit.strOtherAccount = strFrom;
960 credit.strComment = strComment;
961 walletdb.WriteAccountingEntry(credit);
963 if (!walletdb.TxnCommit())
964 throw JSONRPCError(-20, "database error");
970 Value sendfrom(const Array& params, bool fHelp)
972 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
974 "sendfrom <fromaccount> <tonovacoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
975 "<amount> is a real and is rounded to the nearest 0.000001\n"
976 "requires wallet passphrase to be set with walletpassphrase first");
977 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
979 "sendfrom <fromaccount> <tonovacoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
980 "<amount> is a real and is rounded to the nearest 0.000001");
982 string strAccount = AccountFromValue(params[0]);
983 CBitcoinAddress address(params[1].get_str());
984 if (!address.IsValid())
985 throw JSONRPCError(-5, "Invalid novacoin address");
986 int64 nAmount = AmountFromValue(params[2]);
987 if (nAmount < MIN_TXOUT_AMOUNT)
988 throw JSONRPCError(-101, "Send amount too small");
990 if (params.size() > 3)
991 nMinDepth = params[3].get_int();
994 wtx.strFromAccount = strAccount;
995 if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
996 wtx.mapValue["comment"] = params[4].get_str();
997 if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
998 wtx.mapValue["to"] = params[5].get_str();
1000 if (pwalletMain->IsLocked())
1001 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
1004 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
1005 if (nAmount > nBalance)
1006 throw JSONRPCError(-6, "Account has insufficient funds");
1009 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
1011 throw JSONRPCError(-4, strError);
1013 return wtx.GetHash().GetHex();
1017 Value sendmany(const Array& params, bool fHelp)
1019 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
1020 throw runtime_error(
1021 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
1022 "amounts are double-precision floating point numbers\n"
1023 "requires wallet passphrase to be set with walletpassphrase first");
1024 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
1025 throw runtime_error(
1026 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
1027 "amounts are double-precision floating point numbers");
1029 string strAccount = AccountFromValue(params[0]);
1030 Object sendTo = params[1].get_obj();
1032 if (params.size() > 2)
1033 nMinDepth = params[2].get_int();
1036 wtx.strFromAccount = strAccount;
1037 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
1038 wtx.mapValue["comment"] = params[3].get_str();
1040 set<CBitcoinAddress> setAddress;
1041 vector<pair<CScript, int64> > vecSend;
1043 int64 totalAmount = 0;
1044 BOOST_FOREACH(const Pair& s, sendTo)
1046 CBitcoinAddress address(s.name_);
1047 if (!address.IsValid())
1048 throw JSONRPCError(-5, string("Invalid novacoin address:")+s.name_);
1050 if (setAddress.count(address))
1051 throw JSONRPCError(-8, string("Invalid parameter, duplicated address: ")+s.name_);
1052 setAddress.insert(address);
1054 CScript scriptPubKey;
1055 scriptPubKey.SetBitcoinAddress(address);
1056 int64 nAmount = AmountFromValue(s.value_);
1057 if (nAmount < MIN_TXOUT_AMOUNT)
1058 throw JSONRPCError(-101, "Send amount too small");
1059 totalAmount += nAmount;
1061 vecSend.push_back(make_pair(scriptPubKey, nAmount));
1064 if (pwalletMain->IsLocked())
1065 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
1066 if (fWalletUnlockMintOnly)
1067 throw JSONRPCError(-13, "Error: Wallet unlocked for block minting only.");
1070 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
1071 if (totalAmount > nBalance)
1072 throw JSONRPCError(-6, "Account has insufficient funds");
1075 CReserveKey keyChange(pwalletMain);
1076 int64 nFeeRequired = 0;
1077 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
1080 if (totalAmount + nFeeRequired > pwalletMain->GetBalance())
1081 throw JSONRPCError(-6, "Insufficient funds");
1082 throw JSONRPCError(-4, "Transaction creation failed");
1084 if (!pwalletMain->CommitTransaction(wtx, keyChange))
1085 throw JSONRPCError(-4, "Transaction commit failed");
1087 return wtx.GetHash().GetHex();
1090 Value addmultisigaddress(const Array& params, bool fHelp)
1092 if (fHelp || params.size() < 2 || params.size() > 3)
1094 string msg = "addmultisigaddress <nrequired> <'[\"key\",\"key\"]'> [account]\n"
1095 "Add a nrequired-to-sign multisignature address to the wallet\"\n"
1096 "each key is a bitcoin address or hex-encoded public key\n"
1097 "If [account] is specified, assign address to [account].";
1098 throw runtime_error(msg);
1101 int nRequired = params[0].get_int();
1102 const Array& keys = params[1].get_array();
1104 if (params.size() > 2)
1105 strAccount = AccountFromValue(params[2]);
1107 // Gather public keys
1109 throw runtime_error("a multisignature address must require at least one key to redeem");
1110 if ((int)keys.size() < nRequired)
1111 throw runtime_error(
1112 strprintf("not enough keys supplied "
1113 "(got %d keys, but need at least %d to redeem)", keys.size(), nRequired));
1114 std::vector<CKey> pubkeys;
1115 pubkeys.resize(keys.size());
1116 for (unsigned int i = 0; i < keys.size(); i++)
1118 const std::string& ks = keys[i].get_str();
1120 // Case 1: bitcoin address and we have full public key:
1121 CBitcoinAddress address(ks);
1122 if (address.IsValid())
1124 if (address.IsScript())
1125 throw runtime_error(
1126 strprintf("%s is a pay-to-script address",ks.c_str()));
1127 std::vector<unsigned char> vchPubKey;
1128 if (!pwalletMain->GetPubKey(address, vchPubKey))
1129 throw runtime_error(
1130 strprintf("no full public key for address %s",ks.c_str()));
1131 if (vchPubKey.empty() || !pubkeys[i].SetPubKey(vchPubKey))
1132 throw runtime_error(" Invalid public key: "+ks);
1135 // Case 2: hex public key
1138 vector<unsigned char> vchPubKey = ParseHex(ks);
1139 if (vchPubKey.empty() || !pubkeys[i].SetPubKey(vchPubKey))
1140 throw runtime_error(" Invalid public key: "+ks);
1144 throw runtime_error(" Invalid public key: "+ks);
1148 // Construct using pay-to-script-hash:
1150 inner.SetMultisig(nRequired, pubkeys);
1152 uint160 scriptHash = Hash160(inner);
1153 CScript scriptPubKey;
1154 scriptPubKey.SetPayToScriptHash(inner);
1155 pwalletMain->AddCScript(inner);
1156 CBitcoinAddress address;
1157 address.SetScriptHash160(scriptHash);
1159 pwalletMain->SetAddressBookName(address, strAccount);
1160 return address.ToString();
1171 nConf = std::numeric_limits<int>::max();
1175 Value ListReceived(const Array& params, bool fByAccounts)
1177 // Minimum confirmations
1179 if (params.size() > 0)
1180 nMinDepth = params[0].get_int();
1182 // Whether to include empty accounts
1183 bool fIncludeEmpty = false;
1184 if (params.size() > 1)
1185 fIncludeEmpty = params[1].get_bool();
1188 map<CBitcoinAddress, tallyitem> mapTally;
1189 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1191 const CWalletTx& wtx = (*it).second;
1193 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
1196 int nDepth = wtx.GetDepthInMainChain();
1197 if (nDepth < nMinDepth)
1200 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
1202 CBitcoinAddress address;
1203 if (!ExtractAddress(txout.scriptPubKey, address) || !pwalletMain->HaveKey(address) || !address.IsValid())
1206 tallyitem& item = mapTally[address];
1207 item.nAmount += txout.nValue;
1208 item.nConf = min(item.nConf, nDepth);
1214 map<string, tallyitem> mapAccountTally;
1215 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
1217 const CBitcoinAddress& address = item.first;
1218 const string& strAccount = item.second;
1219 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
1220 if (it == mapTally.end() && !fIncludeEmpty)
1224 int nConf = std::numeric_limits<int>::max();
1225 if (it != mapTally.end())
1227 nAmount = (*it).second.nAmount;
1228 nConf = (*it).second.nConf;
1233 tallyitem& item = mapAccountTally[strAccount];
1234 item.nAmount += nAmount;
1235 item.nConf = min(item.nConf, nConf);
1240 obj.push_back(Pair("address", address.ToString()));
1241 obj.push_back(Pair("account", strAccount));
1242 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1243 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1250 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
1252 int64 nAmount = (*it).second.nAmount;
1253 int nConf = (*it).second.nConf;
1255 obj.push_back(Pair("account", (*it).first));
1256 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1257 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1265 Value listreceivedbyaddress(const Array& params, bool fHelp)
1267 if (fHelp || params.size() > 2)
1268 throw runtime_error(
1269 "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
1270 "[minconf] is the minimum number of confirmations before payments are included.\n"
1271 "[includeempty] whether to include addresses that haven't received any payments.\n"
1272 "Returns an array of objects containing:\n"
1273 " \"address\" : receiving address\n"
1274 " \"account\" : the account of the receiving address\n"
1275 " \"amount\" : total amount received by the address\n"
1276 " \"confirmations\" : number of confirmations of the most recent transaction included");
1278 return ListReceived(params, false);
1281 Value listreceivedbyaccount(const Array& params, bool fHelp)
1283 if (fHelp || params.size() > 2)
1284 throw runtime_error(
1285 "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
1286 "[minconf] is the minimum number of confirmations before payments are included.\n"
1287 "[includeempty] whether to include accounts that haven't received any payments.\n"
1288 "Returns an array of objects containing:\n"
1289 " \"account\" : the account of the receiving addresses\n"
1290 " \"amount\" : total amount received by addresses with this account\n"
1291 " \"confirmations\" : number of confirmations of the most recent transaction included");
1293 return ListReceived(params, true);
1296 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret)
1298 int64 nGeneratedImmature, nGeneratedMature, nFee;
1299 string strSentAccount;
1300 list<pair<CBitcoinAddress, int64> > listReceived;
1301 list<pair<CBitcoinAddress, int64> > listSent;
1303 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1305 bool fAllAccounts = (strAccount == string("*"));
1307 // Generated blocks assigned to account ""
1308 if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == ""))
1311 entry.push_back(Pair("account", string("")));
1312 if (nGeneratedImmature)
1314 entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
1315 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
1319 entry.push_back(Pair("category", "generate"));
1320 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
1323 WalletTxToJSON(wtx, entry);
1324 ret.push_back(entry);
1328 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1330 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1333 entry.push_back(Pair("account", strSentAccount));
1334 entry.push_back(Pair("address", s.first.ToString()));
1335 entry.push_back(Pair("category", "send"));
1336 entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1337 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1339 WalletTxToJSON(wtx, entry);
1340 ret.push_back(entry);
1345 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1347 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1350 if (pwalletMain->mapAddressBook.count(r.first))
1351 account = pwalletMain->mapAddressBook[r.first];
1352 if (fAllAccounts || (account == strAccount))
1355 entry.push_back(Pair("account", account));
1356 entry.push_back(Pair("address", r.first.ToString()));
1357 entry.push_back(Pair("category", "receive"));
1358 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1360 WalletTxToJSON(wtx, entry);
1361 ret.push_back(entry);
1367 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1369 bool fAllAccounts = (strAccount == string("*"));
1371 if (fAllAccounts || acentry.strAccount == strAccount)
1374 entry.push_back(Pair("account", acentry.strAccount));
1375 entry.push_back(Pair("category", "move"));
1376 entry.push_back(Pair("time", (boost::int64_t)acentry.nTime));
1377 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1378 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1379 entry.push_back(Pair("comment", acentry.strComment));
1380 ret.push_back(entry);
1384 Value listtransactions(const Array& params, bool fHelp)
1386 if (fHelp || params.size() > 3)
1387 throw runtime_error(
1388 "listtransactions [account] [count=10] [from=0]\n"
1389 "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1391 string strAccount = "*";
1392 if (params.size() > 0)
1393 strAccount = params[0].get_str();
1395 if (params.size() > 1)
1396 nCount = params[1].get_int();
1398 if (params.size() > 2)
1399 nFrom = params[2].get_int();
1402 throw JSONRPCError(-8, "Negative count");
1404 throw JSONRPCError(-8, "Negative from");
1407 CWalletDB walletdb(pwalletMain->strWalletFile);
1409 // First: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap.
1410 typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
1411 typedef multimap<int64, TxPair > TxItems;
1414 // Note: maintaining indices in the database of (account,time) --> txid and (account, time) --> acentry
1415 // would make this much faster for applications that do this a lot.
1416 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1418 CWalletTx* wtx = &((*it).second);
1419 txByTime.insert(make_pair(wtx->GetTxTime(), TxPair(wtx, (CAccountingEntry*)0)));
1421 list<CAccountingEntry> acentries;
1422 walletdb.ListAccountCreditDebit(strAccount, acentries);
1423 BOOST_FOREACH(CAccountingEntry& entry, acentries)
1425 txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
1428 // iterate backwards until we have nCount items to return:
1429 for (TxItems::reverse_iterator it = txByTime.rbegin(); it != txByTime.rend(); ++it)
1431 CWalletTx *const pwtx = (*it).second.first;
1433 ListTransactions(*pwtx, strAccount, 0, true, ret);
1434 CAccountingEntry *const pacentry = (*it).second.second;
1436 AcentryToJSON(*pacentry, strAccount, ret);
1438 if (ret.size() >= (nCount+nFrom)) break;
1440 // ret is newest to oldest
1442 if (nFrom > (int)ret.size())
1444 if ((nFrom + nCount) > (int)ret.size())
1445 nCount = ret.size() - nFrom;
1446 Array::iterator first = ret.begin();
1447 std::advance(first, nFrom);
1448 Array::iterator last = ret.begin();
1449 std::advance(last, nFrom+nCount);
1451 if (last != ret.end()) ret.erase(last, ret.end());
1452 if (first != ret.begin()) ret.erase(ret.begin(), first);
1454 std::reverse(ret.begin(), ret.end()); // Return oldest to newest
1459 Value listaccounts(const Array& params, bool fHelp)
1461 if (fHelp || params.size() > 1)
1462 throw runtime_error(
1463 "listaccounts [minconf=1]\n"
1464 "Returns Object that has account names as keys, account balances as values.");
1467 if (params.size() > 0)
1468 nMinDepth = params[0].get_int();
1470 map<string, int64> mapAccountBalances;
1471 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& entry, pwalletMain->mapAddressBook) {
1472 if (pwalletMain->HaveKey(entry.first)) // This address belongs to me
1473 mapAccountBalances[entry.second] = 0;
1476 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1478 const CWalletTx& wtx = (*it).second;
1479 int64 nGeneratedImmature, nGeneratedMature, nFee;
1480 string strSentAccount;
1481 list<pair<CBitcoinAddress, int64> > listReceived;
1482 list<pair<CBitcoinAddress, int64> > listSent;
1483 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1484 mapAccountBalances[strSentAccount] -= nFee;
1485 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1486 mapAccountBalances[strSentAccount] -= s.second;
1487 if (wtx.GetDepthInMainChain() >= nMinDepth)
1489 mapAccountBalances[""] += nGeneratedMature;
1490 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1491 if (pwalletMain->mapAddressBook.count(r.first))
1492 mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1494 mapAccountBalances[""] += r.second;
1498 list<CAccountingEntry> acentries;
1499 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1500 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1501 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1504 BOOST_FOREACH(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) {
1505 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1510 Value listsinceblock(const Array& params, bool fHelp)
1513 throw runtime_error(
1514 "listsinceblock [blockhash] [target-confirmations]\n"
1515 "Get all transactions in blocks since block [blockhash], or all transactions if omitted");
1517 CBlockIndex *pindex = NULL;
1518 int target_confirms = 1;
1520 if (params.size() > 0)
1522 uint256 blockId = 0;
1524 blockId.SetHex(params[0].get_str());
1525 pindex = CBlockLocator(blockId).GetBlockIndex();
1528 if (params.size() > 1)
1530 target_confirms = params[1].get_int();
1532 if (target_confirms < 1)
1533 throw JSONRPCError(-8, "Invalid parameter");
1536 int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1;
1540 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1542 CWalletTx tx = (*it).second;
1544 if (depth == -1 || tx.GetDepthInMainChain() < depth)
1545 ListTransactions(tx, "*", 0, true, transactions);
1550 if (target_confirms == 1)
1552 lastblock = hashBestChain;
1556 int target_height = pindexBest->nHeight + 1 - target_confirms;
1559 for (block = pindexBest;
1560 block && block->nHeight > target_height;
1561 block = block->pprev) { }
1563 lastblock = block ? block->GetBlockHash() : 0;
1567 ret.push_back(Pair("transactions", transactions));
1568 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1573 Value gettransaction(const Array& params, bool fHelp)
1575 if (fHelp || params.size() != 1)
1576 throw runtime_error(
1577 "gettransaction <txid>\n"
1578 "Get detailed information about <txid>");
1581 hash.SetHex(params[0].get_str());
1585 if (pwalletMain->mapWallet.count(hash))
1587 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1589 TxToJSON(wtx, entry);
1591 int64 nCredit = wtx.GetCredit();
1592 int64 nDebit = wtx.GetDebit();
1593 int64 nNet = nCredit - nDebit;
1594 int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
1596 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1598 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1600 WalletTxToJSON(wtx, entry);
1603 ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
1604 entry.push_back(Pair("details", details));
1609 uint256 hashBlock = 0;
1610 if (GetTransaction(hash, tx, hashBlock))
1612 entry.push_back(Pair("txid", hash.GetHex()));
1613 TxToJSON(tx, entry);
1615 entry.push_back(Pair("confirmations", 0));
1618 entry.push_back(Pair("blockhash", hashBlock.GetHex()));
1619 map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
1620 if (mi != mapBlockIndex.end() && (*mi).second)
1622 CBlockIndex* pindex = (*mi).second;
1623 if (pindex->IsInMainChain())
1625 entry.push_back(Pair("confirmations", 1 + nBestHeight - pindex->nHeight));
1626 entry.push_back(Pair("txntime", (boost::int64_t)tx.nTime));
1627 entry.push_back(Pair("time", (boost::int64_t)pindex->nTime));
1630 entry.push_back(Pair("confirmations", 0));
1635 throw JSONRPCError(-5, "No information available about transaction");
1642 Value backupwallet(const Array& params, bool fHelp)
1644 if (fHelp || params.size() != 1)
1645 throw runtime_error(
1646 "backupwallet <destination>\n"
1647 "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1649 string strDest = params[0].get_str();
1650 BackupWallet(*pwalletMain, strDest);
1656 Value keypoolrefill(const Array& params, bool fHelp)
1658 if (pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1659 throw runtime_error(
1661 "Fills the keypool, requires wallet passphrase to be set.");
1662 if (!pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1663 throw runtime_error(
1665 "Fills the keypool.");
1667 if (pwalletMain->IsLocked())
1668 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
1670 pwalletMain->TopUpKeyPool();
1672 if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100))
1673 throw JSONRPCError(-4, "Error refreshing keypool.");
1679 void ThreadTopUpKeyPool(void* parg)
1681 pwalletMain->TopUpKeyPool();
1684 void ThreadCleanWalletPassphrase(void* parg)
1686 int64 nMyWakeTime = GetTimeMillis() + *((int64*)parg) * 1000;
1688 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1690 if (nWalletUnlockTime == 0)
1692 nWalletUnlockTime = nMyWakeTime;
1696 if (nWalletUnlockTime==0)
1698 int64 nToSleep = nWalletUnlockTime - GetTimeMillis();
1702 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1704 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1708 if (nWalletUnlockTime)
1710 nWalletUnlockTime = 0;
1711 pwalletMain->Lock();
1716 if (nWalletUnlockTime < nMyWakeTime)
1717 nWalletUnlockTime = nMyWakeTime;
1720 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1722 delete (int64*)parg;
1725 Value walletpassphrase(const Array& params, bool fHelp)
1727 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 3))
1728 throw runtime_error(
1729 "walletpassphrase <passphrase> <timeout> [mintonly]\n"
1730 "Stores the wallet decryption key in memory for <timeout> seconds.\n"
1731 "mintonly is optional true/false allowing only block minting.");
1734 if (!pwalletMain->IsCrypted())
1735 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1737 if (!pwalletMain->IsLocked())
1738 throw JSONRPCError(-17, "Error: Wallet is already unlocked, use walletlock first if need to change unlock settings.");
1740 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1741 SecureString strWalletPass;
1742 strWalletPass.reserve(100);
1743 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1744 // Alternately, find a way to make params[0] mlock()'d to begin with.
1745 strWalletPass = params[0].get_str().c_str();
1747 if (strWalletPass.length() > 0)
1749 if (!pwalletMain->Unlock(strWalletPass))
1750 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1753 throw runtime_error(
1754 "walletpassphrase <passphrase> <timeout>\n"
1755 "Stores the wallet decryption key in memory for <timeout> seconds.");
1757 CreateThread(ThreadTopUpKeyPool, NULL);
1758 int64* pnSleepTime = new int64(params[1].get_int64());
1759 CreateThread(ThreadCleanWalletPassphrase, pnSleepTime);
1761 // ppcoin: if user OS account compromised prevent trivial sendmoney commands
1762 if (params.size() > 2)
1763 fWalletUnlockMintOnly = params[2].get_bool();
1765 fWalletUnlockMintOnly = false;
1771 Value walletpassphrasechange(const Array& params, bool fHelp)
1773 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1774 throw runtime_error(
1775 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1776 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1779 if (!pwalletMain->IsCrypted())
1780 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1782 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1783 // Alternately, find a way to make params[0] mlock()'d to begin with.
1784 SecureString strOldWalletPass;
1785 strOldWalletPass.reserve(100);
1786 strOldWalletPass = params[0].get_str().c_str();
1788 SecureString strNewWalletPass;
1789 strNewWalletPass.reserve(100);
1790 strNewWalletPass = params[1].get_str().c_str();
1792 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1793 throw runtime_error(
1794 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1795 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1797 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1798 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1804 Value walletlock(const Array& params, bool fHelp)
1806 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1807 throw runtime_error(
1809 "Removes the wallet encryption key from memory, locking the wallet.\n"
1810 "After calling this method, you will need to call walletpassphrase again\n"
1811 "before being able to call any methods which require the wallet to be unlocked.");
1814 if (!pwalletMain->IsCrypted())
1815 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called.");
1818 LOCK(cs_nWalletUnlockTime);
1819 pwalletMain->Lock();
1820 nWalletUnlockTime = 0;
1827 Value encryptwallet(const Array& params, bool fHelp)
1829 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1830 throw runtime_error(
1831 "encryptwallet <passphrase>\n"
1832 "Encrypts the wallet with <passphrase>.");
1835 if (pwalletMain->IsCrypted())
1836 throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
1838 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1839 // Alternately, find a way to make params[0] mlock()'d to begin with.
1840 SecureString strWalletPass;
1841 strWalletPass.reserve(100);
1842 strWalletPass = params[0].get_str().c_str();
1844 if (strWalletPass.length() < 1)
1845 throw runtime_error(
1846 "encryptwallet <passphrase>\n"
1847 "Encrypts the wallet with <passphrase>.");
1849 if (!pwalletMain->EncryptWallet(strWalletPass))
1850 throw JSONRPCError(-16, "Error: Failed to encrypt the wallet.");
1852 // BDB seems to have a bad habit of writing old data into
1853 // slack space in .dat files; that is bad if the old data is
1854 // unencrypted private keys. So:
1856 return "wallet encrypted; novacoin server stopping, restart to run with encrypted wallet";
1860 Value validateaddress(const Array& params, bool fHelp)
1862 if (fHelp || params.size() != 1)
1863 throw runtime_error(
1864 "validateaddress <novacoinaddress>\n"
1865 "Return information about <novacoinaddress>.");
1867 CBitcoinAddress address(params[0].get_str());
1868 bool isValid = address.IsValid();
1871 ret.push_back(Pair("isvalid", isValid));
1874 // Call Hash160ToAddress() so we always return current ADDRESSVERSION
1875 // version of the address:
1876 string currentAddress = address.ToString();
1877 ret.push_back(Pair("address", currentAddress));
1878 if (pwalletMain->HaveKey(address))
1880 ret.push_back(Pair("ismine", true));
1881 std::vector<unsigned char> vchPubKey;
1882 pwalletMain->GetPubKey(address, vchPubKey);
1883 ret.push_back(Pair("pubkey", HexStr(vchPubKey)));
1885 key.SetPubKey(vchPubKey);
1886 ret.push_back(Pair("iscompressed", key.IsCompressed()));
1888 else if (pwalletMain->HaveCScript(address.GetHash160()))
1890 ret.push_back(Pair("isscript", true));
1892 pwalletMain->GetCScript(address.GetHash160(), subscript);
1893 ret.push_back(Pair("ismine", ::IsMine(*pwalletMain, subscript)));
1894 std::vector<CBitcoinAddress> addresses;
1895 txnouttype whichType;
1897 ExtractAddresses(subscript, whichType, addresses, nRequired);
1898 ret.push_back(Pair("script", GetTxnOutputType(whichType)));
1900 BOOST_FOREACH(const CBitcoinAddress& addr, addresses)
1901 a.push_back(addr.ToString());
1902 ret.push_back(Pair("addresses", a));
1903 if (whichType == TX_MULTISIG)
1904 ret.push_back(Pair("sigsrequired", nRequired));
1907 ret.push_back(Pair("ismine", false));
1908 if (pwalletMain->mapAddressBook.count(address))
1909 ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
1914 Value validatepubkey(const Array& params, bool fHelp)
1916 if (fHelp || !params.size() || params.size() > 2)
1917 throw runtime_error(
1918 "validatepubkey <novacoinpubkey>\n"
1919 "Return information about <novacoinpubkey>.");
1921 std::vector<unsigned char> vchPubKey = ParseHex(params[0].get_str());
1924 if(vchPubKey.size() == 33) // Compressed key
1925 isValid = (vchPubKey[0] == 0x02 || vchPubKey[0] == 0x03);
1926 else if(vchPubKey.size() == 65) // Uncompressed key
1927 isValid = vchPubKey[0] == 0x04;
1931 CBitcoinAddress address(vchPubKey);
1932 isValid = isValid ? address.IsValid() : false;
1935 ret.push_back(Pair("isvalid", isValid));
1938 // Call Hash160ToAddress() so we always return current ADDRESSVERSION
1939 // version of the address:
1940 string currentAddress = address.ToString();
1941 ret.push_back(Pair("address", currentAddress));
1942 if (pwalletMain->HaveKey(address))
1944 ret.push_back(Pair("ismine", true));
1946 key.SetPubKey(vchPubKey);
1947 ret.push_back(Pair("iscompressed", key.IsCompressed()));
1950 ret.push_back(Pair("ismine", false));
1951 if (pwalletMain->mapAddressBook.count(address))
1952 ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
1958 Value getwork(const Array& params, bool fHelp)
1960 if (fHelp || params.size() > 1)
1961 throw runtime_error(
1963 "If [data] is not specified, returns formatted hash data to work on:\n"
1964 " \"midstate\" : precomputed hash state after hashing the first half of the data (DEPRECATED)\n" // deprecated
1965 " \"data\" : block data\n"
1966 " \"hash1\" : formatted hash buffer for second hash (DEPRECATED)\n" // deprecated
1967 " \"target\" : little endian hash target\n"
1968 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1971 throw JSONRPCError(-9, "NovaCoin is not connected!");
1973 if (IsInitialBlockDownload())
1974 throw JSONRPCError(-10, "NovaCoin is downloading blocks...");
1976 typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
1977 static mapNewBlock_t mapNewBlock;
1978 static vector<CBlock*> vNewBlock;
1979 static CReserveKey reservekey(pwalletMain);
1981 if (params.size() == 0)
1984 static unsigned int nTransactionsUpdatedLast;
1985 static CBlockIndex* pindexPrev;
1986 static int64 nStart;
1987 static CBlock* pblock;
1988 if (pindexPrev != pindexBest ||
1989 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
1991 if (pindexPrev != pindexBest)
1993 // Deallocate old blocks since they're obsolete now
1994 mapNewBlock.clear();
1995 BOOST_FOREACH(CBlock* pblock, vNewBlock)
1999 nTransactionsUpdatedLast = nTransactionsUpdated;
2000 pindexPrev = pindexBest;
2004 pblock = CreateNewBlock(pwalletMain);
2006 throw JSONRPCError(-7, "Out of memory");
2007 vNewBlock.push_back(pblock);
2011 pblock->UpdateTime(pindexPrev);
2014 // Update nExtraNonce
2015 static unsigned int nExtraNonce = 0;
2016 IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
2019 mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
2021 // Prebuild hash buffers
2025 FormatHashBuffers(pblock, pmidstate, pdata, phash1);
2027 uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
2030 result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate)))); // deprecated
2031 result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata))));
2032 result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1)))); // deprecated
2033 result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
2039 vector<unsigned char> vchData = ParseHex(params[0].get_str());
2040 if (vchData.size() != 128)
2041 throw JSONRPCError(-8, "Invalid parameter");
2042 CBlock* pdata = (CBlock*)&vchData[0];
2045 for (int i = 0; i < 128/4; i++)
2046 ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]);
2049 if (!mapNewBlock.count(pdata->hashMerkleRoot))
2051 CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
2053 pblock->nTime = pdata->nTime;
2054 pblock->nNonce = pdata->nNonce;
2055 pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
2056 pblock->hashMerkleRoot = pblock->BuildMerkleTree();
2057 if (!pblock->SignBlock(*pwalletMain))
2058 throw JSONRPCError(-100, "Unable to sign block, wallet locked?");
2060 return CheckWork(pblock, *pwalletMain, reservekey);
2064 Value getblocktemplate(const Array& params, bool fHelp)
2066 if (fHelp || params.size() > 1)
2067 throw runtime_error(
2068 "getblocktemplate [params]\n"
2069 "Returns data needed to construct a block to work on:\n"
2070 " \"version\" : block version\n"
2071 " \"previousblockhash\" : hash of current highest block\n"
2072 " \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
2073 " \"coinbaseaux\" : data that should be included in coinbase\n"
2074 " \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
2075 " \"target\" : hash target\n"
2076 " \"mintime\" : minimum timestamp appropriate for next block\n"
2077 " \"curtime\" : current timestamp\n"
2078 " \"mutable\" : list of ways the block template may be changed\n"
2079 " \"noncerange\" : range of valid nonces\n"
2080 " \"sigoplimit\" : limit of sigops in blocks\n"
2081 " \"sizelimit\" : limit of block size\n"
2082 " \"bits\" : compressed target of next block\n"
2083 " \"height\" : height of the next block\n"
2084 "See https://en.bitcoin.it/wiki/BIP_0022 for full specification.");
2086 std::string strMode = "template";
2087 if (params.size() > 0)
2089 const Object& oparam = params[0].get_obj();
2090 const Value& modeval = find_value(oparam, "mode");
2091 if (modeval.type() == str_type)
2092 strMode = modeval.get_str();
2094 throw JSONRPCError(-8, "Invalid mode");
2097 if (strMode != "template")
2098 throw JSONRPCError(-8, "Invalid mode");
2101 throw JSONRPCError(-9, "NovaCoin is not connected!");
2103 if (IsInitialBlockDownload())
2104 throw JSONRPCError(-10, "NovaCoin is downloading blocks...");
2106 static CReserveKey reservekey(pwalletMain);
2109 static unsigned int nTransactionsUpdatedLast;
2110 static CBlockIndex* pindexPrev;
2111 static int64 nStart;
2112 static CBlock* pblock;
2113 if (pindexPrev != pindexBest ||
2114 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5))
2116 // Clear pindexPrev so future calls make a new block, despite any failures from here on
2119 // Store the pindexBest used before CreateNewBlock, to avoid races
2120 nTransactionsUpdatedLast = nTransactionsUpdated;
2121 CBlockIndex* pindexPrevNew = pindexBest;
2130 pblock = CreateNewBlock(pwalletMain);
2132 throw JSONRPCError(-7, "Out of memory");
2134 // Need to update only after we know CreateNewBlock succeeded
2135 pindexPrev = pindexPrevNew;
2139 pblock->UpdateTime(pindexPrev);
2143 map<uint256, int64_t> setTxIndex;
2146 BOOST_FOREACH (CTransaction& tx, pblock->vtx)
2148 uint256 txHash = tx.GetHash();
2149 setTxIndex[txHash] = i++;
2151 if (tx.IsCoinBase() || tx.IsCoinStake())
2156 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
2158 entry.push_back(Pair("data", HexStr(ssTx.begin(), ssTx.end())));
2160 entry.push_back(Pair("hash", txHash.GetHex()));
2162 MapPrevTx mapInputs;
2163 map<uint256, CTxIndex> mapUnused;
2164 bool fInvalid = false;
2165 if (tx.FetchInputs(txdb, mapUnused, false, false, mapInputs, fInvalid))
2167 entry.push_back(Pair("fee", (int64_t)(tx.GetValueIn(mapInputs) - tx.GetValueOut())));
2170 BOOST_FOREACH (MapPrevTx::value_type& inp, mapInputs)
2172 if (setTxIndex.count(inp.first))
2173 deps.push_back(setTxIndex[inp.first]);
2175 entry.push_back(Pair("depends", deps));
2177 int64_t nSigOps = tx.GetLegacySigOpCount();
2178 nSigOps += tx.GetP2SHSigOpCount(mapInputs);
2179 entry.push_back(Pair("sigops", nSigOps));
2182 transactions.push_back(entry);
2186 aux.push_back(Pair("flags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end())));
2188 uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
2190 static Array aMutable;
2191 if (aMutable.empty())
2193 aMutable.push_back("time");
2194 aMutable.push_back("transactions");
2195 aMutable.push_back("prevblock");
2199 result.push_back(Pair("version", pblock->nVersion));
2200 result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
2201 result.push_back(Pair("transactions", transactions));
2202 result.push_back(Pair("coinbaseaux", aux));
2203 result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
2204 result.push_back(Pair("target", hashTarget.GetHex()));
2205 result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1));
2206 result.push_back(Pair("mutable", aMutable));
2207 result.push_back(Pair("noncerange", "00000000ffffffff"));
2208 result.push_back(Pair("sigoplimit", (int64_t)MAX_BLOCK_SIGOPS));
2209 result.push_back(Pair("sizelimit", (int64_t)MAX_BLOCK_SIZE));
2210 result.push_back(Pair("curtime", (int64_t)pblock->nTime));
2211 result.push_back(Pair("bits", HexBits(pblock->nBits)));
2212 result.push_back(Pair("height", (int64_t)(pindexPrev->nHeight+1)));
2217 Value submitblock(const Array& params, bool fHelp)
2219 if (fHelp || params.size() < 1 || params.size() > 2)
2220 throw runtime_error(
2221 "submitblock <hex data> [optional-params-obj]\n"
2222 "[optional-params-obj] parameter is currently ignored.\n"
2223 "Attempts to submit new block to network.\n"
2224 "See https://en.bitcoin.it/wiki/BIP_0022 for full specification.");
2226 vector<unsigned char> blockData(ParseHex(params[0].get_str()));
2227 CDataStream ssBlock(blockData, SER_NETWORK, PROTOCOL_VERSION);
2232 catch (std::exception &e) {
2233 throw JSONRPCError(-22, "Block decode failed");
2236 static CReserveKey reservekey(pwalletMain);
2238 if(!block.SignBlock(*pwalletMain))
2239 throw JSONRPCError(-100, "Unable to sign block, wallet locked?");
2241 bool fAccepted = CheckWork(&block, *pwalletMain, reservekey);
2249 Value getmemorypool(const Array& params, bool fHelp)
2251 if (fHelp || params.size() > 1)
2252 throw runtime_error(
2253 "getmemorypool [data]\n"
2254 "If [data] is not specified, returns data needed to construct a block to work on:\n"
2255 " \"version\" : block version\n"
2256 " \"previousblockhash\" : hash of current highest block\n"
2257 " \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
2258 " \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
2259 " \"coinbaseflags\" : data that should be included in coinbase so support for new features can be judged\n"
2260 " \"time\" : timestamp appropriate for next block\n"
2261 " \"mintime\" : minimum timestamp appropriate for next block\n"
2262 " \"curtime\" : current timestamp\n"
2263 " \"bits\" : compressed target of next block\n"
2264 "If [data] is specified, tries to solve the block and returns true if it was successful.");
2266 if (params.size() == 0)
2269 throw JSONRPCError(-9, "NovaCoin is not connected!");
2271 if (IsInitialBlockDownload())
2272 throw JSONRPCError(-10, "NovaCoin is downloading blocks...");
2274 static CReserveKey reservekey(pwalletMain);
2277 static unsigned int nTransactionsUpdatedLast;
2278 static CBlockIndex* pindexPrev;
2279 static int64 nStart;
2280 static CBlock* pblock;
2281 if (pindexPrev != pindexBest ||
2282 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5))
2284 nTransactionsUpdatedLast = nTransactionsUpdated;
2285 pindexPrev = pindexBest;
2291 pblock = CreateNewBlock(pwalletMain);
2293 throw JSONRPCError(-7, "Out of memory");
2297 pblock->UpdateTime(pindexPrev);
2301 BOOST_FOREACH(CTransaction tx, pblock->vtx) {
2302 if(tx.IsCoinBase() || tx.IsCoinStake())
2305 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
2308 transactions.push_back(HexStr(ssTx.begin(), ssTx.end()));
2312 result.push_back(Pair("version", pblock->nVersion));
2313 result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
2314 result.push_back(Pair("transactions", transactions));
2315 result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
2316 result.push_back(Pair("coinbaseflags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end())));
2317 result.push_back(Pair("time", (int64_t)pblock->nTime));
2318 result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1));
2319 result.push_back(Pair("curtime", (int64_t)GetAdjustedTime()));
2320 result.push_back(Pair("bits", HexBits(pblock->nBits)));
2327 CDataStream ssBlock(ParseHex(params[0].get_str()), SER_NETWORK, PROTOCOL_VERSION);
2331 static CReserveKey reservekey(pwalletMain);
2333 if(!pblock.SignBlock(*pwalletMain))
2334 throw JSONRPCError(-100, "Unable to sign block, wallet locked?");
2336 return CheckWork(&pblock, *pwalletMain, reservekey);
2340 Value getnewpubkey(const Array& params, bool fHelp)
2342 if (fHelp || params.size() > 1)
2343 throw runtime_error(
2344 "getnewpubkey [account]\n"
2345 "Returns new public key for coinbase generation.");
2347 // Parse the account first so we don't generate a key if there's an error
2349 if (params.size() > 0)
2350 strAccount = AccountFromValue(params[0]);
2352 if (!pwalletMain->IsLocked())
2353 pwalletMain->TopUpKeyPool();
2355 // Generate a new key that is added to wallet
2356 std::vector<unsigned char> newKey = pwalletMain->GenerateNewKey(true);
2359 throw JSONRPCError(-12, "Error: Unable to create key");
2361 CBitcoinAddress address(newKey);
2362 pwalletMain->SetAddressBookName(address, strAccount);
2364 return HexStr(newKey.begin(), newKey.end());
2367 Value getblockhash(const Array& params, bool fHelp)
2369 if (fHelp || params.size() != 1)
2370 throw runtime_error(
2371 "getblockhash <index>\n"
2372 "Returns hash of block in best-block-chain at <index>.");
2374 int nHeight = params[0].get_int();
2375 if (nHeight < 0 || nHeight > nBestHeight)
2376 throw runtime_error("Block number out of range.");
2379 CBlockIndex* pblockindex = mapBlockIndex[hashBestChain];
2380 while (pblockindex->nHeight > nHeight)
2381 pblockindex = pblockindex->pprev;
2382 return pblockindex->phashBlock->GetHex();
2385 Value getblock(const Array& params, bool fHelp)
2387 if (fHelp || params.size() < 1 || params.size() > 2)
2388 throw runtime_error(
2389 "getblock <hash> [txinfo]\n"
2390 "txinfo optional to print more detailed tx info\n"
2391 "Returns details of a block with given block-hash.");
2393 std::string strHash = params[0].get_str();
2394 uint256 hash(strHash);
2396 if (mapBlockIndex.count(hash) == 0)
2397 throw JSONRPCError(-5, "Block not found");
2400 CBlockIndex* pblockindex = mapBlockIndex[hash];
2401 block.ReadFromDisk(pblockindex, true);
2403 return blockToJSON(block, pblockindex, params.size() > 1 ? params[1].get_bool() : false);
2406 Value getblockbynumber(const Array& params, bool fHelp)
2408 if (fHelp || params.size() < 1 || params.size() > 2)
2409 throw runtime_error(
2410 "getblock <number> [txinfo]\n"
2411 "txinfo optional to print more detailed tx info\n"
2412 "Returns details of a block with given block-number.");
2414 int nHeight = params[0].get_int();
2415 if (nHeight < 0 || nHeight > nBestHeight)
2416 throw runtime_error("Block number out of range.");
2419 CBlockIndex* pblockindex = mapBlockIndex[hashBestChain];
2420 while (pblockindex->nHeight > nHeight)
2421 pblockindex = pblockindex->pprev;
2423 uint256 hash = *pblockindex->phashBlock;
2425 pblockindex = mapBlockIndex[hash];
2426 block.ReadFromDisk(pblockindex, true);
2428 return blockToJSON(block, pblockindex, params.size() > 1 ? params[1].get_bool() : false);
2431 // ppcoin: get information of sync-checkpoint
2432 Value getcheckpoint(const Array& params, bool fHelp)
2434 if (fHelp || params.size() != 0)
2435 throw runtime_error(
2437 "Show info of synchronized checkpoint.\n");
2440 CBlockIndex* pindexCheckpoint;
2442 result.push_back(Pair("synccheckpoint", Checkpoints::hashSyncCheckpoint.ToString().c_str()));
2443 pindexCheckpoint = mapBlockIndex[Checkpoints::hashSyncCheckpoint];
2444 result.push_back(Pair("height", pindexCheckpoint->nHeight));
2445 result.push_back(Pair("timestamp", DateTimeStrFormat(pindexCheckpoint->GetBlockTime()).c_str()));
2446 if (mapArgs.count("-checkpointkey"))
2447 result.push_back(Pair("checkpointmaster", true));
2453 // ppcoin: reserve balance from being staked for network protection
2454 Value reservebalance(const Array& params, bool fHelp)
2456 if (fHelp || params.size() > 2)
2457 throw runtime_error(
2458 "reservebalance [<reserve> [amount]]\n"
2459 "<reserve> is true or false to turn balance reserve on or off.\n"
2460 "<amount> is a real and rounded to cent.\n"
2461 "Set reserve amount not participating in network protection.\n"
2462 "If no parameters provided current setting is printed.\n");
2464 if (params.size() > 0)
2466 bool fReserve = params[0].get_bool();
2469 if (params.size() == 1)
2470 throw runtime_error("must provide amount to reserve balance.\n");
2471 int64 nAmount = AmountFromValue(params[1]);
2472 nAmount = (nAmount / CENT) * CENT; // round to cent
2474 throw runtime_error("amount cannot be negative.\n");
2475 mapArgs["-reservebalance"] = FormatMoney(nAmount).c_str();
2479 if (params.size() > 1)
2480 throw runtime_error("cannot specify amount to turn off reserve.\n");
2481 mapArgs["-reservebalance"] = "0";
2486 int64 nReserveBalance = 0;
2487 if (mapArgs.count("-reservebalance") && !ParseMoney(mapArgs["-reservebalance"], nReserveBalance))
2488 throw runtime_error("invalid reserve balance amount\n");
2489 result.push_back(Pair("reserve", (nReserveBalance > 0)));
2490 result.push_back(Pair("amount", ValueFromAmount(nReserveBalance)));
2495 // ppcoin: check wallet integrity
2496 Value checkwallet(const Array& params, bool fHelp)
2498 if (fHelp || params.size() > 0)
2499 throw runtime_error(
2501 "Check wallet for integrity.\n");
2504 int64 nBalanceInQuestion;
2505 pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion, true);
2507 if (nMismatchSpent == 0)
2508 result.push_back(Pair("wallet check passed", true));
2511 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
2512 result.push_back(Pair("amount in question", ValueFromAmount(nBalanceInQuestion)));
2518 // ppcoin: repair wallet
2519 Value repairwallet(const Array& params, bool fHelp)
2521 if (fHelp || params.size() > 0)
2522 throw runtime_error(
2524 "Repair wallet if checkwallet reports any problem.\n");
2527 int64 nBalanceInQuestion;
2528 pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion);
2530 if (nMismatchSpent == 0)
2531 result.push_back(Pair("wallet check passed", true));
2534 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
2535 result.push_back(Pair("amount affected by repair", ValueFromAmount(nBalanceInQuestion)));
2540 // NovaCoin: resend unconfirmed wallet transactions
2541 Value resendtx(const Array& params, bool fHelp)
2543 if (fHelp || params.size() > 1)
2544 throw runtime_error(
2546 "Re-send unconfirmed transactions.\n"
2549 ResendWalletTransactions();
2555 // ppcoin: make a public-private key pair
2556 Value makekeypair(const Array& params, bool fHelp)
2558 if (fHelp || params.size() > 1)
2559 throw runtime_error(
2560 "makekeypair [prefix]\n"
2561 "Make a public/private key pair.\n"
2562 "[prefix] is optional preferred prefix for the public key.\n");
2564 string strPrefix = "";
2565 if (params.size() > 0)
2566 strPrefix = params[0].get_str();
2572 key.MakeNewKey(false);
2574 } while (nCount < 10000 && strPrefix != HexStr(key.GetPubKey()).substr(0, strPrefix.size()));
2576 if (strPrefix != HexStr(key.GetPubKey()).substr(0, strPrefix.size()))
2579 CPrivKey vchPrivKey = key.GetPrivKey();
2581 result.push_back(Pair("PrivateKey", HexStr<CPrivKey::iterator>(vchPrivKey.begin(), vchPrivKey.end())));
2582 result.push_back(Pair("PublicKey", HexStr(key.GetPubKey())));
2586 extern CCriticalSection cs_mapAlerts;
2587 extern map<uint256, CAlert> mapAlerts;
2589 // ppcoin: send alert.
2590 // There is a known deadlock situation with ThreadMessageHandler
2591 // ThreadMessageHandler: holds cs_vSend and acquiring cs_main in SendMessages()
2592 // ThreadRPCServer: holds cs_main and acquiring cs_vSend in alert.RelayTo()/PushMessage()/BeginMessage()
2593 Value sendalert(const Array& params, bool fHelp)
2595 if (fHelp || params.size() < 6)
2596 throw runtime_error(
2597 "sendalert <message> <privatekey> <minver> <maxver> <priority> <id> [cancelupto]\n"
2598 "<message> is the alert text message\n"
2599 "<privatekey> is hex string of alert master private key\n"
2600 "<minver> is the minimum applicable internal client version\n"
2601 "<maxver> is the maximum applicable internal client version\n"
2602 "<priority> is integer priority number\n"
2603 "<id> is the alert id\n"
2604 "[cancelupto] cancels all alert id's up to this number\n"
2605 "Returns true or false.");
2610 alert.strStatusBar = params[0].get_str();
2611 alert.nMinVer = params[2].get_int();
2612 alert.nMaxVer = params[3].get_int();
2613 alert.nPriority = params[4].get_int();
2614 alert.nID = params[5].get_int();
2615 if (params.size() > 6)
2616 alert.nCancel = params[6].get_int();
2617 alert.nVersion = PROTOCOL_VERSION;
2618 alert.nRelayUntil = GetAdjustedTime() + 365*24*60*60;
2619 alert.nExpiration = GetAdjustedTime() + 365*24*60*60;
2621 CDataStream sMsg(SER_NETWORK, PROTOCOL_VERSION);
2622 sMsg << (CUnsignedAlert)alert;
2623 alert.vchMsg = vector<unsigned char>(sMsg.begin(), sMsg.end());
2625 vector<unsigned char> vchPrivKey = ParseHex(params[1].get_str());
2626 key.SetPrivKey(CPrivKey(vchPrivKey.begin(), vchPrivKey.end())); // if key is not correct openssl may crash
2627 if (!key.Sign(Hash(alert.vchMsg.begin(), alert.vchMsg.end()), alert.vchSig))
2628 throw runtime_error(
2629 "Unable to sign alert, check private key?\n");
2630 if(!alert.ProcessAlert())
2631 throw runtime_error(
2632 "Failed to process alert.\n");
2636 BOOST_FOREACH(CNode* pnode, vNodes)
2637 alert.RelayTo(pnode);
2641 result.push_back(Pair("strStatusBar", alert.strStatusBar));
2642 result.push_back(Pair("nVersion", alert.nVersion));
2643 result.push_back(Pair("nMinVer", alert.nMinVer));
2644 result.push_back(Pair("nMaxVer", alert.nMaxVer));
2645 result.push_back(Pair("nPriority", alert.nPriority));
2646 result.push_back(Pair("nID", alert.nID));
2647 if (alert.nCancel > 0)
2648 result.push_back(Pair("nCancel", alert.nCancel));
2659 static const CRPCCommand vRPCCommands[] =
2660 { // name function safe mode?
2661 // ------------------------ ----------------------- ----------
2662 { "help", &help, true },
2663 { "stop", &stop, true },
2664 { "getblockcount", &getblockcount, true },
2665 { "getblocknumber", &getblocknumber, true },
2666 { "getconnectioncount", &getconnectioncount, true },
2667 { "getdifficulty", &getdifficulty, true },
2668 { "getpowreward", &getpowreward, true },
2669 { "getgenerate", &getgenerate, true },
2670 { "setgenerate", &setgenerate, true },
2671 { "gethashespersec", &gethashespersec, true },
2672 { "getinfo", &getinfo, true },
2673 { "getmininginfo", &getmininginfo, true },
2674 { "getnewaddress", &getnewaddress, true },
2675 { "getnewpubkey", &getnewpubkey, true },
2676 { "getaccountaddress", &getaccountaddress, true },
2677 { "setaccount", &setaccount, true },
2678 { "getaccount", &getaccount, false },
2679 { "getaddressesbyaccount", &getaddressesbyaccount, true },
2680 { "sendtoaddress", &sendtoaddress, false },
2681 { "getreceivedbyaddress", &getreceivedbyaddress, false },
2682 { "getreceivedbyaccount", &getreceivedbyaccount, false },
2683 { "listreceivedbyaddress", &listreceivedbyaddress, false },
2684 { "listreceivedbyaccount", &listreceivedbyaccount, false },
2685 { "backupwallet", &backupwallet, true },
2686 { "keypoolrefill", &keypoolrefill, true },
2687 { "walletpassphrase", &walletpassphrase, true },
2688 { "walletpassphrasechange", &walletpassphrasechange, false },
2689 { "walletlock", &walletlock, true },
2690 { "encryptwallet", &encryptwallet, false },
2691 { "validateaddress", &validateaddress, true },
2692 { "validatepubkey", &validatepubkey, true },
2693 { "getbalance", &getbalance, false },
2694 { "move", &movecmd, false },
2695 { "sendfrom", &sendfrom, false },
2696 { "sendmany", &sendmany, false },
2697 { "addmultisigaddress", &addmultisigaddress, false },
2698 { "getblock", &getblock, false },
2699 { "getblockhash", &getblockhash, false },
2700 { "getblockbynumber", &getblockbynumber, false },
2701 { "gettransaction", &gettransaction, false },
2702 { "listtransactions", &listtransactions, false },
2703 { "signmessage", &signmessage, false },
2704 { "verifymessage", &verifymessage, false },
2705 { "getwork", &getwork, true },
2706 { "listaccounts", &listaccounts, false },
2707 { "settxfee", &settxfee, false },
2708 { "getmemorypool", &getmemorypool, true },
2709 { "getblocktemplate", &getblocktemplate, true },
2710 { "submitblock", &submitblock, false },
2711 { "listsinceblock", &listsinceblock, false },
2712 { "dumpprivkey", &dumpprivkey, false },
2713 { "importprivkey", &importprivkey, false },
2714 { "getcheckpoint", &getcheckpoint, true },
2715 { "reservebalance", &reservebalance, false},
2716 { "checkwallet", &checkwallet, false},
2717 { "repairwallet", &repairwallet, false},
2718 { "resendtx", &resendtx, false},
2719 { "makekeypair", &makekeypair, false},
2720 { "sendalert", &sendalert, false},
2723 CRPCTable::CRPCTable()
2726 for (vcidx = 0; vcidx < (sizeof(vRPCCommands) / sizeof(vRPCCommands[0])); vcidx++)
2728 const CRPCCommand *pcmd;
2730 pcmd = &vRPCCommands[vcidx];
2731 mapCommands[pcmd->name] = pcmd;
2735 const CRPCCommand *CRPCTable::operator[](string name) const
2737 map<string, const CRPCCommand*>::const_iterator it = mapCommands.find(name);
2738 if (it == mapCommands.end())
2740 return (*it).second;
2746 // This ain't Apache. We're just using HTTP header for the length field
2747 // and to be compatible with other JSON-RPC implementations.
2750 string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
2753 s << "POST / HTTP/1.1\r\n"
2754 << "User-Agent: novacoin-json-rpc/" << FormatFullVersion() << "\r\n"
2755 << "Host: 127.0.0.1\r\n"
2756 << "Content-Type: application/json\r\n"
2757 << "Content-Length: " << strMsg.size() << "\r\n"
2758 << "Connection: close\r\n"
2759 << "Accept: application/json\r\n";
2760 BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
2761 s << item.first << ": " << item.second << "\r\n";
2762 s << "\r\n" << strMsg;
2767 string rfc1123Time()
2772 struct tm* now_gmt = gmtime(&now);
2773 string locale(setlocale(LC_TIME, NULL));
2774 setlocale(LC_TIME, "C"); // we want posix (aka "C") weekday/month strings
2775 strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt);
2776 setlocale(LC_TIME, locale.c_str());
2777 return string(buffer);
2780 static string HTTPReply(int nStatus, const string& strMsg)
2783 return strprintf("HTTP/1.0 401 Authorization Required\r\n"
2785 "Server: novacoin-json-rpc/%s\r\n"
2786 "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
2787 "Content-Type: text/html\r\n"
2788 "Content-Length: 296\r\n"
2790 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
2791 "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
2794 "<TITLE>Error</TITLE>\r\n"
2795 "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
2797 "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
2798 "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
2799 const char *cStatus;
2800 if (nStatus == 200) cStatus = "OK";
2801 else if (nStatus == 400) cStatus = "Bad Request";
2802 else if (nStatus == 403) cStatus = "Forbidden";
2803 else if (nStatus == 404) cStatus = "Not Found";
2804 else if (nStatus == 500) cStatus = "Internal Server Error";
2807 "HTTP/1.1 %d %s\r\n"
2809 "Connection: close\r\n"
2810 "Content-Length: %d\r\n"
2811 "Content-Type: application/json\r\n"
2812 "Server: novacoin-json-rpc/%s\r\n"
2817 rfc1123Time().c_str(),
2819 FormatFullVersion().c_str(),
2823 int ReadHTTPStatus(std::basic_istream<char>& stream)
2826 getline(stream, str);
2827 vector<string> vWords;
2828 boost::split(vWords, str, boost::is_any_of(" "));
2829 if (vWords.size() < 2)
2831 return atoi(vWords[1].c_str());
2834 int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
2840 std::getline(stream, str);
2841 if (str.empty() || str == "\r")
2843 string::size_type nColon = str.find(":");
2844 if (nColon != string::npos)
2846 string strHeader = str.substr(0, nColon);
2847 boost::trim(strHeader);
2848 boost::to_lower(strHeader);
2849 string strValue = str.substr(nColon+1);
2850 boost::trim(strValue);
2851 mapHeadersRet[strHeader] = strValue;
2852 if (strHeader == "content-length")
2853 nLen = atoi(strValue.c_str());
2859 int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
2861 mapHeadersRet.clear();
2865 int nStatus = ReadHTTPStatus(stream);
2868 int nLen = ReadHTTPHeader(stream, mapHeadersRet);
2869 if (nLen < 0 || nLen > (int)MAX_SIZE)
2875 vector<char> vch(nLen);
2876 stream.read(&vch[0], nLen);
2877 strMessageRet = string(vch.begin(), vch.end());
2883 bool HTTPAuthorized(map<string, string>& mapHeaders)
2885 string strAuth = mapHeaders["authorization"];
2886 if (strAuth.substr(0,6) != "Basic ")
2888 string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
2889 string strUserPass = DecodeBase64(strUserPass64);
2890 return strUserPass == strRPCUserColonPass;
2894 // JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
2895 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
2896 // unspecified (HTTP errors and contents of 'error').
2898 // 1.0 spec: http://json-rpc.org/wiki/specification
2899 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
2900 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
2903 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
2906 request.push_back(Pair("method", strMethod));
2907 request.push_back(Pair("params", params));
2908 request.push_back(Pair("id", id));
2909 return write_string(Value(request), false) + "\n";
2912 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
2915 if (error.type() != null_type)
2916 reply.push_back(Pair("result", Value::null));
2918 reply.push_back(Pair("result", result));
2919 reply.push_back(Pair("error", error));
2920 reply.push_back(Pair("id", id));
2921 return write_string(Value(reply), false) + "\n";
2924 void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
2926 // Send error reply from json-rpc error object
2928 int code = find_value(objError, "code").get_int();
2929 if (code == -32600) nStatus = 400;
2930 else if (code == -32601) nStatus = 404;
2931 string strReply = JSONRPCReply(Value::null, objError, id);
2932 stream << HTTPReply(nStatus, strReply) << std::flush;
2935 bool ClientAllowed(const string& strAddress)
2937 if (strAddress == asio::ip::address_v4::loopback().to_string())
2939 const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
2940 BOOST_FOREACH(string strAllow, vAllow)
2941 if (WildcardMatch(strAddress, strAllow))
2947 // IOStream device that speaks SSL but can also speak non-SSL
2949 class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
2951 SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
2953 fUseSSL = fUseSSLIn;
2954 fNeedHandshake = fUseSSLIn;
2957 void handshake(ssl::stream_base::handshake_type role)
2959 if (!fNeedHandshake) return;
2960 fNeedHandshake = false;
2961 stream.handshake(role);
2963 std::streamsize read(char* s, std::streamsize n)
2965 handshake(ssl::stream_base::server); // HTTPS servers read first
2966 if (fUseSSL) return stream.read_some(asio::buffer(s, n));
2967 return stream.next_layer().read_some(asio::buffer(s, n));
2969 std::streamsize write(const char* s, std::streamsize n)
2971 handshake(ssl::stream_base::client); // HTTPS clients write first
2972 if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
2973 return asio::write(stream.next_layer(), asio::buffer(s, n));
2975 bool connect(const std::string& server, const std::string& port)
2977 ip::tcp::resolver resolver(stream.get_io_service());
2978 ip::tcp::resolver::query query(server.c_str(), port.c_str());
2979 ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
2980 ip::tcp::resolver::iterator end;
2981 boost::system::error_code error = asio::error::host_not_found;
2982 while (error && endpoint_iterator != end)
2984 stream.lowest_layer().close();
2985 stream.lowest_layer().connect(*endpoint_iterator++, error);
2993 bool fNeedHandshake;
2998 void ThreadRPCServer(void* parg)
3000 IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
3003 vnThreadsRunning[THREAD_RPCSERVER]++;
3004 ThreadRPCServer2(parg);
3005 vnThreadsRunning[THREAD_RPCSERVER]--;
3007 catch (std::exception& e) {
3008 vnThreadsRunning[THREAD_RPCSERVER]--;
3009 PrintException(&e, "ThreadRPCServer()");
3011 vnThreadsRunning[THREAD_RPCSERVER]--;
3012 PrintException(NULL, "ThreadRPCServer()");
3014 printf("ThreadRPCServer exiting\n");
3017 void ThreadRPCServer2(void* parg)
3019 printf("ThreadRPCServer started\n");
3021 strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
3022 if (mapArgs["-rpcpassword"] == "")
3024 unsigned char rand_pwd[32];
3025 RAND_bytes(rand_pwd, 32);
3026 string strWhatAmI = "To use novacoind";
3027 if (mapArgs.count("-server"))
3028 strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
3029 else if (mapArgs.count("-daemon"))
3030 strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
3031 ThreadSafeMessageBox(strprintf(
3032 _("%s, you must set a rpcpassword in the configuration file:\n %s\n"
3033 "It is recommended you use the following random password:\n"
3036 "(you do not need to remember this password)\n"
3037 "If the file does not exist, create it with owner-readable-only file permissions.\n"),
3039 GetConfigFile().string().c_str(),
3040 EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str()),
3041 _("Error"), wxOK | wxMODAL);
3046 bool fUseSSL = GetBoolArg("-rpcssl");
3047 asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
3049 asio::io_service io_service;
3050 ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", RPC_PORT));
3051 ip::tcp::acceptor acceptor(io_service);
3054 acceptor.open(endpoint.protocol());
3055 acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
3056 acceptor.bind(endpoint);
3057 acceptor.listen(socket_base::max_connections);
3059 catch(boost::system::system_error &e)
3061 ThreadSafeMessageBox(strprintf(_("An error occured while setting up the RPC port %i for listening: %s"), endpoint.port(), e.what()),
3062 _("Error"), wxOK | wxMODAL);
3067 ssl::context context(io_service, ssl::context::sslv23);
3070 context.set_options(ssl::context::no_sslv2);
3072 filesystem::path pathCertFile(GetArg("-rpcsslcertificatechainfile", "server.cert"));
3073 if (!pathCertFile.is_complete()) pathCertFile = filesystem::path(GetDataDir()) / pathCertFile;
3074 if (filesystem::exists(pathCertFile)) context.use_certificate_chain_file(pathCertFile.string());
3075 else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", pathCertFile.string().c_str());
3077 filesystem::path pathPKFile(GetArg("-rpcsslprivatekeyfile", "server.pem"));
3078 if (!pathPKFile.is_complete()) pathPKFile = filesystem::path(GetDataDir()) / pathPKFile;
3079 if (filesystem::exists(pathPKFile)) context.use_private_key_file(pathPKFile.string(), ssl::context::pem);
3080 else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pathPKFile.string().c_str());
3082 string strCiphers = GetArg("-rpcsslciphers", "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
3083 SSL_CTX_set_cipher_list(context.impl(), strCiphers.c_str());
3088 // Accept connection
3089 SSLStream sslStream(io_service, context);
3090 SSLIOStreamDevice d(sslStream, fUseSSL);
3091 iostreams::stream<SSLIOStreamDevice> stream(d);
3093 ip::tcp::endpoint peer;
3094 vnThreadsRunning[THREAD_RPCSERVER]--;
3095 acceptor.accept(sslStream.lowest_layer(), peer);
3096 vnThreadsRunning[4]++;
3100 // Restrict callers by IP
3101 if (!ClientAllowed(peer.address().to_string()))
3103 // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
3105 stream << HTTPReply(403, "") << std::flush;
3109 map<string, string> mapHeaders;
3112 boost::thread api_caller(ReadHTTP, boost::ref(stream), boost::ref(mapHeaders), boost::ref(strRequest));
3113 if (!api_caller.timed_join(boost::posix_time::seconds(GetArg("-rpctimeout", 30))))
3116 printf("ThreadRPCServer ReadHTTP timeout\n");
3120 // Check authorization
3121 if (mapHeaders.count("authorization") == 0)
3123 stream << HTTPReply(401, "") << std::flush;
3126 if (!HTTPAuthorized(mapHeaders))
3128 printf("ThreadRPCServer incorrect password attempt from %s\n",peer.address().to_string().c_str());
3129 /* Deter brute-forcing short passwords.
3130 If this results in a DOS the user really
3131 shouldn't have their RPC port exposed.*/
3132 if (mapArgs["-rpcpassword"].size() < 20)
3135 stream << HTTPReply(401, "") << std::flush;
3139 Value id = Value::null;
3144 if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
3145 throw JSONRPCError(-32700, "Parse error");
3146 const Object& request = valRequest.get_obj();
3148 // Parse id now so errors from here on will have the id
3149 id = find_value(request, "id");
3152 Value valMethod = find_value(request, "method");
3153 if (valMethod.type() == null_type)
3154 throw JSONRPCError(-32600, "Missing method");
3155 if (valMethod.type() != str_type)
3156 throw JSONRPCError(-32600, "Method must be a string");
3157 string strMethod = valMethod.get_str();
3158 if (strMethod != "getwork" && strMethod != "getmemorypool")
3159 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
3162 Value valParams = find_value(request, "params");
3164 if (valParams.type() == array_type)
3165 params = valParams.get_array();
3166 else if (valParams.type() == null_type)
3169 throw JSONRPCError(-32600, "Params must be an array");
3172 const CRPCCommand *pcmd = tableRPC[strMethod];
3174 throw JSONRPCError(-32601, "Method not found");
3176 // Observe safe mode
3177 string strWarning = GetWarnings("rpc");
3178 if (strWarning != "" && !GetBoolArg("-disablesafemode") &&
3180 throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
3187 LOCK2(cs_main, pwalletMain->cs_wallet);
3188 result = pcmd->actor(params, false);
3192 string strReply = JSONRPCReply(result, Value::null, id);
3193 stream << HTTPReply(200, strReply) << std::flush;
3195 catch (std::exception& e)
3197 ErrorReply(stream, JSONRPCError(-1, e.what()), id);
3200 catch (Object& objError)
3202 ErrorReply(stream, objError, id);
3204 catch (std::exception& e)
3206 ErrorReply(stream, JSONRPCError(-32700, e.what()), id);
3214 Object CallRPC(const string& strMethod, const Array& params)
3216 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
3217 throw runtime_error(strprintf(
3218 _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
3219 "If the file does not exist, create it with owner-readable-only file permissions."),
3220 GetConfigFile().string().c_str()));
3222 // Connect to localhost
3223 bool fUseSSL = GetBoolArg("-rpcssl");
3224 asio::io_service io_service;
3225 ssl::context context(io_service, ssl::context::sslv23);
3226 context.set_options(ssl::context::no_sslv2);
3227 SSLStream sslStream(io_service, context);
3228 SSLIOStreamDevice d(sslStream, fUseSSL);
3229 iostreams::stream<SSLIOStreamDevice> stream(d);
3230 if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", CBigNum(RPC_PORT).ToString().c_str())))
3231 throw runtime_error("couldn't connect to server");
3233 // HTTP basic authentication
3234 string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
3235 map<string, string> mapRequestHeaders;
3236 mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
3239 string strRequest = JSONRPCRequest(strMethod, params, 1);
3240 string strPost = HTTPPost(strRequest, mapRequestHeaders);
3241 stream << strPost << std::flush;
3244 map<string, string> mapHeaders;
3246 int nStatus = ReadHTTP(stream, mapHeaders, strReply);
3248 throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
3249 else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
3250 throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
3251 else if (strReply.empty())
3252 throw runtime_error("no response from server");
3256 if (!read_string(strReply, valReply))
3257 throw runtime_error("couldn't parse reply from server");
3258 const Object& reply = valReply.get_obj();
3260 throw runtime_error("expected reply to have result, error and id properties");
3268 template<typename T>
3269 void ConvertTo(Value& value)
3271 if (value.type() == str_type)
3273 // reinterpret string as unquoted json value
3275 if (!read_string(value.get_str(), value2))
3276 throw runtime_error("type mismatch");
3277 value = value2.get_value<T>();
3281 value = value.get_value<T>();
3285 int CommandLineRPC(int argc, char *argv[])
3292 while (argc > 1 && IsSwitchChar(argv[1][0]))
3300 throw runtime_error("too few parameters");
3301 string strMethod = argv[1];
3303 // Parameters default to strings
3305 for (int i = 2; i < argc; i++)
3306 params.push_back(argv[i]);
3307 int n = params.size();
3310 // Special case non-string parameter types
3312 if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
3313 if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
3314 if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
3315 if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]);
3316 if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
3317 if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]);
3318 if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
3319 if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
3320 if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]);
3321 if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
3322 if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]);
3323 if (strMethod == "getblockhash" && n > 0) ConvertTo<boost::int64_t>(params[0]);
3324 if (strMethod == "getblockbynumber" && n > 0) ConvertTo<boost::int64_t>(params[0]);
3325 if (strMethod == "getblockbynumber" && n > 1) ConvertTo<bool>(params[1]);
3326 if (strMethod == "getblock" && n > 1) ConvertTo<bool>(params[1]);
3327 if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]);
3328 if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]);
3329 if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]);
3330 if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]);
3331 if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
3332 if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]);
3333 if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]);
3334 if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]);
3335 if (strMethod == "walletpassphrase" && n > 2) ConvertTo<bool>(params[2]);
3336 if (strMethod == "listsinceblock" && n > 1) ConvertTo<boost::int64_t>(params[1]);
3337 if (strMethod == "sendalert" && n > 2) ConvertTo<boost::int64_t>(params[2]);
3338 if (strMethod == "sendalert" && n > 3) ConvertTo<boost::int64_t>(params[3]);
3339 if (strMethod == "sendalert" && n > 4) ConvertTo<boost::int64_t>(params[4]);
3340 if (strMethod == "sendalert" && n > 5) ConvertTo<boost::int64_t>(params[5]);
3341 if (strMethod == "sendalert" && n > 6) ConvertTo<boost::int64_t>(params[6]);
3342 if (strMethod == "sendmany" && n > 1)
3344 string s = params[1].get_str();
3346 if (!read_string(s, v) || v.type() != obj_type)
3347 throw runtime_error("type mismatch");
3348 params[1] = v.get_obj();
3350 if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]);
3351 if (strMethod == "reservebalance" && n > 0) ConvertTo<bool>(params[0]);
3352 if (strMethod == "reservebalance" && n > 1) ConvertTo<double>(params[1]);
3353 if (strMethod == "addmultisigaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
3354 if (strMethod == "addmultisigaddress" && n > 1)
3356 string s = params[1].get_str();
3358 if (!read_string(s, v) || v.type() != array_type)
3359 throw runtime_error("type mismatch "+s);
3360 params[1] = v.get_array();
3364 Object reply = CallRPC(strMethod, params);
3367 const Value& result = find_value(reply, "result");
3368 const Value& error = find_value(reply, "error");
3370 if (error.type() != null_type)
3373 strPrint = "error: " + write_string(error, false);
3374 int code = find_value(error.get_obj(), "code").get_int();
3380 if (result.type() == null_type)
3382 else if (result.type() == str_type)
3383 strPrint = result.get_str();
3385 strPrint = write_string(result, true);
3388 catch (std::exception& e)
3390 strPrint = string("error: ") + e.what();
3395 PrintException(NULL, "CommandLineRPC()");
3400 fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
3409 int main(int argc, char *argv[])
3412 // Turn off microsoft heap dump noise
3413 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
3414 _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
3416 setbuf(stdin, NULL);
3417 setbuf(stdout, NULL);
3418 setbuf(stderr, NULL);
3422 if (argc >= 2 && string(argv[1]) == "-server")
3424 printf("server ready\n");
3425 ThreadRPCServer(NULL);
3429 return CommandLineRPC(argc, argv);
3432 catch (std::exception& e) {
3433 PrintException(&e, "main()");
3435 PrintException(NULL, "main()");
3441 const CRPCTable tableRPC;