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", (boost::int64_t)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("time", (boost::int64_t)pindex->nTime));
1629 entry.push_back(Pair("confirmations", 0));
1634 throw JSONRPCError(-5, "No information available about transaction");
1641 Value backupwallet(const Array& params, bool fHelp)
1643 if (fHelp || params.size() != 1)
1644 throw runtime_error(
1645 "backupwallet <destination>\n"
1646 "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1648 string strDest = params[0].get_str();
1649 BackupWallet(*pwalletMain, strDest);
1655 Value keypoolrefill(const Array& params, bool fHelp)
1657 if (pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1658 throw runtime_error(
1660 "Fills the keypool, requires wallet passphrase to be set.");
1661 if (!pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1662 throw runtime_error(
1664 "Fills the keypool.");
1666 if (pwalletMain->IsLocked())
1667 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
1669 pwalletMain->TopUpKeyPool();
1671 if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100))
1672 throw JSONRPCError(-4, "Error refreshing keypool.");
1678 void ThreadTopUpKeyPool(void* parg)
1680 pwalletMain->TopUpKeyPool();
1683 void ThreadCleanWalletPassphrase(void* parg)
1685 int64 nMyWakeTime = GetTimeMillis() + *((int64*)parg) * 1000;
1687 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1689 if (nWalletUnlockTime == 0)
1691 nWalletUnlockTime = nMyWakeTime;
1695 if (nWalletUnlockTime==0)
1697 int64 nToSleep = nWalletUnlockTime - GetTimeMillis();
1701 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1703 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1707 if (nWalletUnlockTime)
1709 nWalletUnlockTime = 0;
1710 pwalletMain->Lock();
1715 if (nWalletUnlockTime < nMyWakeTime)
1716 nWalletUnlockTime = nMyWakeTime;
1719 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1721 delete (int64*)parg;
1724 Value walletpassphrase(const Array& params, bool fHelp)
1726 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 3))
1727 throw runtime_error(
1728 "walletpassphrase <passphrase> <timeout> [mintonly]\n"
1729 "Stores the wallet decryption key in memory for <timeout> seconds.\n"
1730 "mintonly is optional true/false allowing only block minting.");
1733 if (!pwalletMain->IsCrypted())
1734 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1736 if (!pwalletMain->IsLocked())
1737 throw JSONRPCError(-17, "Error: Wallet is already unlocked, use walletlock first if need to change unlock settings.");
1739 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1740 SecureString strWalletPass;
1741 strWalletPass.reserve(100);
1742 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1743 // Alternately, find a way to make params[0] mlock()'d to begin with.
1744 strWalletPass = params[0].get_str().c_str();
1746 if (strWalletPass.length() > 0)
1748 if (!pwalletMain->Unlock(strWalletPass))
1749 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1752 throw runtime_error(
1753 "walletpassphrase <passphrase> <timeout>\n"
1754 "Stores the wallet decryption key in memory for <timeout> seconds.");
1756 CreateThread(ThreadTopUpKeyPool, NULL);
1757 int64* pnSleepTime = new int64(params[1].get_int64());
1758 CreateThread(ThreadCleanWalletPassphrase, pnSleepTime);
1760 // ppcoin: if user OS account compromised prevent trivial sendmoney commands
1761 if (params.size() > 2)
1762 fWalletUnlockMintOnly = params[2].get_bool();
1764 fWalletUnlockMintOnly = false;
1770 Value walletpassphrasechange(const Array& params, bool fHelp)
1772 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1773 throw runtime_error(
1774 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1775 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1778 if (!pwalletMain->IsCrypted())
1779 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1781 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1782 // Alternately, find a way to make params[0] mlock()'d to begin with.
1783 SecureString strOldWalletPass;
1784 strOldWalletPass.reserve(100);
1785 strOldWalletPass = params[0].get_str().c_str();
1787 SecureString strNewWalletPass;
1788 strNewWalletPass.reserve(100);
1789 strNewWalletPass = params[1].get_str().c_str();
1791 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1792 throw runtime_error(
1793 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1794 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1796 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1797 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1803 Value walletlock(const Array& params, bool fHelp)
1805 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1806 throw runtime_error(
1808 "Removes the wallet encryption key from memory, locking the wallet.\n"
1809 "After calling this method, you will need to call walletpassphrase again\n"
1810 "before being able to call any methods which require the wallet to be unlocked.");
1813 if (!pwalletMain->IsCrypted())
1814 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called.");
1817 LOCK(cs_nWalletUnlockTime);
1818 pwalletMain->Lock();
1819 nWalletUnlockTime = 0;
1826 Value encryptwallet(const Array& params, bool fHelp)
1828 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1829 throw runtime_error(
1830 "encryptwallet <passphrase>\n"
1831 "Encrypts the wallet with <passphrase>.");
1834 if (pwalletMain->IsCrypted())
1835 throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
1837 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1838 // Alternately, find a way to make params[0] mlock()'d to begin with.
1839 SecureString strWalletPass;
1840 strWalletPass.reserve(100);
1841 strWalletPass = params[0].get_str().c_str();
1843 if (strWalletPass.length() < 1)
1844 throw runtime_error(
1845 "encryptwallet <passphrase>\n"
1846 "Encrypts the wallet with <passphrase>.");
1848 if (!pwalletMain->EncryptWallet(strWalletPass))
1849 throw JSONRPCError(-16, "Error: Failed to encrypt the wallet.");
1851 // BDB seems to have a bad habit of writing old data into
1852 // slack space in .dat files; that is bad if the old data is
1853 // unencrypted private keys. So:
1855 return "wallet encrypted; novacoin server stopping, restart to run with encrypted wallet";
1859 Value validateaddress(const Array& params, bool fHelp)
1861 if (fHelp || params.size() != 1)
1862 throw runtime_error(
1863 "validateaddress <novacoinaddress>\n"
1864 "Return information about <novacoinaddress>.");
1866 CBitcoinAddress address(params[0].get_str());
1867 bool isValid = address.IsValid();
1870 ret.push_back(Pair("isvalid", isValid));
1873 // Call Hash160ToAddress() so we always return current ADDRESSVERSION
1874 // version of the address:
1875 string currentAddress = address.ToString();
1876 ret.push_back(Pair("address", currentAddress));
1877 if (pwalletMain->HaveKey(address))
1879 ret.push_back(Pair("ismine", true));
1880 std::vector<unsigned char> vchPubKey;
1881 pwalletMain->GetPubKey(address, vchPubKey);
1882 ret.push_back(Pair("pubkey", HexStr(vchPubKey)));
1884 key.SetPubKey(vchPubKey);
1885 ret.push_back(Pair("iscompressed", key.IsCompressed()));
1887 else if (pwalletMain->HaveCScript(address.GetHash160()))
1889 ret.push_back(Pair("isscript", true));
1891 pwalletMain->GetCScript(address.GetHash160(), subscript);
1892 ret.push_back(Pair("ismine", ::IsMine(*pwalletMain, subscript)));
1893 std::vector<CBitcoinAddress> addresses;
1894 txnouttype whichType;
1896 ExtractAddresses(subscript, whichType, addresses, nRequired);
1897 ret.push_back(Pair("script", GetTxnOutputType(whichType)));
1899 BOOST_FOREACH(const CBitcoinAddress& addr, addresses)
1900 a.push_back(addr.ToString());
1901 ret.push_back(Pair("addresses", a));
1902 if (whichType == TX_MULTISIG)
1903 ret.push_back(Pair("sigsrequired", nRequired));
1906 ret.push_back(Pair("ismine", false));
1907 if (pwalletMain->mapAddressBook.count(address))
1908 ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
1913 Value validatepubkey(const Array& params, bool fHelp)
1915 if (fHelp || !params.size() || params.size() > 2)
1916 throw runtime_error(
1917 "validatepubkey <novacoinpubkey>\n"
1918 "Return information about <novacoinpubkey>.");
1920 std::vector<unsigned char> vchPubKey = ParseHex(params[0].get_str());
1923 if(vchPubKey.size() == 33) // Compressed key
1924 isValid = (vchPubKey[0] == 0x02 || vchPubKey[0] == 0x03);
1925 else if(vchPubKey.size() == 65) // Uncompressed key
1926 isValid = vchPubKey[0] == 0x04;
1930 CBitcoinAddress address(vchPubKey);
1931 isValid = isValid ? address.IsValid() : false;
1934 ret.push_back(Pair("isvalid", isValid));
1937 // Call Hash160ToAddress() so we always return current ADDRESSVERSION
1938 // version of the address:
1939 string currentAddress = address.ToString();
1940 ret.push_back(Pair("address", currentAddress));
1941 if (pwalletMain->HaveKey(address))
1943 ret.push_back(Pair("ismine", true));
1945 key.SetPubKey(vchPubKey);
1946 ret.push_back(Pair("iscompressed", key.IsCompressed()));
1949 ret.push_back(Pair("ismine", false));
1950 if (pwalletMain->mapAddressBook.count(address))
1951 ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
1956 Value getworkex(const Array& params, bool fHelp)
1958 if (fHelp || params.size() > 2)
1959 throw runtime_error(
1960 "getworkex [data, coinbase]\n"
1961 "If [data, coinbase] is not specified, returns extended work data.\n"
1965 throw JSONRPCError(-9, "NovaCoin is not connected!");
1967 if (IsInitialBlockDownload())
1968 throw JSONRPCError(-10, "NovaCoin is downloading blocks...");
1970 typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
1971 static mapNewBlock_t mapNewBlock;
1972 static vector<CBlock*> vNewBlock;
1973 static CReserveKey reservekey(pwalletMain);
1975 if (params.size() == 0)
1978 static unsigned int nTransactionsUpdatedLast;
1979 static CBlockIndex* pindexPrev;
1980 static int64 nStart;
1981 static CBlock* pblock;
1982 if (pindexPrev != pindexBest ||
1983 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
1985 if (pindexPrev != pindexBest)
1987 // Deallocate old blocks since they're obsolete now
1988 mapNewBlock.clear();
1989 BOOST_FOREACH(CBlock* pblock, vNewBlock)
1993 nTransactionsUpdatedLast = nTransactionsUpdated;
1994 pindexPrev = pindexBest;
1998 pblock = CreateNewBlock(pwalletMain);
2000 throw JSONRPCError(-7, "Out of memory");
2001 vNewBlock.push_back(pblock);
2005 pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
2008 // Update nExtraNonce
2009 static unsigned int nExtraNonce = 0;
2010 IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
2013 mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
2015 // Prebuild hash buffers
2019 FormatHashBuffers(pblock, pmidstate, pdata, phash1);
2021 uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
2023 CTransaction coinbaseTx = pblock->vtx[0];
2024 std::vector<uint256> merkle = pblock->GetMerkleBranch(0);
2027 result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata))));
2028 result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
2030 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
2032 result.push_back(Pair("coinbase", HexStr(ssTx.begin(), ssTx.end())));
2035 printf("DEBUG: merkle size %i\n", merkle.size());
2037 BOOST_FOREACH(uint256 merkleh, merkle) {
2038 printf("%s\n", merkleh.ToString().c_str());
2039 merkle_arr.push_back(HexStr(BEGIN(merkleh), END(merkleh)));
2042 result.push_back(Pair("merkle", merkle_arr));
2050 vector<unsigned char> vchData = ParseHex(params[0].get_str());
2051 vector<unsigned char> coinbase;
2053 if(params.size() == 2)
2054 coinbase = ParseHex(params[1].get_str());
2056 if (vchData.size() != 128)
2057 throw JSONRPCError(-8, "Invalid parameter");
2059 CBlock* pdata = (CBlock*)&vchData[0];
2062 for (int i = 0; i < 128/4; i++)
2063 ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]);
2066 if (!mapNewBlock.count(pdata->hashMerkleRoot))
2068 CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
2070 pblock->nTime = pdata->nTime;
2071 pblock->nNonce = pdata->nNonce;
2073 if(coinbase.size() == 0)
2074 pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
2076 CDataStream(coinbase, SER_NETWORK, PROTOCOL_VERSION) >> pblock->vtx[0]; // FIXME - HACK!
2078 pblock->hashMerkleRoot = pblock->BuildMerkleTree();
2080 if (!pblock->SignBlock(*pwalletMain))
2081 throw JSONRPCError(-100, "Unable to sign block, wallet locked?");
2083 return CheckWork(pblock, *pwalletMain, reservekey);
2088 Value getwork(const Array& params, bool fHelp)
2090 if (fHelp || params.size() > 1)
2091 throw runtime_error(
2093 "If [data] is not specified, returns formatted hash data to work on:\n"
2094 " \"midstate\" : precomputed hash state after hashing the first half of the data (DEPRECATED)\n" // deprecated
2095 " \"data\" : block data\n"
2096 " \"hash1\" : formatted hash buffer for second hash (DEPRECATED)\n" // deprecated
2097 " \"target\" : little endian hash target\n"
2098 "If [data] is specified, tries to solve the block and returns true if it was successful.");
2101 throw JSONRPCError(-9, "NovaCoin is not connected!");
2103 if (IsInitialBlockDownload())
2104 throw JSONRPCError(-10, "NovaCoin is downloading blocks...");
2106 typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
2107 static mapNewBlock_t mapNewBlock;
2108 static vector<CBlock*> vNewBlock;
2109 static CReserveKey reservekey(pwalletMain);
2111 if (params.size() == 0)
2114 static unsigned int nTransactionsUpdatedLast;
2115 static CBlockIndex* pindexPrev;
2116 static int64 nStart;
2117 static CBlock* pblock;
2118 if (pindexPrev != pindexBest ||
2119 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
2121 if (pindexPrev != pindexBest)
2123 // Deallocate old blocks since they're obsolete now
2124 mapNewBlock.clear();
2125 BOOST_FOREACH(CBlock* pblock, vNewBlock)
2129 nTransactionsUpdatedLast = nTransactionsUpdated;
2130 pindexPrev = pindexBest;
2134 pblock = CreateNewBlock(pwalletMain);
2136 throw JSONRPCError(-7, "Out of memory");
2137 vNewBlock.push_back(pblock);
2141 pblock->UpdateTime(pindexPrev);
2144 // Update nExtraNonce
2145 static unsigned int nExtraNonce = 0;
2146 IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
2149 mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
2151 // Prebuild hash buffers
2155 FormatHashBuffers(pblock, pmidstate, pdata, phash1);
2157 uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
2160 result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate)))); // deprecated
2161 result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata))));
2162 result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1)))); // deprecated
2163 result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
2169 vector<unsigned char> vchData = ParseHex(params[0].get_str());
2170 if (vchData.size() != 128)
2171 throw JSONRPCError(-8, "Invalid parameter");
2172 CBlock* pdata = (CBlock*)&vchData[0];
2175 for (int i = 0; i < 128/4; i++)
2176 ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]);
2179 if (!mapNewBlock.count(pdata->hashMerkleRoot))
2181 CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
2183 pblock->nTime = pdata->nTime;
2184 pblock->nNonce = pdata->nNonce;
2185 pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
2186 pblock->hashMerkleRoot = pblock->BuildMerkleTree();
2187 if (!pblock->SignBlock(*pwalletMain))
2188 throw JSONRPCError(-100, "Unable to sign block, wallet locked?");
2190 return CheckWork(pblock, *pwalletMain, reservekey);
2194 Value getblocktemplate(const Array& params, bool fHelp)
2196 if (fHelp || params.size() > 1)
2197 throw runtime_error(
2198 "getblocktemplate [params]\n"
2199 "Returns data needed to construct a block to work on:\n"
2200 " \"version\" : block version\n"
2201 " \"previousblockhash\" : hash of current highest block\n"
2202 " \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
2203 " \"coinbaseaux\" : data that should be included in coinbase\n"
2204 " \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
2205 " \"target\" : hash target\n"
2206 " \"mintime\" : minimum timestamp appropriate for next block\n"
2207 " \"curtime\" : current timestamp\n"
2208 " \"mutable\" : list of ways the block template may be changed\n"
2209 " \"noncerange\" : range of valid nonces\n"
2210 " \"sigoplimit\" : limit of sigops in blocks\n"
2211 " \"sizelimit\" : limit of block size\n"
2212 " \"bits\" : compressed target of next block\n"
2213 " \"height\" : height of the next block\n"
2214 "See https://en.bitcoin.it/wiki/BIP_0022 for full specification.");
2216 std::string strMode = "template";
2217 if (params.size() > 0)
2219 const Object& oparam = params[0].get_obj();
2220 const Value& modeval = find_value(oparam, "mode");
2221 if (modeval.type() == str_type)
2222 strMode = modeval.get_str();
2224 throw JSONRPCError(-8, "Invalid mode");
2227 if (strMode != "template")
2228 throw JSONRPCError(-8, "Invalid mode");
2231 throw JSONRPCError(-9, "NovaCoin is not connected!");
2233 if (IsInitialBlockDownload())
2234 throw JSONRPCError(-10, "NovaCoin is downloading blocks...");
2236 static CReserveKey reservekey(pwalletMain);
2239 static unsigned int nTransactionsUpdatedLast;
2240 static CBlockIndex* pindexPrev;
2241 static int64 nStart;
2242 static CBlock* pblock;
2243 if (pindexPrev != pindexBest ||
2244 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5))
2246 // Clear pindexPrev so future calls make a new block, despite any failures from here on
2249 // Store the pindexBest used before CreateNewBlock, to avoid races
2250 nTransactionsUpdatedLast = nTransactionsUpdated;
2251 CBlockIndex* pindexPrevNew = pindexBest;
2260 pblock = CreateNewBlock(pwalletMain);
2262 throw JSONRPCError(-7, "Out of memory");
2264 // Need to update only after we know CreateNewBlock succeeded
2265 pindexPrev = pindexPrevNew;
2269 pblock->UpdateTime(pindexPrev);
2273 map<uint256, int64_t> setTxIndex;
2276 BOOST_FOREACH (CTransaction& tx, pblock->vtx)
2278 uint256 txHash = tx.GetHash();
2279 setTxIndex[txHash] = i++;
2281 if (tx.IsCoinBase() || tx.IsCoinStake())
2286 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
2288 entry.push_back(Pair("data", HexStr(ssTx.begin(), ssTx.end())));
2290 entry.push_back(Pair("hash", txHash.GetHex()));
2292 MapPrevTx mapInputs;
2293 map<uint256, CTxIndex> mapUnused;
2294 bool fInvalid = false;
2295 if (tx.FetchInputs(txdb, mapUnused, false, false, mapInputs, fInvalid))
2297 entry.push_back(Pair("fee", (int64_t)(tx.GetValueIn(mapInputs) - tx.GetValueOut())));
2300 BOOST_FOREACH (MapPrevTx::value_type& inp, mapInputs)
2302 if (setTxIndex.count(inp.first))
2303 deps.push_back(setTxIndex[inp.first]);
2305 entry.push_back(Pair("depends", deps));
2307 int64_t nSigOps = tx.GetLegacySigOpCount();
2308 nSigOps += tx.GetP2SHSigOpCount(mapInputs);
2309 entry.push_back(Pair("sigops", nSigOps));
2312 transactions.push_back(entry);
2316 aux.push_back(Pair("flags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end())));
2318 uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
2320 static Array aMutable;
2321 if (aMutable.empty())
2323 aMutable.push_back("time");
2324 aMutable.push_back("transactions");
2325 aMutable.push_back("prevblock");
2329 result.push_back(Pair("version", pblock->nVersion));
2330 result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
2331 result.push_back(Pair("transactions", transactions));
2332 result.push_back(Pair("coinbaseaux", aux));
2333 result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
2334 result.push_back(Pair("target", hashTarget.GetHex()));
2335 result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1));
2336 result.push_back(Pair("mutable", aMutable));
2337 result.push_back(Pair("noncerange", "00000000ffffffff"));
2338 result.push_back(Pair("sigoplimit", (int64_t)MAX_BLOCK_SIGOPS));
2339 result.push_back(Pair("sizelimit", (int64_t)MAX_BLOCK_SIZE));
2340 result.push_back(Pair("curtime", (int64_t)pblock->nTime));
2341 result.push_back(Pair("bits", HexBits(pblock->nBits)));
2342 result.push_back(Pair("height", (int64_t)(pindexPrev->nHeight+1)));
2347 Value submitblock(const Array& params, bool fHelp)
2349 if (fHelp || params.size() < 1 || params.size() > 2)
2350 throw runtime_error(
2351 "submitblock <hex data> [optional-params-obj]\n"
2352 "[optional-params-obj] parameter is currently ignored.\n"
2353 "Attempts to submit new block to network.\n"
2354 "See https://en.bitcoin.it/wiki/BIP_0022 for full specification.");
2356 vector<unsigned char> blockData(ParseHex(params[0].get_str()));
2357 CDataStream ssBlock(blockData, SER_NETWORK, PROTOCOL_VERSION);
2362 catch (std::exception &e) {
2363 throw JSONRPCError(-22, "Block decode failed");
2366 static CReserveKey reservekey(pwalletMain);
2368 if(!block.SignBlock(*pwalletMain))
2369 throw JSONRPCError(-100, "Unable to sign block, wallet locked?");
2371 bool fAccepted = CheckWork(&block, *pwalletMain, reservekey);
2379 Value getmemorypool(const Array& params, bool fHelp)
2381 if (fHelp || params.size() > 1)
2382 throw runtime_error(
2383 "getmemorypool [data]\n"
2384 "If [data] is not specified, returns data needed to construct a block to work on:\n"
2385 " \"version\" : block version\n"
2386 " \"previousblockhash\" : hash of current highest block\n"
2387 " \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
2388 " \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
2389 " \"coinbaseflags\" : data that should be included in coinbase so support for new features can be judged\n"
2390 " \"time\" : timestamp appropriate for next block\n"
2391 " \"mintime\" : minimum timestamp appropriate for next block\n"
2392 " \"curtime\" : current timestamp\n"
2393 " \"bits\" : compressed target of next block\n"
2394 "If [data] is specified, tries to solve the block and returns true if it was successful.");
2396 if (params.size() == 0)
2399 throw JSONRPCError(-9, "NovaCoin is not connected!");
2401 if (IsInitialBlockDownload())
2402 throw JSONRPCError(-10, "NovaCoin is downloading blocks...");
2404 static CReserveKey reservekey(pwalletMain);
2407 static unsigned int nTransactionsUpdatedLast;
2408 static CBlockIndex* pindexPrev;
2409 static int64 nStart;
2410 static CBlock* pblock;
2411 if (pindexPrev != pindexBest ||
2412 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5))
2414 nTransactionsUpdatedLast = nTransactionsUpdated;
2415 pindexPrev = pindexBest;
2421 pblock = CreateNewBlock(pwalletMain);
2423 throw JSONRPCError(-7, "Out of memory");
2427 pblock->UpdateTime(pindexPrev);
2431 BOOST_FOREACH(CTransaction tx, pblock->vtx) {
2432 if(tx.IsCoinBase() || tx.IsCoinStake())
2435 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
2438 transactions.push_back(HexStr(ssTx.begin(), ssTx.end()));
2442 result.push_back(Pair("version", pblock->nVersion));
2443 result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
2444 result.push_back(Pair("transactions", transactions));
2445 result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
2446 result.push_back(Pair("coinbaseflags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end())));
2447 result.push_back(Pair("time", (int64_t)pblock->nTime));
2448 result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1));
2449 result.push_back(Pair("curtime", (int64_t)GetAdjustedTime()));
2450 result.push_back(Pair("bits", HexBits(pblock->nBits)));
2457 CDataStream ssBlock(ParseHex(params[0].get_str()), SER_NETWORK, PROTOCOL_VERSION);
2461 static CReserveKey reservekey(pwalletMain);
2463 if(!pblock.SignBlock(*pwalletMain))
2464 throw JSONRPCError(-100, "Unable to sign block, wallet locked?");
2466 return CheckWork(&pblock, *pwalletMain, reservekey);
2470 Value getnewpubkey(const Array& params, bool fHelp)
2472 if (fHelp || params.size() > 1)
2473 throw runtime_error(
2474 "getnewpubkey [account]\n"
2475 "Returns new public key for coinbase generation.");
2477 // Parse the account first so we don't generate a key if there's an error
2479 if (params.size() > 0)
2480 strAccount = AccountFromValue(params[0]);
2482 if (!pwalletMain->IsLocked())
2483 pwalletMain->TopUpKeyPool();
2485 // Generate a new key that is added to wallet
2486 std::vector<unsigned char> newKey = pwalletMain->GenerateNewKey(false);
2489 throw JSONRPCError(-12, "Error: Unable to create key");
2491 CBitcoinAddress address(newKey);
2492 pwalletMain->SetAddressBookName(address, strAccount);
2494 return HexStr(newKey.begin(), newKey.end());
2497 Value getblockhash(const Array& params, bool fHelp)
2499 if (fHelp || params.size() != 1)
2500 throw runtime_error(
2501 "getblockhash <index>\n"
2502 "Returns hash of block in best-block-chain at <index>.");
2504 int nHeight = params[0].get_int();
2505 if (nHeight < 0 || nHeight > nBestHeight)
2506 throw runtime_error("Block number out of range.");
2509 CBlockIndex* pblockindex = mapBlockIndex[hashBestChain];
2510 while (pblockindex->nHeight > nHeight)
2511 pblockindex = pblockindex->pprev;
2512 return pblockindex->phashBlock->GetHex();
2515 Value getblock(const Array& params, bool fHelp)
2517 if (fHelp || params.size() < 1 || params.size() > 2)
2518 throw runtime_error(
2519 "getblock <hash> [txinfo]\n"
2520 "txinfo optional to print more detailed tx info\n"
2521 "Returns details of a block with given block-hash.");
2523 std::string strHash = params[0].get_str();
2524 uint256 hash(strHash);
2526 if (mapBlockIndex.count(hash) == 0)
2527 throw JSONRPCError(-5, "Block not found");
2530 CBlockIndex* pblockindex = mapBlockIndex[hash];
2531 block.ReadFromDisk(pblockindex, true);
2533 return blockToJSON(block, pblockindex, params.size() > 1 ? params[1].get_bool() : false);
2536 Value getblockbynumber(const Array& params, bool fHelp)
2538 if (fHelp || params.size() < 1 || params.size() > 2)
2539 throw runtime_error(
2540 "getblock <number> [txinfo]\n"
2541 "txinfo optional to print more detailed tx info\n"
2542 "Returns details of a block with given block-number.");
2544 int nHeight = params[0].get_int();
2545 if (nHeight < 0 || nHeight > nBestHeight)
2546 throw runtime_error("Block number out of range.");
2549 CBlockIndex* pblockindex = mapBlockIndex[hashBestChain];
2550 while (pblockindex->nHeight > nHeight)
2551 pblockindex = pblockindex->pprev;
2553 uint256 hash = *pblockindex->phashBlock;
2555 pblockindex = mapBlockIndex[hash];
2556 block.ReadFromDisk(pblockindex, true);
2558 return blockToJSON(block, pblockindex, params.size() > 1 ? params[1].get_bool() : false);
2561 // ppcoin: get information of sync-checkpoint
2562 Value getcheckpoint(const Array& params, bool fHelp)
2564 if (fHelp || params.size() != 0)
2565 throw runtime_error(
2567 "Show info of synchronized checkpoint.\n");
2570 CBlockIndex* pindexCheckpoint;
2572 result.push_back(Pair("synccheckpoint", Checkpoints::hashSyncCheckpoint.ToString().c_str()));
2573 pindexCheckpoint = mapBlockIndex[Checkpoints::hashSyncCheckpoint];
2574 result.push_back(Pair("height", pindexCheckpoint->nHeight));
2575 result.push_back(Pair("timestamp", DateTimeStrFormat(pindexCheckpoint->GetBlockTime()).c_str()));
2576 if (mapArgs.count("-checkpointkey"))
2577 result.push_back(Pair("checkpointmaster", true));
2583 // ppcoin: reserve balance from being staked for network protection
2584 Value reservebalance(const Array& params, bool fHelp)
2586 if (fHelp || params.size() > 2)
2587 throw runtime_error(
2588 "reservebalance [<reserve> [amount]]\n"
2589 "<reserve> is true or false to turn balance reserve on or off.\n"
2590 "<amount> is a real and rounded to cent.\n"
2591 "Set reserve amount not participating in network protection.\n"
2592 "If no parameters provided current setting is printed.\n");
2594 if (params.size() > 0)
2596 bool fReserve = params[0].get_bool();
2599 if (params.size() == 1)
2600 throw runtime_error("must provide amount to reserve balance.\n");
2601 int64 nAmount = AmountFromValue(params[1]);
2602 nAmount = (nAmount / CENT) * CENT; // round to cent
2604 throw runtime_error("amount cannot be negative.\n");
2605 mapArgs["-reservebalance"] = FormatMoney(nAmount).c_str();
2609 if (params.size() > 1)
2610 throw runtime_error("cannot specify amount to turn off reserve.\n");
2611 mapArgs["-reservebalance"] = "0";
2616 int64 nReserveBalance = 0;
2617 if (mapArgs.count("-reservebalance") && !ParseMoney(mapArgs["-reservebalance"], nReserveBalance))
2618 throw runtime_error("invalid reserve balance amount\n");
2619 result.push_back(Pair("reserve", (nReserveBalance > 0)));
2620 result.push_back(Pair("amount", ValueFromAmount(nReserveBalance)));
2625 // ppcoin: check wallet integrity
2626 Value checkwallet(const Array& params, bool fHelp)
2628 if (fHelp || params.size() > 0)
2629 throw runtime_error(
2631 "Check wallet for integrity.\n");
2634 int64 nBalanceInQuestion;
2635 pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion, true);
2637 if (nMismatchSpent == 0)
2638 result.push_back(Pair("wallet check passed", true));
2641 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
2642 result.push_back(Pair("amount in question", ValueFromAmount(nBalanceInQuestion)));
2648 // ppcoin: repair wallet
2649 Value repairwallet(const Array& params, bool fHelp)
2651 if (fHelp || params.size() > 0)
2652 throw runtime_error(
2654 "Repair wallet if checkwallet reports any problem.\n");
2657 int64 nBalanceInQuestion;
2658 pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion);
2660 if (nMismatchSpent == 0)
2661 result.push_back(Pair("wallet check passed", true));
2664 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
2665 result.push_back(Pair("amount affected by repair", ValueFromAmount(nBalanceInQuestion)));
2670 // NovaCoin: resend unconfirmed wallet transactions
2671 Value resendtx(const Array& params, bool fHelp)
2673 if (fHelp || params.size() > 1)
2674 throw runtime_error(
2676 "Re-send unconfirmed transactions.\n"
2679 ResendWalletTransactions();
2685 // ppcoin: make a public-private key pair
2686 Value makekeypair(const Array& params, bool fHelp)
2688 if (fHelp || params.size() > 1)
2689 throw runtime_error(
2690 "makekeypair [prefix]\n"
2691 "Make a public/private key pair.\n"
2692 "[prefix] is optional preferred prefix for the public key.\n");
2694 string strPrefix = "";
2695 if (params.size() > 0)
2696 strPrefix = params[0].get_str();
2702 key.MakeNewKey(false);
2704 } while (nCount < 10000 && strPrefix != HexStr(key.GetPubKey()).substr(0, strPrefix.size()));
2706 if (strPrefix != HexStr(key.GetPubKey()).substr(0, strPrefix.size()))
2709 CPrivKey vchPrivKey = key.GetPrivKey();
2711 result.push_back(Pair("PrivateKey", HexStr<CPrivKey::iterator>(vchPrivKey.begin(), vchPrivKey.end())));
2712 result.push_back(Pair("PublicKey", HexStr(key.GetPubKey())));
2716 extern CCriticalSection cs_mapAlerts;
2717 extern map<uint256, CAlert> mapAlerts;
2719 // ppcoin: send alert.
2720 // There is a known deadlock situation with ThreadMessageHandler
2721 // ThreadMessageHandler: holds cs_vSend and acquiring cs_main in SendMessages()
2722 // ThreadRPCServer: holds cs_main and acquiring cs_vSend in alert.RelayTo()/PushMessage()/BeginMessage()
2723 Value sendalert(const Array& params, bool fHelp)
2725 if (fHelp || params.size() < 6)
2726 throw runtime_error(
2727 "sendalert <message> <privatekey> <minver> <maxver> <priority> <id> [cancelupto]\n"
2728 "<message> is the alert text message\n"
2729 "<privatekey> is hex string of alert master private key\n"
2730 "<minver> is the minimum applicable internal client version\n"
2731 "<maxver> is the maximum applicable internal client version\n"
2732 "<priority> is integer priority number\n"
2733 "<id> is the alert id\n"
2734 "[cancelupto] cancels all alert id's up to this number\n"
2735 "Returns true or false.");
2740 alert.strStatusBar = params[0].get_str();
2741 alert.nMinVer = params[2].get_int();
2742 alert.nMaxVer = params[3].get_int();
2743 alert.nPriority = params[4].get_int();
2744 alert.nID = params[5].get_int();
2745 if (params.size() > 6)
2746 alert.nCancel = params[6].get_int();
2747 alert.nVersion = PROTOCOL_VERSION;
2748 alert.nRelayUntil = GetAdjustedTime() + 365*24*60*60;
2749 alert.nExpiration = GetAdjustedTime() + 365*24*60*60;
2751 CDataStream sMsg(SER_NETWORK, PROTOCOL_VERSION);
2752 sMsg << (CUnsignedAlert)alert;
2753 alert.vchMsg = vector<unsigned char>(sMsg.begin(), sMsg.end());
2755 vector<unsigned char> vchPrivKey = ParseHex(params[1].get_str());
2756 key.SetPrivKey(CPrivKey(vchPrivKey.begin(), vchPrivKey.end())); // if key is not correct openssl may crash
2757 if (!key.Sign(Hash(alert.vchMsg.begin(), alert.vchMsg.end()), alert.vchSig))
2758 throw runtime_error(
2759 "Unable to sign alert, check private key?\n");
2760 if(!alert.ProcessAlert())
2761 throw runtime_error(
2762 "Failed to process alert.\n");
2766 BOOST_FOREACH(CNode* pnode, vNodes)
2767 alert.RelayTo(pnode);
2771 result.push_back(Pair("strStatusBar", alert.strStatusBar));
2772 result.push_back(Pair("nVersion", alert.nVersion));
2773 result.push_back(Pair("nMinVer", alert.nMinVer));
2774 result.push_back(Pair("nMaxVer", alert.nMaxVer));
2775 result.push_back(Pair("nPriority", alert.nPriority));
2776 result.push_back(Pair("nID", alert.nID));
2777 if (alert.nCancel > 0)
2778 result.push_back(Pair("nCancel", alert.nCancel));
2789 static const CRPCCommand vRPCCommands[] =
2790 { // name function safe mode?
2791 // ------------------------ ----------------------- ----------
2792 { "help", &help, true },
2793 { "stop", &stop, true },
2794 { "getblockcount", &getblockcount, true },
2795 { "getblocknumber", &getblocknumber, true },
2796 { "getconnectioncount", &getconnectioncount, true },
2797 { "getdifficulty", &getdifficulty, true },
2798 { "getpowreward", &getpowreward, true },
2799 { "getgenerate", &getgenerate, true },
2800 { "setgenerate", &setgenerate, true },
2801 { "gethashespersec", &gethashespersec, true },
2802 { "getinfo", &getinfo, true },
2803 { "getmininginfo", &getmininginfo, true },
2804 { "getnewaddress", &getnewaddress, true },
2805 { "getnewpubkey", &getnewpubkey, true },
2806 { "getaccountaddress", &getaccountaddress, true },
2807 { "setaccount", &setaccount, true },
2808 { "getaccount", &getaccount, false },
2809 { "getaddressesbyaccount", &getaddressesbyaccount, true },
2810 { "sendtoaddress", &sendtoaddress, false },
2811 { "getreceivedbyaddress", &getreceivedbyaddress, false },
2812 { "getreceivedbyaccount", &getreceivedbyaccount, false },
2813 { "listreceivedbyaddress", &listreceivedbyaddress, false },
2814 { "listreceivedbyaccount", &listreceivedbyaccount, false },
2815 { "backupwallet", &backupwallet, true },
2816 { "keypoolrefill", &keypoolrefill, true },
2817 { "walletpassphrase", &walletpassphrase, true },
2818 { "walletpassphrasechange", &walletpassphrasechange, false },
2819 { "walletlock", &walletlock, true },
2820 { "encryptwallet", &encryptwallet, false },
2821 { "validateaddress", &validateaddress, true },
2822 { "validatepubkey", &validatepubkey, true },
2823 { "getbalance", &getbalance, false },
2824 { "move", &movecmd, false },
2825 { "sendfrom", &sendfrom, false },
2826 { "sendmany", &sendmany, false },
2827 { "addmultisigaddress", &addmultisigaddress, false },
2828 { "getblock", &getblock, false },
2829 { "getblockhash", &getblockhash, false },
2830 { "getblockbynumber", &getblockbynumber, false },
2831 { "gettransaction", &gettransaction, false },
2832 { "listtransactions", &listtransactions, false },
2833 { "signmessage", &signmessage, false },
2834 { "verifymessage", &verifymessage, false },
2835 { "getwork", &getwork, true },
2836 { "getworkex", &getworkex, true },
2837 { "listaccounts", &listaccounts, false },
2838 { "settxfee", &settxfee, false },
2839 { "getmemorypool", &getmemorypool, true },
2840 { "getblocktemplate", &getblocktemplate, true },
2841 { "submitblock", &submitblock, false },
2842 { "listsinceblock", &listsinceblock, false },
2843 { "dumpprivkey", &dumpprivkey, false },
2844 { "importprivkey", &importprivkey, false },
2845 { "getcheckpoint", &getcheckpoint, true },
2846 { "reservebalance", &reservebalance, false},
2847 { "checkwallet", &checkwallet, false},
2848 { "repairwallet", &repairwallet, false},
2849 { "resendtx", &resendtx, false},
2850 { "makekeypair", &makekeypair, false},
2851 { "sendalert", &sendalert, false},
2854 CRPCTable::CRPCTable()
2857 for (vcidx = 0; vcidx < (sizeof(vRPCCommands) / sizeof(vRPCCommands[0])); vcidx++)
2859 const CRPCCommand *pcmd;
2861 pcmd = &vRPCCommands[vcidx];
2862 mapCommands[pcmd->name] = pcmd;
2866 const CRPCCommand *CRPCTable::operator[](string name) const
2868 map<string, const CRPCCommand*>::const_iterator it = mapCommands.find(name);
2869 if (it == mapCommands.end())
2871 return (*it).second;
2877 // This ain't Apache. We're just using HTTP header for the length field
2878 // and to be compatible with other JSON-RPC implementations.
2881 string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
2884 s << "POST / HTTP/1.1\r\n"
2885 << "User-Agent: novacoin-json-rpc/" << FormatFullVersion() << "\r\n"
2886 << "Host: 127.0.0.1\r\n"
2887 << "Content-Type: application/json\r\n"
2888 << "Content-Length: " << strMsg.size() << "\r\n"
2889 << "Connection: close\r\n"
2890 << "Accept: application/json\r\n";
2891 BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
2892 s << item.first << ": " << item.second << "\r\n";
2893 s << "\r\n" << strMsg;
2898 string rfc1123Time()
2903 struct tm* now_gmt = gmtime(&now);
2904 string locale(setlocale(LC_TIME, NULL));
2905 setlocale(LC_TIME, "C"); // we want posix (aka "C") weekday/month strings
2906 strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt);
2907 setlocale(LC_TIME, locale.c_str());
2908 return string(buffer);
2911 static string HTTPReply(int nStatus, const string& strMsg)
2914 return strprintf("HTTP/1.0 401 Authorization Required\r\n"
2916 "Server: novacoin-json-rpc/%s\r\n"
2917 "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
2918 "Content-Type: text/html\r\n"
2919 "Content-Length: 296\r\n"
2921 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
2922 "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
2925 "<TITLE>Error</TITLE>\r\n"
2926 "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
2928 "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
2929 "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
2930 const char *cStatus;
2931 if (nStatus == 200) cStatus = "OK";
2932 else if (nStatus == 400) cStatus = "Bad Request";
2933 else if (nStatus == 403) cStatus = "Forbidden";
2934 else if (nStatus == 404) cStatus = "Not Found";
2935 else if (nStatus == 500) cStatus = "Internal Server Error";
2938 "HTTP/1.1 %d %s\r\n"
2940 "Connection: close\r\n"
2941 "Content-Length: %d\r\n"
2942 "Content-Type: application/json\r\n"
2943 "Server: novacoin-json-rpc/%s\r\n"
2948 rfc1123Time().c_str(),
2950 FormatFullVersion().c_str(),
2954 int ReadHTTPStatus(std::basic_istream<char>& stream)
2957 getline(stream, str);
2958 vector<string> vWords;
2959 boost::split(vWords, str, boost::is_any_of(" "));
2960 if (vWords.size() < 2)
2962 return atoi(vWords[1].c_str());
2965 int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
2971 std::getline(stream, str);
2972 if (str.empty() || str == "\r")
2974 string::size_type nColon = str.find(":");
2975 if (nColon != string::npos)
2977 string strHeader = str.substr(0, nColon);
2978 boost::trim(strHeader);
2979 boost::to_lower(strHeader);
2980 string strValue = str.substr(nColon+1);
2981 boost::trim(strValue);
2982 mapHeadersRet[strHeader] = strValue;
2983 if (strHeader == "content-length")
2984 nLen = atoi(strValue.c_str());
2990 int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
2992 mapHeadersRet.clear();
2996 int nStatus = ReadHTTPStatus(stream);
2999 int nLen = ReadHTTPHeader(stream, mapHeadersRet);
3000 if (nLen < 0 || nLen > (int)MAX_SIZE)
3006 vector<char> vch(nLen);
3007 stream.read(&vch[0], nLen);
3008 strMessageRet = string(vch.begin(), vch.end());
3014 bool HTTPAuthorized(map<string, string>& mapHeaders)
3016 string strAuth = mapHeaders["authorization"];
3017 if (strAuth.substr(0,6) != "Basic ")
3019 string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
3020 string strUserPass = DecodeBase64(strUserPass64);
3021 return strUserPass == strRPCUserColonPass;
3025 // JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
3026 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
3027 // unspecified (HTTP errors and contents of 'error').
3029 // 1.0 spec: http://json-rpc.org/wiki/specification
3030 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
3031 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
3034 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
3037 request.push_back(Pair("method", strMethod));
3038 request.push_back(Pair("params", params));
3039 request.push_back(Pair("id", id));
3040 return write_string(Value(request), false) + "\n";
3043 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
3046 if (error.type() != null_type)
3047 reply.push_back(Pair("result", Value::null));
3049 reply.push_back(Pair("result", result));
3050 reply.push_back(Pair("error", error));
3051 reply.push_back(Pair("id", id));
3052 return write_string(Value(reply), false) + "\n";
3055 void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
3057 // Send error reply from json-rpc error object
3059 int code = find_value(objError, "code").get_int();
3060 if (code == -32600) nStatus = 400;
3061 else if (code == -32601) nStatus = 404;
3062 string strReply = JSONRPCReply(Value::null, objError, id);
3063 stream << HTTPReply(nStatus, strReply) << std::flush;
3066 bool ClientAllowed(const string& strAddress)
3068 if (strAddress == asio::ip::address_v4::loopback().to_string())
3070 const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
3071 BOOST_FOREACH(string strAllow, vAllow)
3072 if (WildcardMatch(strAddress, strAllow))
3078 // IOStream device that speaks SSL but can also speak non-SSL
3080 class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
3082 SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
3084 fUseSSL = fUseSSLIn;
3085 fNeedHandshake = fUseSSLIn;
3088 void handshake(ssl::stream_base::handshake_type role)
3090 if (!fNeedHandshake) return;
3091 fNeedHandshake = false;
3092 stream.handshake(role);
3094 std::streamsize read(char* s, std::streamsize n)
3096 handshake(ssl::stream_base::server); // HTTPS servers read first
3097 if (fUseSSL) return stream.read_some(asio::buffer(s, n));
3098 return stream.next_layer().read_some(asio::buffer(s, n));
3100 std::streamsize write(const char* s, std::streamsize n)
3102 handshake(ssl::stream_base::client); // HTTPS clients write first
3103 if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
3104 return asio::write(stream.next_layer(), asio::buffer(s, n));
3106 bool connect(const std::string& server, const std::string& port)
3108 ip::tcp::resolver resolver(stream.get_io_service());
3109 ip::tcp::resolver::query query(server.c_str(), port.c_str());
3110 ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
3111 ip::tcp::resolver::iterator end;
3112 boost::system::error_code error = asio::error::host_not_found;
3113 while (error && endpoint_iterator != end)
3115 stream.lowest_layer().close();
3116 stream.lowest_layer().connect(*endpoint_iterator++, error);
3124 bool fNeedHandshake;
3129 void ThreadRPCServer(void* parg)
3131 IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
3134 vnThreadsRunning[THREAD_RPCSERVER]++;
3135 ThreadRPCServer2(parg);
3136 vnThreadsRunning[THREAD_RPCSERVER]--;
3138 catch (std::exception& e) {
3139 vnThreadsRunning[THREAD_RPCSERVER]--;
3140 PrintException(&e, "ThreadRPCServer()");
3142 vnThreadsRunning[THREAD_RPCSERVER]--;
3143 PrintException(NULL, "ThreadRPCServer()");
3145 printf("ThreadRPCServer exiting\n");
3148 void ThreadRPCServer2(void* parg)
3150 printf("ThreadRPCServer started\n");
3152 strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
3153 if (mapArgs["-rpcpassword"] == "")
3155 unsigned char rand_pwd[32];
3156 RAND_bytes(rand_pwd, 32);
3157 string strWhatAmI = "To use novacoind";
3158 if (mapArgs.count("-server"))
3159 strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
3160 else if (mapArgs.count("-daemon"))
3161 strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
3162 ThreadSafeMessageBox(strprintf(
3163 _("%s, you must set a rpcpassword in the configuration file:\n %s\n"
3164 "It is recommended you use the following random password:\n"
3167 "(you do not need to remember this password)\n"
3168 "If the file does not exist, create it with owner-readable-only file permissions.\n"),
3170 GetConfigFile().string().c_str(),
3171 EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str()),
3172 _("Error"), wxOK | wxMODAL);
3177 bool fUseSSL = GetBoolArg("-rpcssl");
3178 asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
3180 asio::io_service io_service;
3181 ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", RPC_PORT));
3182 ip::tcp::acceptor acceptor(io_service);
3185 acceptor.open(endpoint.protocol());
3186 acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
3187 acceptor.bind(endpoint);
3188 acceptor.listen(socket_base::max_connections);
3190 catch(boost::system::system_error &e)
3192 ThreadSafeMessageBox(strprintf(_("An error occured while setting up the RPC port %i for listening: %s"), endpoint.port(), e.what()),
3193 _("Error"), wxOK | wxMODAL);
3198 ssl::context context(io_service, ssl::context::sslv23);
3201 context.set_options(ssl::context::no_sslv2);
3203 filesystem::path pathCertFile(GetArg("-rpcsslcertificatechainfile", "server.cert"));
3204 if (!pathCertFile.is_complete()) pathCertFile = filesystem::path(GetDataDir()) / pathCertFile;
3205 if (filesystem::exists(pathCertFile)) context.use_certificate_chain_file(pathCertFile.string());
3206 else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", pathCertFile.string().c_str());
3208 filesystem::path pathPKFile(GetArg("-rpcsslprivatekeyfile", "server.pem"));
3209 if (!pathPKFile.is_complete()) pathPKFile = filesystem::path(GetDataDir()) / pathPKFile;
3210 if (filesystem::exists(pathPKFile)) context.use_private_key_file(pathPKFile.string(), ssl::context::pem);
3211 else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pathPKFile.string().c_str());
3213 string strCiphers = GetArg("-rpcsslciphers", "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
3214 SSL_CTX_set_cipher_list(context.impl(), strCiphers.c_str());
3219 // Accept connection
3220 SSLStream sslStream(io_service, context);
3221 SSLIOStreamDevice d(sslStream, fUseSSL);
3222 iostreams::stream<SSLIOStreamDevice> stream(d);
3224 ip::tcp::endpoint peer;
3225 vnThreadsRunning[THREAD_RPCSERVER]--;
3226 acceptor.accept(sslStream.lowest_layer(), peer);
3227 vnThreadsRunning[4]++;
3231 // Restrict callers by IP
3232 if (!ClientAllowed(peer.address().to_string()))
3234 // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
3236 stream << HTTPReply(403, "") << std::flush;
3240 map<string, string> mapHeaders;
3243 boost::thread api_caller(ReadHTTP, boost::ref(stream), boost::ref(mapHeaders), boost::ref(strRequest));
3244 if (!api_caller.timed_join(boost::posix_time::seconds(GetArg("-rpctimeout", 30))))
3247 printf("ThreadRPCServer ReadHTTP timeout\n");
3251 // Check authorization
3252 if (mapHeaders.count("authorization") == 0)
3254 stream << HTTPReply(401, "") << std::flush;
3257 if (!HTTPAuthorized(mapHeaders))
3259 printf("ThreadRPCServer incorrect password attempt from %s\n",peer.address().to_string().c_str());
3260 /* Deter brute-forcing short passwords.
3261 If this results in a DOS the user really
3262 shouldn't have their RPC port exposed.*/
3263 if (mapArgs["-rpcpassword"].size() < 20)
3266 stream << HTTPReply(401, "") << std::flush;
3270 Value id = Value::null;
3275 if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
3276 throw JSONRPCError(-32700, "Parse error");
3277 const Object& request = valRequest.get_obj();
3279 // Parse id now so errors from here on will have the id
3280 id = find_value(request, "id");
3283 Value valMethod = find_value(request, "method");
3284 if (valMethod.type() == null_type)
3285 throw JSONRPCError(-32600, "Missing method");
3286 if (valMethod.type() != str_type)
3287 throw JSONRPCError(-32600, "Method must be a string");
3288 string strMethod = valMethod.get_str();
3289 if (strMethod != "getwork" && strMethod != "getmemorypool")
3290 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
3293 Value valParams = find_value(request, "params");
3295 if (valParams.type() == array_type)
3296 params = valParams.get_array();
3297 else if (valParams.type() == null_type)
3300 throw JSONRPCError(-32600, "Params must be an array");
3303 const CRPCCommand *pcmd = tableRPC[strMethod];
3305 throw JSONRPCError(-32601, "Method not found");
3307 // Observe safe mode
3308 string strWarning = GetWarnings("rpc");
3309 if (strWarning != "" && !GetBoolArg("-disablesafemode") &&
3311 throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
3318 LOCK2(cs_main, pwalletMain->cs_wallet);
3319 result = pcmd->actor(params, false);
3323 string strReply = JSONRPCReply(result, Value::null, id);
3324 stream << HTTPReply(200, strReply) << std::flush;
3326 catch (std::exception& e)
3328 ErrorReply(stream, JSONRPCError(-1, e.what()), id);
3331 catch (Object& objError)
3333 ErrorReply(stream, objError, id);
3335 catch (std::exception& e)
3337 ErrorReply(stream, JSONRPCError(-32700, e.what()), id);
3345 Object CallRPC(const string& strMethod, const Array& params)
3347 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
3348 throw runtime_error(strprintf(
3349 _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
3350 "If the file does not exist, create it with owner-readable-only file permissions."),
3351 GetConfigFile().string().c_str()));
3353 // Connect to localhost
3354 bool fUseSSL = GetBoolArg("-rpcssl");
3355 asio::io_service io_service;
3356 ssl::context context(io_service, ssl::context::sslv23);
3357 context.set_options(ssl::context::no_sslv2);
3358 SSLStream sslStream(io_service, context);
3359 SSLIOStreamDevice d(sslStream, fUseSSL);
3360 iostreams::stream<SSLIOStreamDevice> stream(d);
3361 if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", CBigNum(RPC_PORT).ToString().c_str())))
3362 throw runtime_error("couldn't connect to server");
3364 // HTTP basic authentication
3365 string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
3366 map<string, string> mapRequestHeaders;
3367 mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
3370 string strRequest = JSONRPCRequest(strMethod, params, 1);
3371 string strPost = HTTPPost(strRequest, mapRequestHeaders);
3372 stream << strPost << std::flush;
3375 map<string, string> mapHeaders;
3377 int nStatus = ReadHTTP(stream, mapHeaders, strReply);
3379 throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
3380 else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
3381 throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
3382 else if (strReply.empty())
3383 throw runtime_error("no response from server");
3387 if (!read_string(strReply, valReply))
3388 throw runtime_error("couldn't parse reply from server");
3389 const Object& reply = valReply.get_obj();
3391 throw runtime_error("expected reply to have result, error and id properties");
3399 template<typename T>
3400 void ConvertTo(Value& value)
3402 if (value.type() == str_type)
3404 // reinterpret string as unquoted json value
3406 if (!read_string(value.get_str(), value2))
3407 throw runtime_error("type mismatch");
3408 value = value2.get_value<T>();
3412 value = value.get_value<T>();
3416 int CommandLineRPC(int argc, char *argv[])
3423 while (argc > 1 && IsSwitchChar(argv[1][0]))
3431 throw runtime_error("too few parameters");
3432 string strMethod = argv[1];
3434 // Parameters default to strings
3436 for (int i = 2; i < argc; i++)
3437 params.push_back(argv[i]);
3438 int n = params.size();
3441 // Special case non-string parameter types
3443 if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
3444 if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
3445 if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
3446 if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]);
3447 if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
3448 if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]);
3449 if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
3450 if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
3451 if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]);
3452 if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
3453 if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]);
3454 if (strMethod == "getblockhash" && n > 0) ConvertTo<boost::int64_t>(params[0]);
3455 if (strMethod == "getblockbynumber" && n > 0) ConvertTo<boost::int64_t>(params[0]);
3456 if (strMethod == "getblockbynumber" && n > 1) ConvertTo<bool>(params[1]);
3457 if (strMethod == "getblock" && n > 1) ConvertTo<bool>(params[1]);
3458 if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]);
3459 if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]);
3460 if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]);
3461 if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]);
3462 if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
3463 if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]);
3464 if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]);
3465 if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]);
3466 if (strMethod == "walletpassphrase" && n > 2) ConvertTo<bool>(params[2]);
3467 if (strMethod == "listsinceblock" && n > 1) ConvertTo<boost::int64_t>(params[1]);
3468 if (strMethod == "sendalert" && n > 2) ConvertTo<boost::int64_t>(params[2]);
3469 if (strMethod == "sendalert" && n > 3) ConvertTo<boost::int64_t>(params[3]);
3470 if (strMethod == "sendalert" && n > 4) ConvertTo<boost::int64_t>(params[4]);
3471 if (strMethod == "sendalert" && n > 5) ConvertTo<boost::int64_t>(params[5]);
3472 if (strMethod == "sendalert" && n > 6) ConvertTo<boost::int64_t>(params[6]);
3473 if (strMethod == "sendmany" && n > 1)
3475 string s = params[1].get_str();
3477 if (!read_string(s, v) || v.type() != obj_type)
3478 throw runtime_error("type mismatch");
3479 params[1] = v.get_obj();
3481 if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]);
3482 if (strMethod == "reservebalance" && n > 0) ConvertTo<bool>(params[0]);
3483 if (strMethod == "reservebalance" && n > 1) ConvertTo<double>(params[1]);
3484 if (strMethod == "addmultisigaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
3485 if (strMethod == "addmultisigaddress" && n > 1)
3487 string s = params[1].get_str();
3489 if (!read_string(s, v) || v.type() != array_type)
3490 throw runtime_error("type mismatch "+s);
3491 params[1] = v.get_array();
3495 Object reply = CallRPC(strMethod, params);
3498 const Value& result = find_value(reply, "result");
3499 const Value& error = find_value(reply, "error");
3501 if (error.type() != null_type)
3504 strPrint = "error: " + write_string(error, false);
3505 int code = find_value(error.get_obj(), "code").get_int();
3511 if (result.type() == null_type)
3513 else if (result.type() == str_type)
3514 strPrint = result.get_str();
3516 strPrint = write_string(result, true);
3519 catch (std::exception& e)
3521 strPrint = string("error: ") + e.what();
3526 PrintException(NULL, "CommandLineRPC()");
3531 fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
3540 int main(int argc, char *argv[])
3543 // Turn off microsoft heap dump noise
3544 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
3545 _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
3547 setbuf(stdin, NULL);
3548 setbuf(stdout, NULL);
3549 setbuf(stderr, NULL);
3553 if (argc >= 2 && string(argv[1]) == "-server")
3555 printf("server ready\n");
3556 ThreadRPCServer(NULL);
3560 return CommandLineRPC(argc, argv);
3563 catch (std::exception& e) {
3564 PrintException(&e, "main()");
3566 PrintException(NULL, "main()");
3572 const CRPCTable tableRPC;