1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2012 The Bitcoin developers
3 // Copyright (c) 2011-2013 The PPCoin developers
4 // Copyright (c) 2013 NovaCoin Developers
5 // Distributed under the MIT/X11 software license, see the accompanying
6 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
14 #include "checkpoints.h"
15 #include "ui_interface.h"
16 #include "bitcoinrpc.h"
19 #include <boost/asio.hpp>
20 #include <boost/filesystem.hpp>
21 #include <boost/iostreams/concepts.hpp>
22 #include <boost/iostreams/stream.hpp>
23 #include <boost/algorithm/string.hpp>
24 #include <boost/lexical_cast.hpp>
25 #include <boost/asio/ssl.hpp>
26 #include <boost/filesystem/fstream.hpp>
27 typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> SSLStream;
29 #define printf OutputDebugStringF
30 // MinGW 3.4.5 gets "fatal error: had to relocate PCH" if the json headers are
31 // precompiled in headers.h. The problem might be when the pch file goes over
32 // a certain size around 145MB. If we need access to json_spirit outside this
33 // file, we could use the compiled json_spirit option.
36 using namespace boost;
37 using namespace boost::asio;
38 using namespace json_spirit;
40 void ThreadRPCServer2(void* parg);
42 static std::string strRPCUserColonPass;
44 static int64 nWalletUnlockTime;
45 static CCriticalSection cs_nWalletUnlockTime;
47 extern Value dumpprivkey(const Array& params, bool fHelp);
48 extern Value importprivkey(const Array& params, bool fHelp);
50 Object JSONRPCError(int code, const string& message)
53 error.push_back(Pair("code", code));
54 error.push_back(Pair("message", message));
58 double GetDifficulty(const CBlockIndex* blockindex = NULL)
60 // Floating point number that is a multiple of the minimum difficulty,
61 // minimum difficulty = 1.0.
62 if (blockindex == NULL)
64 if (pindexBest == NULL)
67 blockindex = GetLastBlockIndex(pindexBest, false);
70 int nShift = (blockindex->nBits >> 24) & 0xff;
73 (double)0x0000ffff / (double)(blockindex->nBits & 0x00ffffff);
90 int64 AmountFromValue(const Value& value)
92 double dAmount = value.get_real();
93 if (dAmount <= 0.0 || dAmount > MAX_MONEY)
94 throw JSONRPCError(-3, "Invalid amount");
95 int64 nAmount = roundint64(dAmount * COIN);
96 if (!MoneyRange(nAmount))
97 throw JSONRPCError(-3, "Invalid amount");
101 Value ValueFromAmount(int64 amount)
103 return (double)amount / (double)COIN;
107 HexBits(unsigned int nBits)
113 uBits.nBits = htonl((int32_t)nBits);
114 return HexStr(BEGIN(uBits.cBits), END(uBits.cBits));
117 unsigned int BitsHex(std::string HexBits)
124 vector<unsigned char> vchBits = ParseHex(HexBits);
125 copy(vchBits.begin(), vchBits.begin() + 4, uBits.cBits);
126 uBits.nBits = htonl((int32_t)uBits.nBits);
130 void TxToJSON(const CTransaction &tx, Object& entry)
132 entry.push_back(Pair("version", tx.nVersion));
133 entry.push_back(Pair("locktime", (boost::int64_t)tx.nLockTime));
134 entry.push_back(Pair("size", (boost::int64_t)::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION)));
136 BOOST_FOREACH(const CTxIn& txin, tx.vin)
140 in.push_back(Pair("coinbase", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
144 prevout.push_back(Pair("hash", txin.prevout.hash.GetHex()));
145 prevout.push_back(Pair("n", (boost::int64_t)txin.prevout.n));
146 in.push_back(Pair("prevout", prevout));
147 in.push_back(Pair("scriptSig", txin.scriptSig.ToString()));
149 in.push_back(Pair("sequence", (boost::int64_t)txin.nSequence));
152 entry.push_back(Pair("vin", vin));
154 BOOST_FOREACH(const CTxOut& txout, tx.vout)
157 out.push_back(Pair("value", ValueFromAmount(txout.nValue)));
158 out.push_back(Pair("scriptPubKey", txout.scriptPubKey.ToString()));
161 entry.push_back(Pair("vout", vout));
164 void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
166 int confirms = wtx.GetDepthInMainChain();
167 entry.push_back(Pair("confirmations", confirms));
170 entry.push_back(Pair("blockhash", wtx.hashBlock.GetHex()));
171 entry.push_back(Pair("blockindex", wtx.nIndex));
173 entry.push_back(Pair("txid", wtx.GetHash().GetHex()));
174 entry.push_back(Pair("time", (boost::int64_t)wtx.GetTxTime()));
175 BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
176 entry.push_back(Pair(item.first, item.second));
179 string AccountFromValue(const Value& value)
181 string strAccount = value.get_str();
182 if (strAccount == "*")
183 throw JSONRPCError(-11, "Invalid account name");
187 Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool fPrintTransactionDetail)
190 result.push_back(Pair("hash", block.GetHash().GetHex()));
191 result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION)));
192 result.push_back(Pair("height", blockindex->nHeight));
193 result.push_back(Pair("version", block.nVersion));
194 result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex()));
195 result.push_back(Pair("time", DateTimeStrFormat(block.GetBlockTime())));
196 result.push_back(Pair("nonce", (boost::uint64_t)block.nNonce));
197 result.push_back(Pair("bits", HexBits(block.nBits)));
198 result.push_back(Pair("difficulty", GetDifficulty(blockindex)));
199 result.push_back(Pair("mint", ValueFromAmount(blockindex->nMint)));
200 if (blockindex->pprev)
201 result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex()));
202 if (blockindex->pnext)
203 result.push_back(Pair("nextblockhash", blockindex->pnext->GetBlockHash().GetHex()));
204 result.push_back(Pair("flags", strprintf("%s%s", blockindex->IsProofOfStake()? "proof-of-stake" : "proof-of-work", blockindex->GeneratedStakeModifier()? " stake-modifier": "")));
205 result.push_back(Pair("proofhash", blockindex->IsProofOfStake()? blockindex->hashProofOfStake.GetHex() : blockindex->GetBlockHash().GetHex()));
206 result.push_back(Pair("entropybit", (int)blockindex->GetStakeEntropyBit()));
207 result.push_back(Pair("modifier", strprintf("%016"PRI64x, blockindex->nStakeModifier)));
208 result.push_back(Pair("modifierchecksum", strprintf("%08x", blockindex->nStakeModifierChecksum)));
210 BOOST_FOREACH (const CTransaction& tx, block.vtx)
212 if (fPrintTransactionDetail)
216 entry.push_back(Pair("txid", tx.GetHash().GetHex()));
218 entry.push_back(Pair("time", DateTimeStrFormat(tx.nTime)));
220 txinfo.push_back(entry);
223 txinfo.push_back(tx.GetHash().GetHex());
226 result.push_back(Pair("tx", txinfo));
227 result.push_back(Pair("signature", HexStr(block.vchBlockSig.begin(), block.vchBlockSig.end())));
235 /// Note: This interface may still be subject to change.
238 string CRPCTable::help(string strCommand) const
241 set<rpcfn_type> setDone;
242 for (map<string, const CRPCCommand*>::const_iterator mi = mapCommands.begin(); mi != mapCommands.end(); ++mi)
244 const CRPCCommand *pcmd = mi->second;
245 string strMethod = mi->first;
246 // We already filter duplicates, but these deprecated screw up the sort order
247 if (strMethod == "getamountreceived" ||
248 strMethod == "getallreceived" ||
249 strMethod == "getblocknumber" || // deprecated
250 (strMethod.find("label") != string::npos))
252 if (strCommand != "" && strMethod != strCommand)
257 rpcfn_type pfn = pcmd->actor;
258 if (setDone.insert(pfn).second)
259 (*pfn)(params, true);
261 catch (std::exception& e)
263 // Help text is returned in an exception
264 string strHelp = string(e.what());
265 if (strCommand == "")
266 if (strHelp.find('\n') != string::npos)
267 strHelp = strHelp.substr(0, strHelp.find('\n'));
268 strRet += strHelp + "\n";
272 strRet = strprintf("help: unknown command: %s\n", strCommand.c_str());
273 strRet = strRet.substr(0,strRet.size()-1);
277 Value help(const Array& params, bool fHelp)
279 if (fHelp || params.size() > 1)
282 "List commands, or get help for a command.");
285 if (params.size() > 0)
286 strCommand = params[0].get_str();
288 return tableRPC.help(strCommand);
292 Value stop(const Array& params, bool fHelp)
294 if (fHelp || params.size() != 0)
297 "Stop novacoin server.");
298 // Shutdown will take long enough that the response should get back
300 return "novacoin server stopping";
304 Value getblockcount(const Array& params, bool fHelp)
306 if (fHelp || params.size() != 0)
309 "Returns the number of blocks in the longest block chain.");
316 Value getblocknumber(const Array& params, bool fHelp)
318 if (fHelp || params.size() != 0)
321 "Deprecated. Use getblockcount.");
327 Value getconnectioncount(const Array& params, bool fHelp)
329 if (fHelp || params.size() != 0)
331 "getconnectioncount\n"
332 "Returns the number of connections to other nodes.");
334 return (int)vNodes.size();
338 Value getdifficulty(const Array& params, bool fHelp)
340 if (fHelp || params.size() != 0)
343 "Returns difficulty as a multiple of the minimum difficulty.");
346 obj.push_back(Pair("proof-of-work", GetDifficulty()));
347 obj.push_back(Pair("proof-of-stake", GetDifficulty(GetLastBlockIndex(pindexBest, true))));
348 obj.push_back(Pair("search-interval", (int)nLastCoinStakeSearchInterval));
353 Value getgenerate(const Array& params, bool fHelp)
355 if (fHelp || params.size() != 0)
358 "Returns true or false.");
360 return GetBoolArg("-gen");
364 Value setgenerate(const Array& params, bool fHelp)
366 if (fHelp || params.size() < 1 || params.size() > 2)
368 "setgenerate <generate> [genproclimit]\n"
369 "<generate> is true or false to turn generation on or off.\n"
370 "Generation is limited to [genproclimit] processors, -1 is unlimited.");
372 bool fGenerate = true;
373 if (params.size() > 0)
374 fGenerate = params[0].get_bool();
376 if (params.size() > 1)
378 int nGenProcLimit = params[1].get_int();
379 mapArgs["-genproclimit"] = itostr(nGenProcLimit);
380 if (nGenProcLimit == 0)
383 mapArgs["-gen"] = (fGenerate ? "1" : "0");
385 GenerateBitcoins(fGenerate, pwalletMain);
390 Value gethashespersec(const Array& params, bool fHelp)
392 if (fHelp || params.size() != 0)
395 "Returns a recent hashes per second performance measurement while generating.");
397 if (GetTimeMillis() - nHPSTimerStart > 8000)
398 return (boost::int64_t)0;
399 return (boost::int64_t)dHashesPerSec;
403 Value getinfo(const Array& params, bool fHelp)
405 if (fHelp || params.size() != 0)
408 "Returns an object containing various state info.");
411 obj.push_back(Pair("version", FormatFullVersion()));
412 obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION));
413 obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
414 obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
415 obj.push_back(Pair("newmint", ValueFromAmount(pwalletMain->GetNewMint())));
416 obj.push_back(Pair("stake", ValueFromAmount(pwalletMain->GetStake())));
417 obj.push_back(Pair("blocks", (int)nBestHeight));
418 obj.push_back(Pair("moneysupply", ValueFromAmount(pindexBest->nMoneySupply)));
419 obj.push_back(Pair("connections", (int)vNodes.size()));
420 obj.push_back(Pair("proxy", (fUseProxy ? addrProxy.ToStringIPPort() : string())));
421 obj.push_back(Pair("ip", addrSeenByPeer.ToStringIP()));
422 obj.push_back(Pair("difficulty", (double)GetDifficulty()));
423 obj.push_back(Pair("testnet", fTestNet));
424 obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));
425 obj.push_back(Pair("keypoolsize", pwalletMain->GetKeyPoolSize()));
426 obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee)));
427 if (pwalletMain->IsCrypted())
428 obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime / 1000));
429 obj.push_back(Pair("errors", GetWarnings("statusbar")));
434 Value getmininginfo(const Array& params, bool fHelp)
436 if (fHelp || params.size() != 0)
439 "Returns an object containing mining-related information.");
442 obj.push_back(Pair("blocks", (int)nBestHeight));
443 obj.push_back(Pair("currentblocksize",(uint64_t)nLastBlockSize));
444 obj.push_back(Pair("currentblocktx",(uint64_t)nLastBlockTx));
445 obj.push_back(Pair("difficulty", (double)GetDifficulty()));
446 obj.push_back(Pair("errors", GetWarnings("statusbar")));
447 obj.push_back(Pair("generate", GetBoolArg("-gen")));
448 obj.push_back(Pair("genproclimit", (int)GetArg("-genproclimit", -1)));
449 obj.push_back(Pair("hashespersec", gethashespersec(params, false)));
450 obj.push_back(Pair("pooledtx", (uint64_t)mempool.size()));
451 obj.push_back(Pair("testnet", fTestNet));
456 Value getnewaddress(const Array& params, bool fHelp)
458 if (fHelp || params.size() > 1)
460 "getnewaddress [account]\n"
461 "Returns a new novacoin address for receiving payments. "
462 "If [account] is specified (recommended), it is added to the address book "
463 "so payments received with the address will be credited to [account].");
465 // Parse the account first so we don't generate a key if there's an error
467 if (params.size() > 0)
468 strAccount = AccountFromValue(params[0]);
470 if (!pwalletMain->IsLocked())
471 pwalletMain->TopUpKeyPool();
473 // Generate a new key that is added to wallet
474 std::vector<unsigned char> newKey;
475 if (!pwalletMain->GetKeyFromPool(newKey, false))
476 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
477 CBitcoinAddress address(newKey);
479 pwalletMain->SetAddressBookName(address, strAccount);
481 return address.ToString();
485 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
487 CWalletDB walletdb(pwalletMain->strWalletFile);
490 walletdb.ReadAccount(strAccount, account);
492 bool bKeyUsed = false;
494 // Check if the current key has been used
495 if (!account.vchPubKey.empty())
497 CScript scriptPubKey;
498 scriptPubKey.SetBitcoinAddress(account.vchPubKey);
499 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
500 it != pwalletMain->mapWallet.end() && !account.vchPubKey.empty();
503 const CWalletTx& wtx = (*it).second;
504 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
505 if (txout.scriptPubKey == scriptPubKey)
510 // Generate a new key
511 if (account.vchPubKey.empty() || bForceNew || bKeyUsed)
513 if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false))
514 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
516 pwalletMain->SetAddressBookName(CBitcoinAddress(account.vchPubKey), strAccount);
517 walletdb.WriteAccount(strAccount, account);
520 return CBitcoinAddress(account.vchPubKey);
523 Value getaccountaddress(const Array& params, bool fHelp)
525 if (fHelp || params.size() != 1)
527 "getaccountaddress <account>\n"
528 "Returns the current novacoin address for receiving payments to this account.");
530 // Parse the account first so we don't generate a key if there's an error
531 string strAccount = AccountFromValue(params[0]);
535 ret = GetAccountAddress(strAccount).ToString();
542 Value setaccount(const Array& params, bool fHelp)
544 if (fHelp || params.size() < 1 || params.size() > 2)
546 "setaccount <novacoinaddress> <account>\n"
547 "Sets the account associated with the given address.");
549 CBitcoinAddress address(params[0].get_str());
550 if (!address.IsValid())
551 throw JSONRPCError(-5, "Invalid novacoin address");
555 if (params.size() > 1)
556 strAccount = AccountFromValue(params[1]);
558 // Detect when changing the account of an address that is the 'unused current key' of another account:
559 if (pwalletMain->mapAddressBook.count(address))
561 string strOldAccount = pwalletMain->mapAddressBook[address];
562 if (address == GetAccountAddress(strOldAccount))
563 GetAccountAddress(strOldAccount, true);
566 pwalletMain->SetAddressBookName(address, strAccount);
572 Value getaccount(const Array& params, bool fHelp)
574 if (fHelp || params.size() != 1)
576 "getaccount <novacoinaddress>\n"
577 "Returns the account associated with the given address.");
579 CBitcoinAddress address(params[0].get_str());
580 if (!address.IsValid())
581 throw JSONRPCError(-5, "Invalid novacoin address");
584 map<CBitcoinAddress, string>::iterator mi = pwalletMain->mapAddressBook.find(address);
585 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
586 strAccount = (*mi).second;
591 Value getaddressesbyaccount(const Array& params, bool fHelp)
593 if (fHelp || params.size() != 1)
595 "getaddressesbyaccount <account>\n"
596 "Returns the list of addresses for the given account.");
598 string strAccount = AccountFromValue(params[0]);
600 // Find all addresses that have the given account
602 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
604 const CBitcoinAddress& address = item.first;
605 const string& strName = item.second;
606 if (strName == strAccount)
607 ret.push_back(address.ToString());
612 Value settxfee(const Array& params, bool fHelp)
614 if (fHelp || params.size() < 1 || params.size() > 1 || AmountFromValue(params[0]) < MIN_TX_FEE)
616 "settxfee <amount>\n"
617 "<amount> is a real and is rounded to 0.01 (cent)\n"
618 "Minimum and default transaction fee per KB is 1 cent");
620 nTransactionFee = AmountFromValue(params[0]);
621 nTransactionFee = (nTransactionFee / CENT) * CENT; // round to cent
625 Value sendtoaddress(const Array& params, bool fHelp)
627 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
629 "sendtoaddress <novacoinaddress> <amount> [comment] [comment-to]\n"
630 "<amount> is a real and is rounded to the nearest 0.000001\n"
631 "requires wallet passphrase to be set with walletpassphrase first");
632 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
634 "sendtoaddress <novacoinaddress> <amount> [comment] [comment-to]\n"
635 "<amount> is a real and is rounded to the nearest 0.000001");
637 CBitcoinAddress address(params[0].get_str());
638 if (!address.IsValid())
639 throw JSONRPCError(-5, "Invalid novacoin address");
642 int64 nAmount = AmountFromValue(params[1]);
643 if (nAmount < MIN_TXOUT_AMOUNT)
644 throw JSONRPCError(-101, "Send amount too small");
648 if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
649 wtx.mapValue["comment"] = params[2].get_str();
650 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
651 wtx.mapValue["to"] = params[3].get_str();
653 if (pwalletMain->IsLocked())
654 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
656 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
658 throw JSONRPCError(-4, strError);
660 return wtx.GetHash().GetHex();
663 Value signmessage(const Array& params, bool fHelp)
665 if (fHelp || params.size() != 2)
667 "signmessage <novacoinaddress> <message>\n"
668 "Sign a message with the private key of an address");
670 if (pwalletMain->IsLocked())
671 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
673 string strAddress = params[0].get_str();
674 string strMessage = params[1].get_str();
676 CBitcoinAddress addr(strAddress);
678 throw JSONRPCError(-3, "Invalid address");
681 if (!pwalletMain->GetKey(addr, key))
682 throw JSONRPCError(-4, "Private key not available");
684 CDataStream ss(SER_GETHASH, 0);
685 ss << strMessageMagic;
688 vector<unsigned char> vchSig;
689 if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig))
690 throw JSONRPCError(-5, "Sign failed");
692 return EncodeBase64(&vchSig[0], vchSig.size());
695 Value verifymessage(const Array& params, bool fHelp)
697 if (fHelp || params.size() != 3)
699 "verifymessage <novacoinaddress> <signature> <message>\n"
700 "Verify a signed message");
702 string strAddress = params[0].get_str();
703 string strSign = params[1].get_str();
704 string strMessage = params[2].get_str();
706 CBitcoinAddress addr(strAddress);
708 throw JSONRPCError(-3, "Invalid address");
710 bool fInvalid = false;
711 vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
714 throw JSONRPCError(-5, "Malformed base64 encoding");
716 CDataStream ss(SER_GETHASH, 0);
717 ss << strMessageMagic;
721 if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
724 return (CBitcoinAddress(key.GetPubKey()) == addr);
728 Value getreceivedbyaddress(const Array& params, bool fHelp)
730 if (fHelp || params.size() < 1 || params.size() > 2)
732 "getreceivedbyaddress <novacoinaddress> [minconf=1]\n"
733 "Returns the total amount received by <novacoinaddress> in transactions with at least [minconf] confirmations.");
736 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
737 CScript scriptPubKey;
738 if (!address.IsValid())
739 throw JSONRPCError(-5, "Invalid novacoin address");
740 scriptPubKey.SetBitcoinAddress(address);
741 if (!IsMine(*pwalletMain,scriptPubKey))
744 // Minimum confirmations
746 if (params.size() > 1)
747 nMinDepth = params[1].get_int();
751 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
753 const CWalletTx& wtx = (*it).second;
754 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
757 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
758 if (txout.scriptPubKey == scriptPubKey)
759 if (wtx.GetDepthInMainChain() >= nMinDepth)
760 nAmount += txout.nValue;
763 return ValueFromAmount(nAmount);
767 void GetAccountAddresses(string strAccount, set<CBitcoinAddress>& setAddress)
769 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
771 const CBitcoinAddress& address = item.first;
772 const string& strName = item.second;
773 if (strName == strAccount)
774 setAddress.insert(address);
779 Value getreceivedbyaccount(const Array& params, bool fHelp)
781 if (fHelp || params.size() < 1 || params.size() > 2)
783 "getreceivedbyaccount <account> [minconf=1]\n"
784 "Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.");
786 // Minimum confirmations
788 if (params.size() > 1)
789 nMinDepth = params[1].get_int();
791 // Get the set of pub keys assigned to account
792 string strAccount = AccountFromValue(params[0]);
793 set<CBitcoinAddress> setAddress;
794 GetAccountAddresses(strAccount, setAddress);
798 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
800 const CWalletTx& wtx = (*it).second;
801 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
804 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
806 CBitcoinAddress address;
807 if (ExtractAddress(txout.scriptPubKey, address) && pwalletMain->HaveKey(address) && setAddress.count(address))
808 if (wtx.GetDepthInMainChain() >= nMinDepth)
809 nAmount += txout.nValue;
813 return (double)nAmount / (double)COIN;
817 int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth)
821 // Tally wallet transactions
822 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
824 const CWalletTx& wtx = (*it).second;
828 int64 nGenerated, nReceived, nSent, nFee;
829 wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee);
831 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
832 nBalance += nReceived;
833 nBalance += nGenerated - nSent - nFee;
836 // Tally internal accounting entries
837 nBalance += walletdb.GetAccountCreditDebit(strAccount);
842 int64 GetAccountBalance(const string& strAccount, int nMinDepth)
844 CWalletDB walletdb(pwalletMain->strWalletFile);
845 return GetAccountBalance(walletdb, strAccount, nMinDepth);
849 Value getbalance(const Array& params, bool fHelp)
851 if (fHelp || params.size() > 2)
853 "getbalance [account] [minconf=1]\n"
854 "If [account] is not specified, returns the server's total available balance.\n"
855 "If [account] is specified, returns the balance in the account.");
857 if (params.size() == 0)
858 return ValueFromAmount(pwalletMain->GetBalance());
861 if (params.size() > 1)
862 nMinDepth = params[1].get_int();
864 if (params[0].get_str() == "*") {
865 // Calculate total balance a different way from GetBalance()
866 // (GetBalance() sums up all unspent TxOuts)
867 // getbalance and getbalance '*' should always return the same number.
869 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
871 const CWalletTx& wtx = (*it).second;
875 int64 allGeneratedImmature, allGeneratedMature, allFee;
876 allGeneratedImmature = allGeneratedMature = allFee = 0;
877 string strSentAccount;
878 list<pair<CBitcoinAddress, int64> > listReceived;
879 list<pair<CBitcoinAddress, int64> > listSent;
880 wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
881 if (wtx.GetDepthInMainChain() >= nMinDepth)
883 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listReceived)
884 nBalance += r.second;
886 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listSent)
887 nBalance -= r.second;
889 nBalance += allGeneratedMature;
891 return ValueFromAmount(nBalance);
894 string strAccount = AccountFromValue(params[0]);
896 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
898 return ValueFromAmount(nBalance);
902 Value getpowreward(const Array& params, bool fHelp)
904 if (fHelp || params.size() > 1)
906 "getpowreward [nBits]\n"
907 "Returns PoW reward for block with provided difficulty.");
909 if (params.size() == 0)
910 throw JSONRPCError(-200, "no bits provided");
912 std::string sBits = params[0].get_str();
914 if (sBits.length() != 8)
915 throw JSONRPCError(-201, "incorrect bits provided");
917 unsigned int nBits = BitsHex(sBits);
919 return (int)GetProofOfWorkReward(nBits);
924 Value movecmd(const Array& params, bool fHelp)
926 if (fHelp || params.size() < 3 || params.size() > 5)
928 "move <fromaccount> <toaccount> <amount> [minconf=1] [comment]\n"
929 "Move from one account in your wallet to another.");
931 string strFrom = AccountFromValue(params[0]);
932 string strTo = AccountFromValue(params[1]);
933 int64 nAmount = AmountFromValue(params[2]);
934 if (params.size() > 3)
935 // unused parameter, used to be nMinDepth, keep type-checking it though
936 (void)params[3].get_int();
938 if (params.size() > 4)
939 strComment = params[4].get_str();
941 CWalletDB walletdb(pwalletMain->strWalletFile);
942 if (!walletdb.TxnBegin())
943 throw JSONRPCError(-20, "database error");
945 int64 nNow = GetAdjustedTime();
948 CAccountingEntry debit;
949 debit.strAccount = strFrom;
950 debit.nCreditDebit = -nAmount;
952 debit.strOtherAccount = strTo;
953 debit.strComment = strComment;
954 walletdb.WriteAccountingEntry(debit);
957 CAccountingEntry credit;
958 credit.strAccount = strTo;
959 credit.nCreditDebit = nAmount;
961 credit.strOtherAccount = strFrom;
962 credit.strComment = strComment;
963 walletdb.WriteAccountingEntry(credit);
965 if (!walletdb.TxnCommit())
966 throw JSONRPCError(-20, "database error");
972 Value sendfrom(const Array& params, bool fHelp)
974 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
976 "sendfrom <fromaccount> <tonovacoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
977 "<amount> is a real and is rounded to the nearest 0.000001\n"
978 "requires wallet passphrase to be set with walletpassphrase first");
979 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
981 "sendfrom <fromaccount> <tonovacoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
982 "<amount> is a real and is rounded to the nearest 0.000001");
984 string strAccount = AccountFromValue(params[0]);
985 CBitcoinAddress address(params[1].get_str());
986 if (!address.IsValid())
987 throw JSONRPCError(-5, "Invalid novacoin address");
988 int64 nAmount = AmountFromValue(params[2]);
989 if (nAmount < MIN_TXOUT_AMOUNT)
990 throw JSONRPCError(-101, "Send amount too small");
992 if (params.size() > 3)
993 nMinDepth = params[3].get_int();
996 wtx.strFromAccount = strAccount;
997 if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
998 wtx.mapValue["comment"] = params[4].get_str();
999 if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
1000 wtx.mapValue["to"] = params[5].get_str();
1002 if (pwalletMain->IsLocked())
1003 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
1006 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
1007 if (nAmount > nBalance)
1008 throw JSONRPCError(-6, "Account has insufficient funds");
1011 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
1013 throw JSONRPCError(-4, strError);
1015 return wtx.GetHash().GetHex();
1019 Value sendmany(const Array& params, bool fHelp)
1021 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
1022 throw runtime_error(
1023 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
1024 "amounts are double-precision floating point numbers\n"
1025 "requires wallet passphrase to be set with walletpassphrase first");
1026 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
1027 throw runtime_error(
1028 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
1029 "amounts are double-precision floating point numbers");
1031 string strAccount = AccountFromValue(params[0]);
1032 Object sendTo = params[1].get_obj();
1034 if (params.size() > 2)
1035 nMinDepth = params[2].get_int();
1038 wtx.strFromAccount = strAccount;
1039 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
1040 wtx.mapValue["comment"] = params[3].get_str();
1042 set<CBitcoinAddress> setAddress;
1043 vector<pair<CScript, int64> > vecSend;
1045 int64 totalAmount = 0;
1046 BOOST_FOREACH(const Pair& s, sendTo)
1048 CBitcoinAddress address(s.name_);
1049 if (!address.IsValid())
1050 throw JSONRPCError(-5, string("Invalid novacoin address:")+s.name_);
1052 if (setAddress.count(address))
1053 throw JSONRPCError(-8, string("Invalid parameter, duplicated address: ")+s.name_);
1054 setAddress.insert(address);
1056 CScript scriptPubKey;
1057 scriptPubKey.SetBitcoinAddress(address);
1058 int64 nAmount = AmountFromValue(s.value_);
1059 if (nAmount < MIN_TXOUT_AMOUNT)
1060 throw JSONRPCError(-101, "Send amount too small");
1061 totalAmount += nAmount;
1063 vecSend.push_back(make_pair(scriptPubKey, nAmount));
1066 if (pwalletMain->IsLocked())
1067 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
1068 if (fWalletUnlockMintOnly)
1069 throw JSONRPCError(-13, "Error: Wallet unlocked for block minting only.");
1072 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
1073 if (totalAmount > nBalance)
1074 throw JSONRPCError(-6, "Account has insufficient funds");
1077 CReserveKey keyChange(pwalletMain);
1078 int64 nFeeRequired = 0;
1079 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
1082 if (totalAmount + nFeeRequired > pwalletMain->GetBalance())
1083 throw JSONRPCError(-6, "Insufficient funds");
1084 throw JSONRPCError(-4, "Transaction creation failed");
1086 if (!pwalletMain->CommitTransaction(wtx, keyChange))
1087 throw JSONRPCError(-4, "Transaction commit failed");
1089 return wtx.GetHash().GetHex();
1092 Value addmultisigaddress(const Array& params, bool fHelp)
1094 if (fHelp || params.size() < 2 || params.size() > 3)
1096 string msg = "addmultisigaddress <nrequired> <'[\"key\",\"key\"]'> [account]\n"
1097 "Add a nrequired-to-sign multisignature address to the wallet\"\n"
1098 "each key is a bitcoin address or hex-encoded public key\n"
1099 "If [account] is specified, assign address to [account].";
1100 throw runtime_error(msg);
1103 int nRequired = params[0].get_int();
1104 const Array& keys = params[1].get_array();
1106 if (params.size() > 2)
1107 strAccount = AccountFromValue(params[2]);
1109 // Gather public keys
1111 throw runtime_error("a multisignature address must require at least one key to redeem");
1112 if ((int)keys.size() < nRequired)
1113 throw runtime_error(
1114 strprintf("not enough keys supplied "
1115 "(got %d keys, but need at least %d to redeem)", keys.size(), nRequired));
1116 std::vector<CKey> pubkeys;
1117 pubkeys.resize(keys.size());
1118 for (unsigned int i = 0; i < keys.size(); i++)
1120 const std::string& ks = keys[i].get_str();
1122 // Case 1: bitcoin address and we have full public key:
1123 CBitcoinAddress address(ks);
1124 if (address.IsValid())
1126 if (address.IsScript())
1127 throw runtime_error(
1128 strprintf("%s is a pay-to-script address",ks.c_str()));
1129 std::vector<unsigned char> vchPubKey;
1130 if (!pwalletMain->GetPubKey(address, vchPubKey))
1131 throw runtime_error(
1132 strprintf("no full public key for address %s",ks.c_str()));
1133 if (vchPubKey.empty() || !pubkeys[i].SetPubKey(vchPubKey))
1134 throw runtime_error(" Invalid public key: "+ks);
1137 // Case 2: hex public key
1140 vector<unsigned char> vchPubKey = ParseHex(ks);
1141 if (vchPubKey.empty() || !pubkeys[i].SetPubKey(vchPubKey))
1142 throw runtime_error(" Invalid public key: "+ks);
1146 throw runtime_error(" Invalid public key: "+ks);
1150 // Construct using pay-to-script-hash:
1152 inner.SetMultisig(nRequired, pubkeys);
1154 uint160 scriptHash = Hash160(inner);
1155 CScript scriptPubKey;
1156 scriptPubKey.SetPayToScriptHash(inner);
1157 pwalletMain->AddCScript(inner);
1158 CBitcoinAddress address;
1159 address.SetScriptHash160(scriptHash);
1161 pwalletMain->SetAddressBookName(address, strAccount);
1162 return address.ToString();
1173 nConf = std::numeric_limits<int>::max();
1177 Value ListReceived(const Array& params, bool fByAccounts)
1179 // Minimum confirmations
1181 if (params.size() > 0)
1182 nMinDepth = params[0].get_int();
1184 // Whether to include empty accounts
1185 bool fIncludeEmpty = false;
1186 if (params.size() > 1)
1187 fIncludeEmpty = params[1].get_bool();
1190 map<CBitcoinAddress, tallyitem> mapTally;
1191 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1193 const CWalletTx& wtx = (*it).second;
1195 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
1198 int nDepth = wtx.GetDepthInMainChain();
1199 if (nDepth < nMinDepth)
1202 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
1204 CBitcoinAddress address;
1205 if (!ExtractAddress(txout.scriptPubKey, address) || !pwalletMain->HaveKey(address) || !address.IsValid())
1208 tallyitem& item = mapTally[address];
1209 item.nAmount += txout.nValue;
1210 item.nConf = min(item.nConf, nDepth);
1216 map<string, tallyitem> mapAccountTally;
1217 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
1219 const CBitcoinAddress& address = item.first;
1220 const string& strAccount = item.second;
1221 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
1222 if (it == mapTally.end() && !fIncludeEmpty)
1226 int nConf = std::numeric_limits<int>::max();
1227 if (it != mapTally.end())
1229 nAmount = (*it).second.nAmount;
1230 nConf = (*it).second.nConf;
1235 tallyitem& item = mapAccountTally[strAccount];
1236 item.nAmount += nAmount;
1237 item.nConf = min(item.nConf, nConf);
1242 obj.push_back(Pair("address", address.ToString()));
1243 obj.push_back(Pair("account", strAccount));
1244 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1245 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1252 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
1254 int64 nAmount = (*it).second.nAmount;
1255 int nConf = (*it).second.nConf;
1257 obj.push_back(Pair("account", (*it).first));
1258 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1259 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1267 Value listreceivedbyaddress(const Array& params, bool fHelp)
1269 if (fHelp || params.size() > 2)
1270 throw runtime_error(
1271 "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
1272 "[minconf] is the minimum number of confirmations before payments are included.\n"
1273 "[includeempty] whether to include addresses that haven't received any payments.\n"
1274 "Returns an array of objects containing:\n"
1275 " \"address\" : receiving address\n"
1276 " \"account\" : the account of the receiving address\n"
1277 " \"amount\" : total amount received by the address\n"
1278 " \"confirmations\" : number of confirmations of the most recent transaction included");
1280 return ListReceived(params, false);
1283 Value listreceivedbyaccount(const Array& params, bool fHelp)
1285 if (fHelp || params.size() > 2)
1286 throw runtime_error(
1287 "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
1288 "[minconf] is the minimum number of confirmations before payments are included.\n"
1289 "[includeempty] whether to include accounts that haven't received any payments.\n"
1290 "Returns an array of objects containing:\n"
1291 " \"account\" : the account of the receiving addresses\n"
1292 " \"amount\" : total amount received by addresses with this account\n"
1293 " \"confirmations\" : number of confirmations of the most recent transaction included");
1295 return ListReceived(params, true);
1298 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret)
1300 int64 nGeneratedImmature, nGeneratedMature, nFee;
1301 string strSentAccount;
1302 list<pair<CBitcoinAddress, int64> > listReceived;
1303 list<pair<CBitcoinAddress, int64> > listSent;
1305 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1307 bool fAllAccounts = (strAccount == string("*"));
1309 // Generated blocks assigned to account ""
1310 if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == ""))
1313 entry.push_back(Pair("account", string("")));
1314 if (nGeneratedImmature)
1316 entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
1317 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
1321 entry.push_back(Pair("category", "generate"));
1322 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
1325 WalletTxToJSON(wtx, entry);
1326 ret.push_back(entry);
1330 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1332 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1335 entry.push_back(Pair("account", strSentAccount));
1336 entry.push_back(Pair("address", s.first.ToString()));
1337 entry.push_back(Pair("category", "send"));
1338 entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1339 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1341 WalletTxToJSON(wtx, entry);
1342 ret.push_back(entry);
1347 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1349 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1352 if (pwalletMain->mapAddressBook.count(r.first))
1353 account = pwalletMain->mapAddressBook[r.first];
1354 if (fAllAccounts || (account == strAccount))
1357 entry.push_back(Pair("account", account));
1358 entry.push_back(Pair("address", r.first.ToString()));
1359 entry.push_back(Pair("category", "receive"));
1360 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1362 WalletTxToJSON(wtx, entry);
1363 ret.push_back(entry);
1369 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1371 bool fAllAccounts = (strAccount == string("*"));
1373 if (fAllAccounts || acentry.strAccount == strAccount)
1376 entry.push_back(Pair("account", acentry.strAccount));
1377 entry.push_back(Pair("category", "move"));
1378 entry.push_back(Pair("time", (boost::int64_t)acentry.nTime));
1379 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1380 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1381 entry.push_back(Pair("comment", acentry.strComment));
1382 ret.push_back(entry);
1386 Value listtransactions(const Array& params, bool fHelp)
1388 if (fHelp || params.size() > 3)
1389 throw runtime_error(
1390 "listtransactions [account] [count=10] [from=0]\n"
1391 "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1393 string strAccount = "*";
1394 if (params.size() > 0)
1395 strAccount = params[0].get_str();
1397 if (params.size() > 1)
1398 nCount = params[1].get_int();
1400 if (params.size() > 2)
1401 nFrom = params[2].get_int();
1404 throw JSONRPCError(-8, "Negative count");
1406 throw JSONRPCError(-8, "Negative from");
1409 CWalletDB walletdb(pwalletMain->strWalletFile);
1411 // First: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap.
1412 typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
1413 typedef multimap<int64, TxPair > TxItems;
1416 // Note: maintaining indices in the database of (account,time) --> txid and (account, time) --> acentry
1417 // would make this much faster for applications that do this a lot.
1418 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1420 CWalletTx* wtx = &((*it).second);
1421 txByTime.insert(make_pair(wtx->GetTxTime(), TxPair(wtx, (CAccountingEntry*)0)));
1423 list<CAccountingEntry> acentries;
1424 walletdb.ListAccountCreditDebit(strAccount, acentries);
1425 BOOST_FOREACH(CAccountingEntry& entry, acentries)
1427 txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
1430 // iterate backwards until we have nCount items to return:
1431 for (TxItems::reverse_iterator it = txByTime.rbegin(); it != txByTime.rend(); ++it)
1433 CWalletTx *const pwtx = (*it).second.first;
1435 ListTransactions(*pwtx, strAccount, 0, true, ret);
1436 CAccountingEntry *const pacentry = (*it).second.second;
1438 AcentryToJSON(*pacentry, strAccount, ret);
1440 if (ret.size() >= (nCount+nFrom)) break;
1442 // ret is newest to oldest
1444 if (nFrom > (int)ret.size())
1446 if ((nFrom + nCount) > (int)ret.size())
1447 nCount = ret.size() - nFrom;
1448 Array::iterator first = ret.begin();
1449 std::advance(first, nFrom);
1450 Array::iterator last = ret.begin();
1451 std::advance(last, nFrom+nCount);
1453 if (last != ret.end()) ret.erase(last, ret.end());
1454 if (first != ret.begin()) ret.erase(ret.begin(), first);
1456 std::reverse(ret.begin(), ret.end()); // Return oldest to newest
1461 Value listaccounts(const Array& params, bool fHelp)
1463 if (fHelp || params.size() > 1)
1464 throw runtime_error(
1465 "listaccounts [minconf=1]\n"
1466 "Returns Object that has account names as keys, account balances as values.");
1469 if (params.size() > 0)
1470 nMinDepth = params[0].get_int();
1472 map<string, int64> mapAccountBalances;
1473 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& entry, pwalletMain->mapAddressBook) {
1474 if (pwalletMain->HaveKey(entry.first)) // This address belongs to me
1475 mapAccountBalances[entry.second] = 0;
1478 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1480 const CWalletTx& wtx = (*it).second;
1481 int64 nGeneratedImmature, nGeneratedMature, nFee;
1482 string strSentAccount;
1483 list<pair<CBitcoinAddress, int64> > listReceived;
1484 list<pair<CBitcoinAddress, int64> > listSent;
1485 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1486 mapAccountBalances[strSentAccount] -= nFee;
1487 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1488 mapAccountBalances[strSentAccount] -= s.second;
1489 if (wtx.GetDepthInMainChain() >= nMinDepth)
1491 mapAccountBalances[""] += nGeneratedMature;
1492 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1493 if (pwalletMain->mapAddressBook.count(r.first))
1494 mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1496 mapAccountBalances[""] += r.second;
1500 list<CAccountingEntry> acentries;
1501 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1502 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1503 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1506 BOOST_FOREACH(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) {
1507 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1512 Value listsinceblock(const Array& params, bool fHelp)
1515 throw runtime_error(
1516 "listsinceblock [blockhash] [target-confirmations]\n"
1517 "Get all transactions in blocks since block [blockhash], or all transactions if omitted");
1519 CBlockIndex *pindex = NULL;
1520 int target_confirms = 1;
1522 if (params.size() > 0)
1524 uint256 blockId = 0;
1526 blockId.SetHex(params[0].get_str());
1527 pindex = CBlockLocator(blockId).GetBlockIndex();
1530 if (params.size() > 1)
1532 target_confirms = params[1].get_int();
1534 if (target_confirms < 1)
1535 throw JSONRPCError(-8, "Invalid parameter");
1538 int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1;
1542 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1544 CWalletTx tx = (*it).second;
1546 if (depth == -1 || tx.GetDepthInMainChain() < depth)
1547 ListTransactions(tx, "*", 0, true, transactions);
1552 if (target_confirms == 1)
1554 lastblock = hashBestChain;
1558 int target_height = pindexBest->nHeight + 1 - target_confirms;
1561 for (block = pindexBest;
1562 block && block->nHeight > target_height;
1563 block = block->pprev) { }
1565 lastblock = block ? block->GetBlockHash() : 0;
1569 ret.push_back(Pair("transactions", transactions));
1570 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1575 Value gettransaction(const Array& params, bool fHelp)
1577 if (fHelp || params.size() != 1)
1578 throw runtime_error(
1579 "gettransaction <txid>\n"
1580 "Get detailed information about <txid>");
1583 hash.SetHex(params[0].get_str());
1587 if (pwalletMain->mapWallet.count(hash))
1589 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1591 TxToJSON(wtx, entry);
1593 int64 nCredit = wtx.GetCredit();
1594 int64 nDebit = wtx.GetDebit();
1595 int64 nNet = nCredit - nDebit;
1596 int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
1598 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1600 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1602 WalletTxToJSON(wtx, entry);
1605 ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
1606 entry.push_back(Pair("details", details));
1611 uint256 hashBlock = 0;
1612 if (GetTransaction(hash, tx, hashBlock))
1614 entry.push_back(Pair("txid", hash.GetHex()));
1615 TxToJSON(tx, entry);
1617 entry.push_back(Pair("confirmations", 0));
1620 entry.push_back(Pair("blockhash", hashBlock.GetHex()));
1621 map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
1622 if (mi != mapBlockIndex.end() && (*mi).second)
1624 CBlockIndex* pindex = (*mi).second;
1625 if (pindex->IsInMainChain())
1627 entry.push_back(Pair("confirmations", 1 + nBestHeight - pindex->nHeight));
1628 entry.push_back(Pair("txntime", (boost::int64_t)tx.nTime));
1629 entry.push_back(Pair("time", (boost::int64_t)pindex->nTime));
1632 entry.push_back(Pair("confirmations", 0));
1637 throw JSONRPCError(-5, "No information available about transaction");
1644 Value backupwallet(const Array& params, bool fHelp)
1646 if (fHelp || params.size() != 1)
1647 throw runtime_error(
1648 "backupwallet <destination>\n"
1649 "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1651 string strDest = params[0].get_str();
1652 BackupWallet(*pwalletMain, strDest);
1658 Value keypoolrefill(const Array& params, bool fHelp)
1660 if (pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1661 throw runtime_error(
1663 "Fills the keypool, requires wallet passphrase to be set.");
1664 if (!pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1665 throw runtime_error(
1667 "Fills the keypool.");
1669 if (pwalletMain->IsLocked())
1670 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
1672 pwalletMain->TopUpKeyPool();
1674 if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100))
1675 throw JSONRPCError(-4, "Error refreshing keypool.");
1681 void ThreadTopUpKeyPool(void* parg)
1683 pwalletMain->TopUpKeyPool();
1686 void ThreadCleanWalletPassphrase(void* parg)
1688 int64 nMyWakeTime = GetTimeMillis() + *((int64*)parg) * 1000;
1690 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1692 if (nWalletUnlockTime == 0)
1694 nWalletUnlockTime = nMyWakeTime;
1698 if (nWalletUnlockTime==0)
1700 int64 nToSleep = nWalletUnlockTime - GetTimeMillis();
1704 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1706 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1710 if (nWalletUnlockTime)
1712 nWalletUnlockTime = 0;
1713 pwalletMain->Lock();
1718 if (nWalletUnlockTime < nMyWakeTime)
1719 nWalletUnlockTime = nMyWakeTime;
1722 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1724 delete (int64*)parg;
1727 Value walletpassphrase(const Array& params, bool fHelp)
1729 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 3))
1730 throw runtime_error(
1731 "walletpassphrase <passphrase> <timeout> [mintonly]\n"
1732 "Stores the wallet decryption key in memory for <timeout> seconds.\n"
1733 "mintonly is optional true/false allowing only block minting.");
1736 if (!pwalletMain->IsCrypted())
1737 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1739 if (!pwalletMain->IsLocked())
1740 throw JSONRPCError(-17, "Error: Wallet is already unlocked, use walletlock first if need to change unlock settings.");
1742 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1743 SecureString strWalletPass;
1744 strWalletPass.reserve(100);
1745 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1746 // Alternately, find a way to make params[0] mlock()'d to begin with.
1747 strWalletPass = params[0].get_str().c_str();
1749 if (strWalletPass.length() > 0)
1751 if (!pwalletMain->Unlock(strWalletPass))
1752 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1755 throw runtime_error(
1756 "walletpassphrase <passphrase> <timeout>\n"
1757 "Stores the wallet decryption key in memory for <timeout> seconds.");
1759 CreateThread(ThreadTopUpKeyPool, NULL);
1760 int64* pnSleepTime = new int64(params[1].get_int64());
1761 CreateThread(ThreadCleanWalletPassphrase, pnSleepTime);
1763 // ppcoin: if user OS account compromised prevent trivial sendmoney commands
1764 if (params.size() > 2)
1765 fWalletUnlockMintOnly = params[2].get_bool();
1767 fWalletUnlockMintOnly = false;
1773 Value walletpassphrasechange(const Array& params, bool fHelp)
1775 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1776 throw runtime_error(
1777 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1778 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1781 if (!pwalletMain->IsCrypted())
1782 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1784 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1785 // Alternately, find a way to make params[0] mlock()'d to begin with.
1786 SecureString strOldWalletPass;
1787 strOldWalletPass.reserve(100);
1788 strOldWalletPass = params[0].get_str().c_str();
1790 SecureString strNewWalletPass;
1791 strNewWalletPass.reserve(100);
1792 strNewWalletPass = params[1].get_str().c_str();
1794 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1795 throw runtime_error(
1796 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1797 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1799 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1800 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1806 Value walletlock(const Array& params, bool fHelp)
1808 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1809 throw runtime_error(
1811 "Removes the wallet encryption key from memory, locking the wallet.\n"
1812 "After calling this method, you will need to call walletpassphrase again\n"
1813 "before being able to call any methods which require the wallet to be unlocked.");
1816 if (!pwalletMain->IsCrypted())
1817 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called.");
1820 LOCK(cs_nWalletUnlockTime);
1821 pwalletMain->Lock();
1822 nWalletUnlockTime = 0;
1829 Value encryptwallet(const Array& params, bool fHelp)
1831 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1832 throw runtime_error(
1833 "encryptwallet <passphrase>\n"
1834 "Encrypts the wallet with <passphrase>.");
1837 if (pwalletMain->IsCrypted())
1838 throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
1840 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1841 // Alternately, find a way to make params[0] mlock()'d to begin with.
1842 SecureString strWalletPass;
1843 strWalletPass.reserve(100);
1844 strWalletPass = params[0].get_str().c_str();
1846 if (strWalletPass.length() < 1)
1847 throw runtime_error(
1848 "encryptwallet <passphrase>\n"
1849 "Encrypts the wallet with <passphrase>.");
1851 if (!pwalletMain->EncryptWallet(strWalletPass))
1852 throw JSONRPCError(-16, "Error: Failed to encrypt the wallet.");
1854 // BDB seems to have a bad habit of writing old data into
1855 // slack space in .dat files; that is bad if the old data is
1856 // unencrypted private keys. So:
1858 return "wallet encrypted; novacoin server stopping, restart to run with encrypted wallet";
1862 Value validateaddress(const Array& params, bool fHelp)
1864 if (fHelp || params.size() != 1)
1865 throw runtime_error(
1866 "validateaddress <novacoinaddress>\n"
1867 "Return information about <novacoinaddress>.");
1869 CBitcoinAddress address(params[0].get_str());
1870 bool isValid = address.IsValid();
1873 ret.push_back(Pair("isvalid", isValid));
1876 // Call Hash160ToAddress() so we always return current ADDRESSVERSION
1877 // version of the address:
1878 string currentAddress = address.ToString();
1879 ret.push_back(Pair("address", currentAddress));
1880 if (pwalletMain->HaveKey(address))
1882 ret.push_back(Pair("ismine", true));
1883 std::vector<unsigned char> vchPubKey;
1884 pwalletMain->GetPubKey(address, vchPubKey);
1885 ret.push_back(Pair("pubkey", HexStr(vchPubKey)));
1887 key.SetPubKey(vchPubKey);
1888 ret.push_back(Pair("iscompressed", key.IsCompressed()));
1890 else if (pwalletMain->HaveCScript(address.GetHash160()))
1892 ret.push_back(Pair("isscript", true));
1894 pwalletMain->GetCScript(address.GetHash160(), subscript);
1895 ret.push_back(Pair("ismine", ::IsMine(*pwalletMain, subscript)));
1896 std::vector<CBitcoinAddress> addresses;
1897 txnouttype whichType;
1899 ExtractAddresses(subscript, whichType, addresses, nRequired);
1900 ret.push_back(Pair("script", GetTxnOutputType(whichType)));
1902 BOOST_FOREACH(const CBitcoinAddress& addr, addresses)
1903 a.push_back(addr.ToString());
1904 ret.push_back(Pair("addresses", a));
1905 if (whichType == TX_MULTISIG)
1906 ret.push_back(Pair("sigsrequired", nRequired));
1909 ret.push_back(Pair("ismine", false));
1910 if (pwalletMain->mapAddressBook.count(address))
1911 ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
1916 Value validatepubkey(const Array& params, bool fHelp)
1918 if (fHelp || !params.size() || params.size() > 2)
1919 throw runtime_error(
1920 "validatepubkey <novacoinpubkey>\n"
1921 "Return information about <novacoinpubkey>.");
1923 std::vector<unsigned char> vchPubKey = ParseHex(params[0].get_str());
1926 if(vchPubKey.size() == 33) // Compressed key
1927 isValid = (vchPubKey[0] == 0x02 || vchPubKey[0] == 0x03);
1928 else if(vchPubKey.size() == 65) // Uncompressed key
1929 isValid = vchPubKey[0] == 0x04;
1933 CBitcoinAddress address(vchPubKey);
1934 isValid = isValid ? address.IsValid() : false;
1937 ret.push_back(Pair("isvalid", isValid));
1940 // Call Hash160ToAddress() so we always return current ADDRESSVERSION
1941 // version of the address:
1942 string currentAddress = address.ToString();
1943 ret.push_back(Pair("address", currentAddress));
1944 if (pwalletMain->HaveKey(address))
1946 ret.push_back(Pair("ismine", true));
1948 key.SetPubKey(vchPubKey);
1949 ret.push_back(Pair("iscompressed", key.IsCompressed()));
1952 ret.push_back(Pair("ismine", false));
1953 if (pwalletMain->mapAddressBook.count(address))
1954 ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
1959 Value getworkex(const Array& params, bool fHelp)
1961 if (fHelp || params.size() > 2)
1962 throw runtime_error(
1963 "getworkex [data, coinbase]\n"
1964 "If [data, coinbase] is not specified, returns extended work data.\n"
1968 throw JSONRPCError(-9, "NovaCoin is not connected!");
1970 if (IsInitialBlockDownload())
1971 throw JSONRPCError(-10, "NovaCoin is downloading blocks...");
1973 typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
1974 static mapNewBlock_t mapNewBlock;
1975 static vector<CBlock*> vNewBlock;
1976 static CReserveKey reservekey(pwalletMain);
1978 if (params.size() == 0)
1981 static unsigned int nTransactionsUpdatedLast;
1982 static CBlockIndex* pindexPrev;
1983 static int64 nStart;
1984 static CBlock* pblock;
1985 if (pindexPrev != pindexBest ||
1986 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
1988 if (pindexPrev != pindexBest)
1990 // Deallocate old blocks since they're obsolete now
1991 mapNewBlock.clear();
1992 BOOST_FOREACH(CBlock* pblock, vNewBlock)
1996 nTransactionsUpdatedLast = nTransactionsUpdated;
1997 pindexPrev = pindexBest;
2001 pblock = CreateNewBlock(pwalletMain);
2003 throw JSONRPCError(-7, "Out of memory");
2004 vNewBlock.push_back(pblock);
2008 pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
2011 // Update nExtraNonce
2012 static unsigned int nExtraNonce = 0;
2013 IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
2016 mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
2018 // Prebuild hash buffers
2022 FormatHashBuffers(pblock, pmidstate, pdata, phash1);
2024 uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
2026 CTransaction coinbaseTx = pblock->vtx[0];
2027 std::vector<uint256> merkle = pblock->GetMerkleBranch(0);
2030 result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata))));
2031 result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
2033 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
2035 result.push_back(Pair("coinbase", HexStr(ssTx.begin(), ssTx.end())));
2038 printf("DEBUG: merkle size %i\n", merkle.size());
2040 BOOST_FOREACH(uint256 merkleh, merkle) {
2041 printf("%s\n", merkleh.ToString().c_str());
2042 merkle_arr.push_back(HexStr(BEGIN(merkleh), END(merkleh)));
2045 result.push_back(Pair("merkle", merkle_arr));
2053 vector<unsigned char> vchData = ParseHex(params[0].get_str());
2054 vector<unsigned char> coinbase;
2056 if(params.size() == 2)
2057 coinbase = ParseHex(params[1].get_str());
2059 if (vchData.size() != 128)
2060 throw JSONRPCError(-8, "Invalid parameter");
2062 CBlock* pdata = (CBlock*)&vchData[0];
2065 for (int i = 0; i < 128/4; i++)
2066 ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]);
2069 if (!mapNewBlock.count(pdata->hashMerkleRoot))
2071 CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
2073 pblock->nTime = pdata->nTime;
2074 pblock->nNonce = pdata->nNonce;
2076 if(coinbase.size() == 0)
2077 pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
2079 CDataStream(coinbase, SER_NETWORK, PROTOCOL_VERSION) >> pblock->vtx[0]; // FIXME - HACK!
2081 pblock->hashMerkleRoot = pblock->BuildMerkleTree();
2083 if (!pblock->SignBlock(*pwalletMain))
2084 throw JSONRPCError(-100, "Unable to sign block, wallet locked?");
2087 return CheckWork(pblock, *pwalletMain, reservekey);
2092 Value getwork(const Array& params, bool fHelp)
2094 if (fHelp || params.size() > 1)
2095 throw runtime_error(
2097 "If [data] is not specified, returns formatted hash data to work on:\n"
2098 " \"midstate\" : precomputed hash state after hashing the first half of the data (DEPRECATED)\n" // deprecated
2099 " \"data\" : block data\n"
2100 " \"hash1\" : formatted hash buffer for second hash (DEPRECATED)\n" // deprecated
2101 " \"target\" : little endian hash target\n"
2102 "If [data] is specified, tries to solve the block and returns true if it was successful.");
2105 throw JSONRPCError(-9, "NovaCoin is not connected!");
2107 if (IsInitialBlockDownload())
2108 throw JSONRPCError(-10, "NovaCoin is downloading blocks...");
2110 typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
2111 static mapNewBlock_t mapNewBlock;
2112 static vector<CBlock*> vNewBlock;
2113 static CReserveKey reservekey(pwalletMain);
2115 if (params.size() == 0)
2118 static unsigned int nTransactionsUpdatedLast;
2119 static CBlockIndex* pindexPrev;
2120 static int64 nStart;
2121 static CBlock* pblock;
2122 if (pindexPrev != pindexBest ||
2123 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
2125 if (pindexPrev != pindexBest)
2127 // Deallocate old blocks since they're obsolete now
2128 mapNewBlock.clear();
2129 BOOST_FOREACH(CBlock* pblock, vNewBlock)
2133 nTransactionsUpdatedLast = nTransactionsUpdated;
2134 pindexPrev = pindexBest;
2138 pblock = CreateNewBlock(pwalletMain);
2140 throw JSONRPCError(-7, "Out of memory");
2141 vNewBlock.push_back(pblock);
2145 pblock->UpdateTime(pindexPrev);
2148 // Update nExtraNonce
2149 static unsigned int nExtraNonce = 0;
2150 IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
2153 mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
2155 // Prebuild hash buffers
2159 FormatHashBuffers(pblock, pmidstate, pdata, phash1);
2161 uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
2164 result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate)))); // deprecated
2165 result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata))));
2166 result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1)))); // deprecated
2167 result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
2173 vector<unsigned char> vchData = ParseHex(params[0].get_str());
2174 if (vchData.size() != 128)
2175 throw JSONRPCError(-8, "Invalid parameter");
2176 CBlock* pdata = (CBlock*)&vchData[0];
2179 for (int i = 0; i < 128/4; i++)
2180 ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]);
2183 if (!mapNewBlock.count(pdata->hashMerkleRoot))
2185 CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
2187 pblock->nTime = pdata->nTime;
2188 pblock->nNonce = pdata->nNonce;
2189 pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
2190 pblock->hashMerkleRoot = pblock->BuildMerkleTree();
2191 if (!pblock->SignBlock(*pwalletMain))
2192 throw JSONRPCError(-100, "Unable to sign block, wallet locked?");
2194 return CheckWork(pblock, *pwalletMain, reservekey);
2198 Value getblocktemplate(const Array& params, bool fHelp)
2200 if (fHelp || params.size() > 1)
2201 throw runtime_error(
2202 "getblocktemplate [params]\n"
2203 "Returns data needed to construct a block to work on:\n"
2204 " \"version\" : block version\n"
2205 " \"previousblockhash\" : hash of current highest block\n"
2206 " \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
2207 " \"coinbaseaux\" : data that should be included in coinbase\n"
2208 " \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
2209 " \"target\" : hash target\n"
2210 " \"mintime\" : minimum timestamp appropriate for next block\n"
2211 " \"curtime\" : current timestamp\n"
2212 " \"mutable\" : list of ways the block template may be changed\n"
2213 " \"noncerange\" : range of valid nonces\n"
2214 " \"sigoplimit\" : limit of sigops in blocks\n"
2215 " \"sizelimit\" : limit of block size\n"
2216 " \"bits\" : compressed target of next block\n"
2217 " \"height\" : height of the next block\n"
2218 "See https://en.bitcoin.it/wiki/BIP_0022 for full specification.");
2220 std::string strMode = "template";
2221 if (params.size() > 0)
2223 const Object& oparam = params[0].get_obj();
2224 const Value& modeval = find_value(oparam, "mode");
2225 if (modeval.type() == str_type)
2226 strMode = modeval.get_str();
2228 throw JSONRPCError(-8, "Invalid mode");
2231 if (strMode != "template")
2232 throw JSONRPCError(-8, "Invalid mode");
2235 throw JSONRPCError(-9, "NovaCoin is not connected!");
2237 if (IsInitialBlockDownload())
2238 throw JSONRPCError(-10, "NovaCoin is downloading blocks...");
2240 static CReserveKey reservekey(pwalletMain);
2243 static unsigned int nTransactionsUpdatedLast;
2244 static CBlockIndex* pindexPrev;
2245 static int64 nStart;
2246 static CBlock* pblock;
2247 if (pindexPrev != pindexBest ||
2248 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5))
2250 // Clear pindexPrev so future calls make a new block, despite any failures from here on
2253 // Store the pindexBest used before CreateNewBlock, to avoid races
2254 nTransactionsUpdatedLast = nTransactionsUpdated;
2255 CBlockIndex* pindexPrevNew = pindexBest;
2264 pblock = CreateNewBlock(pwalletMain);
2266 throw JSONRPCError(-7, "Out of memory");
2268 // Need to update only after we know CreateNewBlock succeeded
2269 pindexPrev = pindexPrevNew;
2273 pblock->UpdateTime(pindexPrev);
2277 map<uint256, int64_t> setTxIndex;
2280 BOOST_FOREACH (CTransaction& tx, pblock->vtx)
2282 uint256 txHash = tx.GetHash();
2283 setTxIndex[txHash] = i++;
2285 if (tx.IsCoinBase() || tx.IsCoinStake())
2290 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
2292 entry.push_back(Pair("data", HexStr(ssTx.begin(), ssTx.end())));
2294 entry.push_back(Pair("hash", txHash.GetHex()));
2296 MapPrevTx mapInputs;
2297 map<uint256, CTxIndex> mapUnused;
2298 bool fInvalid = false;
2299 if (tx.FetchInputs(txdb, mapUnused, false, false, mapInputs, fInvalid))
2301 entry.push_back(Pair("fee", (int64_t)(tx.GetValueIn(mapInputs) - tx.GetValueOut())));
2304 BOOST_FOREACH (MapPrevTx::value_type& inp, mapInputs)
2306 if (setTxIndex.count(inp.first))
2307 deps.push_back(setTxIndex[inp.first]);
2309 entry.push_back(Pair("depends", deps));
2311 int64_t nSigOps = tx.GetLegacySigOpCount();
2312 nSigOps += tx.GetP2SHSigOpCount(mapInputs);
2313 entry.push_back(Pair("sigops", nSigOps));
2316 transactions.push_back(entry);
2320 aux.push_back(Pair("flags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end())));
2322 uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
2324 static Array aMutable;
2325 if (aMutable.empty())
2327 aMutable.push_back("time");
2328 aMutable.push_back("transactions");
2329 aMutable.push_back("prevblock");
2333 result.push_back(Pair("version", pblock->nVersion));
2334 result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
2335 result.push_back(Pair("transactions", transactions));
2336 result.push_back(Pair("coinbaseaux", aux));
2337 result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
2338 result.push_back(Pair("target", hashTarget.GetHex()));
2339 result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1));
2340 result.push_back(Pair("mutable", aMutable));
2341 result.push_back(Pair("noncerange", "00000000ffffffff"));
2342 result.push_back(Pair("sigoplimit", (int64_t)MAX_BLOCK_SIGOPS));
2343 result.push_back(Pair("sizelimit", (int64_t)MAX_BLOCK_SIZE));
2344 result.push_back(Pair("curtime", (int64_t)pblock->nTime));
2345 result.push_back(Pair("bits", HexBits(pblock->nBits)));
2346 result.push_back(Pair("height", (int64_t)(pindexPrev->nHeight+1)));
2351 Value submitblock(const Array& params, bool fHelp)
2353 if (fHelp || params.size() < 1 || params.size() > 2)
2354 throw runtime_error(
2355 "submitblock <hex data> [optional-params-obj]\n"
2356 "[optional-params-obj] parameter is currently ignored.\n"
2357 "Attempts to submit new block to network.\n"
2358 "See https://en.bitcoin.it/wiki/BIP_0022 for full specification.");
2360 vector<unsigned char> blockData(ParseHex(params[0].get_str()));
2361 CDataStream ssBlock(blockData, SER_NETWORK, PROTOCOL_VERSION);
2366 catch (std::exception &e) {
2367 throw JSONRPCError(-22, "Block decode failed");
2370 static CReserveKey reservekey(pwalletMain);
2372 if(!block.SignBlock(*pwalletMain))
2373 throw JSONRPCError(-100, "Unable to sign block, wallet locked?");
2375 bool fAccepted = CheckWork(&block, *pwalletMain, reservekey);
2383 Value getmemorypool(const Array& params, bool fHelp)
2385 if (fHelp || params.size() > 1)
2386 throw runtime_error(
2387 "getmemorypool [data]\n"
2388 "If [data] is not specified, returns data needed to construct a block to work on:\n"
2389 " \"version\" : block version\n"
2390 " \"previousblockhash\" : hash of current highest block\n"
2391 " \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
2392 " \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
2393 " \"coinbaseflags\" : data that should be included in coinbase so support for new features can be judged\n"
2394 " \"time\" : timestamp appropriate for next block\n"
2395 " \"mintime\" : minimum timestamp appropriate for next block\n"
2396 " \"curtime\" : current timestamp\n"
2397 " \"bits\" : compressed target of next block\n"
2398 "If [data] is specified, tries to solve the block and returns true if it was successful.");
2400 if (params.size() == 0)
2403 throw JSONRPCError(-9, "NovaCoin is not connected!");
2405 if (IsInitialBlockDownload())
2406 throw JSONRPCError(-10, "NovaCoin is downloading blocks...");
2408 static CReserveKey reservekey(pwalletMain);
2411 static unsigned int nTransactionsUpdatedLast;
2412 static CBlockIndex* pindexPrev;
2413 static int64 nStart;
2414 static CBlock* pblock;
2415 if (pindexPrev != pindexBest ||
2416 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5))
2418 nTransactionsUpdatedLast = nTransactionsUpdated;
2419 pindexPrev = pindexBest;
2425 pblock = CreateNewBlock(pwalletMain);
2427 throw JSONRPCError(-7, "Out of memory");
2431 pblock->UpdateTime(pindexPrev);
2435 BOOST_FOREACH(CTransaction tx, pblock->vtx) {
2436 if(tx.IsCoinBase() || tx.IsCoinStake())
2439 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
2442 transactions.push_back(HexStr(ssTx.begin(), ssTx.end()));
2446 result.push_back(Pair("version", pblock->nVersion));
2447 result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
2448 result.push_back(Pair("transactions", transactions));
2449 result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
2450 result.push_back(Pair("coinbaseflags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end())));
2451 result.push_back(Pair("time", (int64_t)pblock->nTime));
2452 result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1));
2453 result.push_back(Pair("curtime", (int64_t)GetAdjustedTime()));
2454 result.push_back(Pair("bits", HexBits(pblock->nBits)));
2461 CDataStream ssBlock(ParseHex(params[0].get_str()), SER_NETWORK, PROTOCOL_VERSION);
2465 static CReserveKey reservekey(pwalletMain);
2467 if(!pblock.SignBlock(*pwalletMain))
2468 throw JSONRPCError(-100, "Unable to sign block, wallet locked?");
2470 return CheckWork(&pblock, *pwalletMain, reservekey);
2474 Value getnewpubkey(const Array& params, bool fHelp)
2476 if (fHelp || params.size() > 1)
2477 throw runtime_error(
2478 "getnewpubkey [account]\n"
2479 "Returns new public key for coinbase generation.");
2481 // Parse the account first so we don't generate a key if there's an error
2483 if (params.size() > 0)
2484 strAccount = AccountFromValue(params[0]);
2486 if (!pwalletMain->IsLocked())
2487 pwalletMain->TopUpKeyPool();
2489 // Generate a new key that is added to wallet
2490 std::vector<unsigned char> newKey = pwalletMain->GenerateNewKey(true);
2493 throw JSONRPCError(-12, "Error: Unable to create key");
2495 CBitcoinAddress address(newKey);
2496 pwalletMain->SetAddressBookName(address, strAccount);
2498 return HexStr(newKey.begin(), newKey.end());
2501 Value getblockhash(const Array& params, bool fHelp)
2503 if (fHelp || params.size() != 1)
2504 throw runtime_error(
2505 "getblockhash <index>\n"
2506 "Returns hash of block in best-block-chain at <index>.");
2508 int nHeight = params[0].get_int();
2509 if (nHeight < 0 || nHeight > nBestHeight)
2510 throw runtime_error("Block number out of range.");
2513 CBlockIndex* pblockindex = mapBlockIndex[hashBestChain];
2514 while (pblockindex->nHeight > nHeight)
2515 pblockindex = pblockindex->pprev;
2516 return pblockindex->phashBlock->GetHex();
2519 Value getblock(const Array& params, bool fHelp)
2521 if (fHelp || params.size() < 1 || params.size() > 2)
2522 throw runtime_error(
2523 "getblock <hash> [txinfo]\n"
2524 "txinfo optional to print more detailed tx info\n"
2525 "Returns details of a block with given block-hash.");
2527 std::string strHash = params[0].get_str();
2528 uint256 hash(strHash);
2530 if (mapBlockIndex.count(hash) == 0)
2531 throw JSONRPCError(-5, "Block not found");
2534 CBlockIndex* pblockindex = mapBlockIndex[hash];
2535 block.ReadFromDisk(pblockindex, true);
2537 return blockToJSON(block, pblockindex, params.size() > 1 ? params[1].get_bool() : false);
2540 Value getblockbynumber(const Array& params, bool fHelp)
2542 if (fHelp || params.size() < 1 || params.size() > 2)
2543 throw runtime_error(
2544 "getblock <number> [txinfo]\n"
2545 "txinfo optional to print more detailed tx info\n"
2546 "Returns details of a block with given block-number.");
2548 int nHeight = params[0].get_int();
2549 if (nHeight < 0 || nHeight > nBestHeight)
2550 throw runtime_error("Block number out of range.");
2553 CBlockIndex* pblockindex = mapBlockIndex[hashBestChain];
2554 while (pblockindex->nHeight > nHeight)
2555 pblockindex = pblockindex->pprev;
2557 uint256 hash = *pblockindex->phashBlock;
2559 pblockindex = mapBlockIndex[hash];
2560 block.ReadFromDisk(pblockindex, true);
2562 return blockToJSON(block, pblockindex, params.size() > 1 ? params[1].get_bool() : false);
2565 // ppcoin: get information of sync-checkpoint
2566 Value getcheckpoint(const Array& params, bool fHelp)
2568 if (fHelp || params.size() != 0)
2569 throw runtime_error(
2571 "Show info of synchronized checkpoint.\n");
2574 CBlockIndex* pindexCheckpoint;
2576 result.push_back(Pair("synccheckpoint", Checkpoints::hashSyncCheckpoint.ToString().c_str()));
2577 pindexCheckpoint = mapBlockIndex[Checkpoints::hashSyncCheckpoint];
2578 result.push_back(Pair("height", pindexCheckpoint->nHeight));
2579 result.push_back(Pair("timestamp", DateTimeStrFormat(pindexCheckpoint->GetBlockTime()).c_str()));
2580 if (mapArgs.count("-checkpointkey"))
2581 result.push_back(Pair("checkpointmaster", true));
2587 // ppcoin: reserve balance from being staked for network protection
2588 Value reservebalance(const Array& params, bool fHelp)
2590 if (fHelp || params.size() > 2)
2591 throw runtime_error(
2592 "reservebalance [<reserve> [amount]]\n"
2593 "<reserve> is true or false to turn balance reserve on or off.\n"
2594 "<amount> is a real and rounded to cent.\n"
2595 "Set reserve amount not participating in network protection.\n"
2596 "If no parameters provided current setting is printed.\n");
2598 if (params.size() > 0)
2600 bool fReserve = params[0].get_bool();
2603 if (params.size() == 1)
2604 throw runtime_error("must provide amount to reserve balance.\n");
2605 int64 nAmount = AmountFromValue(params[1]);
2606 nAmount = (nAmount / CENT) * CENT; // round to cent
2608 throw runtime_error("amount cannot be negative.\n");
2609 mapArgs["-reservebalance"] = FormatMoney(nAmount).c_str();
2613 if (params.size() > 1)
2614 throw runtime_error("cannot specify amount to turn off reserve.\n");
2615 mapArgs["-reservebalance"] = "0";
2620 int64 nReserveBalance = 0;
2621 if (mapArgs.count("-reservebalance") && !ParseMoney(mapArgs["-reservebalance"], nReserveBalance))
2622 throw runtime_error("invalid reserve balance amount\n");
2623 result.push_back(Pair("reserve", (nReserveBalance > 0)));
2624 result.push_back(Pair("amount", ValueFromAmount(nReserveBalance)));
2629 // ppcoin: check wallet integrity
2630 Value checkwallet(const Array& params, bool fHelp)
2632 if (fHelp || params.size() > 0)
2633 throw runtime_error(
2635 "Check wallet for integrity.\n");
2638 int64 nBalanceInQuestion;
2639 pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion, true);
2641 if (nMismatchSpent == 0)
2642 result.push_back(Pair("wallet check passed", true));
2645 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
2646 result.push_back(Pair("amount in question", ValueFromAmount(nBalanceInQuestion)));
2652 // ppcoin: repair wallet
2653 Value repairwallet(const Array& params, bool fHelp)
2655 if (fHelp || params.size() > 0)
2656 throw runtime_error(
2658 "Repair wallet if checkwallet reports any problem.\n");
2661 int64 nBalanceInQuestion;
2662 pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion);
2664 if (nMismatchSpent == 0)
2665 result.push_back(Pair("wallet check passed", true));
2668 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
2669 result.push_back(Pair("amount affected by repair", ValueFromAmount(nBalanceInQuestion)));
2674 // NovaCoin: resend unconfirmed wallet transactions
2675 Value resendtx(const Array& params, bool fHelp)
2677 if (fHelp || params.size() > 1)
2678 throw runtime_error(
2680 "Re-send unconfirmed transactions.\n"
2683 ResendWalletTransactions();
2689 // ppcoin: make a public-private key pair
2690 Value makekeypair(const Array& params, bool fHelp)
2692 if (fHelp || params.size() > 1)
2693 throw runtime_error(
2694 "makekeypair [prefix]\n"
2695 "Make a public/private key pair.\n"
2696 "[prefix] is optional preferred prefix for the public key.\n");
2698 string strPrefix = "";
2699 if (params.size() > 0)
2700 strPrefix = params[0].get_str();
2706 key.MakeNewKey(false);
2708 } while (nCount < 10000 && strPrefix != HexStr(key.GetPubKey()).substr(0, strPrefix.size()));
2710 if (strPrefix != HexStr(key.GetPubKey()).substr(0, strPrefix.size()))
2713 CPrivKey vchPrivKey = key.GetPrivKey();
2715 result.push_back(Pair("PrivateKey", HexStr<CPrivKey::iterator>(vchPrivKey.begin(), vchPrivKey.end())));
2716 result.push_back(Pair("PublicKey", HexStr(key.GetPubKey())));
2720 extern CCriticalSection cs_mapAlerts;
2721 extern map<uint256, CAlert> mapAlerts;
2723 // ppcoin: send alert.
2724 // There is a known deadlock situation with ThreadMessageHandler
2725 // ThreadMessageHandler: holds cs_vSend and acquiring cs_main in SendMessages()
2726 // ThreadRPCServer: holds cs_main and acquiring cs_vSend in alert.RelayTo()/PushMessage()/BeginMessage()
2727 Value sendalert(const Array& params, bool fHelp)
2729 if (fHelp || params.size() < 6)
2730 throw runtime_error(
2731 "sendalert <message> <privatekey> <minver> <maxver> <priority> <id> [cancelupto]\n"
2732 "<message> is the alert text message\n"
2733 "<privatekey> is hex string of alert master private key\n"
2734 "<minver> is the minimum applicable internal client version\n"
2735 "<maxver> is the maximum applicable internal client version\n"
2736 "<priority> is integer priority number\n"
2737 "<id> is the alert id\n"
2738 "[cancelupto] cancels all alert id's up to this number\n"
2739 "Returns true or false.");
2744 alert.strStatusBar = params[0].get_str();
2745 alert.nMinVer = params[2].get_int();
2746 alert.nMaxVer = params[3].get_int();
2747 alert.nPriority = params[4].get_int();
2748 alert.nID = params[5].get_int();
2749 if (params.size() > 6)
2750 alert.nCancel = params[6].get_int();
2751 alert.nVersion = PROTOCOL_VERSION;
2752 alert.nRelayUntil = GetAdjustedTime() + 365*24*60*60;
2753 alert.nExpiration = GetAdjustedTime() + 365*24*60*60;
2755 CDataStream sMsg(SER_NETWORK, PROTOCOL_VERSION);
2756 sMsg << (CUnsignedAlert)alert;
2757 alert.vchMsg = vector<unsigned char>(sMsg.begin(), sMsg.end());
2759 vector<unsigned char> vchPrivKey = ParseHex(params[1].get_str());
2760 key.SetPrivKey(CPrivKey(vchPrivKey.begin(), vchPrivKey.end())); // if key is not correct openssl may crash
2761 if (!key.Sign(Hash(alert.vchMsg.begin(), alert.vchMsg.end()), alert.vchSig))
2762 throw runtime_error(
2763 "Unable to sign alert, check private key?\n");
2764 if(!alert.ProcessAlert())
2765 throw runtime_error(
2766 "Failed to process alert.\n");
2770 BOOST_FOREACH(CNode* pnode, vNodes)
2771 alert.RelayTo(pnode);
2775 result.push_back(Pair("strStatusBar", alert.strStatusBar));
2776 result.push_back(Pair("nVersion", alert.nVersion));
2777 result.push_back(Pair("nMinVer", alert.nMinVer));
2778 result.push_back(Pair("nMaxVer", alert.nMaxVer));
2779 result.push_back(Pair("nPriority", alert.nPriority));
2780 result.push_back(Pair("nID", alert.nID));
2781 if (alert.nCancel > 0)
2782 result.push_back(Pair("nCancel", alert.nCancel));
2793 static const CRPCCommand vRPCCommands[] =
2794 { // name function safe mode?
2795 // ------------------------ ----------------------- ----------
2796 { "help", &help, true },
2797 { "stop", &stop, true },
2798 { "getblockcount", &getblockcount, true },
2799 { "getblocknumber", &getblocknumber, true },
2800 { "getconnectioncount", &getconnectioncount, true },
2801 { "getdifficulty", &getdifficulty, true },
2802 { "getpowreward", &getpowreward, true },
2803 { "getgenerate", &getgenerate, true },
2804 { "setgenerate", &setgenerate, true },
2805 { "gethashespersec", &gethashespersec, true },
2806 { "getinfo", &getinfo, true },
2807 { "getmininginfo", &getmininginfo, true },
2808 { "getnewaddress", &getnewaddress, true },
2809 { "getnewpubkey", &getnewpubkey, true },
2810 { "getaccountaddress", &getaccountaddress, true },
2811 { "setaccount", &setaccount, true },
2812 { "getaccount", &getaccount, false },
2813 { "getaddressesbyaccount", &getaddressesbyaccount, true },
2814 { "sendtoaddress", &sendtoaddress, false },
2815 { "getreceivedbyaddress", &getreceivedbyaddress, false },
2816 { "getreceivedbyaccount", &getreceivedbyaccount, false },
2817 { "listreceivedbyaddress", &listreceivedbyaddress, false },
2818 { "listreceivedbyaccount", &listreceivedbyaccount, false },
2819 { "backupwallet", &backupwallet, true },
2820 { "keypoolrefill", &keypoolrefill, true },
2821 { "walletpassphrase", &walletpassphrase, true },
2822 { "walletpassphrasechange", &walletpassphrasechange, false },
2823 { "walletlock", &walletlock, true },
2824 { "encryptwallet", &encryptwallet, false },
2825 { "validateaddress", &validateaddress, true },
2826 { "validatepubkey", &validatepubkey, true },
2827 { "getbalance", &getbalance, false },
2828 { "move", &movecmd, false },
2829 { "sendfrom", &sendfrom, false },
2830 { "sendmany", &sendmany, false },
2831 { "addmultisigaddress", &addmultisigaddress, false },
2832 { "getblock", &getblock, false },
2833 { "getblockhash", &getblockhash, false },
2834 { "getblockbynumber", &getblockbynumber, false },
2835 { "gettransaction", &gettransaction, false },
2836 { "listtransactions", &listtransactions, false },
2837 { "signmessage", &signmessage, false },
2838 { "verifymessage", &verifymessage, false },
2839 { "getwork", &getwork, true },
2840 { "getworkex", &getworkex, true },
2841 { "listaccounts", &listaccounts, false },
2842 { "settxfee", &settxfee, false },
2843 { "getmemorypool", &getmemorypool, true },
2844 { "getblocktemplate", &getblocktemplate, true },
2845 { "submitblock", &submitblock, false },
2846 { "listsinceblock", &listsinceblock, false },
2847 { "dumpprivkey", &dumpprivkey, false },
2848 { "importprivkey", &importprivkey, false },
2849 { "getcheckpoint", &getcheckpoint, true },
2850 { "reservebalance", &reservebalance, false},
2851 { "checkwallet", &checkwallet, false},
2852 { "repairwallet", &repairwallet, false},
2853 { "resendtx", &resendtx, false},
2854 { "makekeypair", &makekeypair, false},
2855 { "sendalert", &sendalert, false},
2858 CRPCTable::CRPCTable()
2861 for (vcidx = 0; vcidx < (sizeof(vRPCCommands) / sizeof(vRPCCommands[0])); vcidx++)
2863 const CRPCCommand *pcmd;
2865 pcmd = &vRPCCommands[vcidx];
2866 mapCommands[pcmd->name] = pcmd;
2870 const CRPCCommand *CRPCTable::operator[](string name) const
2872 map<string, const CRPCCommand*>::const_iterator it = mapCommands.find(name);
2873 if (it == mapCommands.end())
2875 return (*it).second;
2881 // This ain't Apache. We're just using HTTP header for the length field
2882 // and to be compatible with other JSON-RPC implementations.
2885 string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
2888 s << "POST / HTTP/1.1\r\n"
2889 << "User-Agent: novacoin-json-rpc/" << FormatFullVersion() << "\r\n"
2890 << "Host: 127.0.0.1\r\n"
2891 << "Content-Type: application/json\r\n"
2892 << "Content-Length: " << strMsg.size() << "\r\n"
2893 << "Connection: close\r\n"
2894 << "Accept: application/json\r\n";
2895 BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
2896 s << item.first << ": " << item.second << "\r\n";
2897 s << "\r\n" << strMsg;
2902 string rfc1123Time()
2907 struct tm* now_gmt = gmtime(&now);
2908 string locale(setlocale(LC_TIME, NULL));
2909 setlocale(LC_TIME, "C"); // we want posix (aka "C") weekday/month strings
2910 strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt);
2911 setlocale(LC_TIME, locale.c_str());
2912 return string(buffer);
2915 static string HTTPReply(int nStatus, const string& strMsg)
2918 return strprintf("HTTP/1.0 401 Authorization Required\r\n"
2920 "Server: novacoin-json-rpc/%s\r\n"
2921 "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
2922 "Content-Type: text/html\r\n"
2923 "Content-Length: 296\r\n"
2925 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
2926 "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
2929 "<TITLE>Error</TITLE>\r\n"
2930 "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
2932 "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
2933 "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
2934 const char *cStatus;
2935 if (nStatus == 200) cStatus = "OK";
2936 else if (nStatus == 400) cStatus = "Bad Request";
2937 else if (nStatus == 403) cStatus = "Forbidden";
2938 else if (nStatus == 404) cStatus = "Not Found";
2939 else if (nStatus == 500) cStatus = "Internal Server Error";
2942 "HTTP/1.1 %d %s\r\n"
2944 "Connection: close\r\n"
2945 "Content-Length: %d\r\n"
2946 "Content-Type: application/json\r\n"
2947 "Server: novacoin-json-rpc/%s\r\n"
2952 rfc1123Time().c_str(),
2954 FormatFullVersion().c_str(),
2958 int ReadHTTPStatus(std::basic_istream<char>& stream)
2961 getline(stream, str);
2962 vector<string> vWords;
2963 boost::split(vWords, str, boost::is_any_of(" "));
2964 if (vWords.size() < 2)
2966 return atoi(vWords[1].c_str());
2969 int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
2975 std::getline(stream, str);
2976 if (str.empty() || str == "\r")
2978 string::size_type nColon = str.find(":");
2979 if (nColon != string::npos)
2981 string strHeader = str.substr(0, nColon);
2982 boost::trim(strHeader);
2983 boost::to_lower(strHeader);
2984 string strValue = str.substr(nColon+1);
2985 boost::trim(strValue);
2986 mapHeadersRet[strHeader] = strValue;
2987 if (strHeader == "content-length")
2988 nLen = atoi(strValue.c_str());
2994 int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
2996 mapHeadersRet.clear();
3000 int nStatus = ReadHTTPStatus(stream);
3003 int nLen = ReadHTTPHeader(stream, mapHeadersRet);
3004 if (nLen < 0 || nLen > (int)MAX_SIZE)
3010 vector<char> vch(nLen);
3011 stream.read(&vch[0], nLen);
3012 strMessageRet = string(vch.begin(), vch.end());
3018 bool HTTPAuthorized(map<string, string>& mapHeaders)
3020 string strAuth = mapHeaders["authorization"];
3021 if (strAuth.substr(0,6) != "Basic ")
3023 string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
3024 string strUserPass = DecodeBase64(strUserPass64);
3025 return strUserPass == strRPCUserColonPass;
3029 // JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
3030 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
3031 // unspecified (HTTP errors and contents of 'error').
3033 // 1.0 spec: http://json-rpc.org/wiki/specification
3034 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
3035 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
3038 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
3041 request.push_back(Pair("method", strMethod));
3042 request.push_back(Pair("params", params));
3043 request.push_back(Pair("id", id));
3044 return write_string(Value(request), false) + "\n";
3047 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
3050 if (error.type() != null_type)
3051 reply.push_back(Pair("result", Value::null));
3053 reply.push_back(Pair("result", result));
3054 reply.push_back(Pair("error", error));
3055 reply.push_back(Pair("id", id));
3056 return write_string(Value(reply), false) + "\n";
3059 void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
3061 // Send error reply from json-rpc error object
3063 int code = find_value(objError, "code").get_int();
3064 if (code == -32600) nStatus = 400;
3065 else if (code == -32601) nStatus = 404;
3066 string strReply = JSONRPCReply(Value::null, objError, id);
3067 stream << HTTPReply(nStatus, strReply) << std::flush;
3070 bool ClientAllowed(const string& strAddress)
3072 if (strAddress == asio::ip::address_v4::loopback().to_string())
3074 const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
3075 BOOST_FOREACH(string strAllow, vAllow)
3076 if (WildcardMatch(strAddress, strAllow))
3082 // IOStream device that speaks SSL but can also speak non-SSL
3084 class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
3086 SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
3088 fUseSSL = fUseSSLIn;
3089 fNeedHandshake = fUseSSLIn;
3092 void handshake(ssl::stream_base::handshake_type role)
3094 if (!fNeedHandshake) return;
3095 fNeedHandshake = false;
3096 stream.handshake(role);
3098 std::streamsize read(char* s, std::streamsize n)
3100 handshake(ssl::stream_base::server); // HTTPS servers read first
3101 if (fUseSSL) return stream.read_some(asio::buffer(s, n));
3102 return stream.next_layer().read_some(asio::buffer(s, n));
3104 std::streamsize write(const char* s, std::streamsize n)
3106 handshake(ssl::stream_base::client); // HTTPS clients write first
3107 if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
3108 return asio::write(stream.next_layer(), asio::buffer(s, n));
3110 bool connect(const std::string& server, const std::string& port)
3112 ip::tcp::resolver resolver(stream.get_io_service());
3113 ip::tcp::resolver::query query(server.c_str(), port.c_str());
3114 ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
3115 ip::tcp::resolver::iterator end;
3116 boost::system::error_code error = asio::error::host_not_found;
3117 while (error && endpoint_iterator != end)
3119 stream.lowest_layer().close();
3120 stream.lowest_layer().connect(*endpoint_iterator++, error);
3128 bool fNeedHandshake;
3133 void ThreadRPCServer(void* parg)
3135 IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
3138 vnThreadsRunning[THREAD_RPCSERVER]++;
3139 ThreadRPCServer2(parg);
3140 vnThreadsRunning[THREAD_RPCSERVER]--;
3142 catch (std::exception& e) {
3143 vnThreadsRunning[THREAD_RPCSERVER]--;
3144 PrintException(&e, "ThreadRPCServer()");
3146 vnThreadsRunning[THREAD_RPCSERVER]--;
3147 PrintException(NULL, "ThreadRPCServer()");
3149 printf("ThreadRPCServer exiting\n");
3152 void ThreadRPCServer2(void* parg)
3154 printf("ThreadRPCServer started\n");
3156 strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
3157 if (mapArgs["-rpcpassword"] == "")
3159 unsigned char rand_pwd[32];
3160 RAND_bytes(rand_pwd, 32);
3161 string strWhatAmI = "To use novacoind";
3162 if (mapArgs.count("-server"))
3163 strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
3164 else if (mapArgs.count("-daemon"))
3165 strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
3166 ThreadSafeMessageBox(strprintf(
3167 _("%s, you must set a rpcpassword in the configuration file:\n %s\n"
3168 "It is recommended you use the following random password:\n"
3171 "(you do not need to remember this password)\n"
3172 "If the file does not exist, create it with owner-readable-only file permissions.\n"),
3174 GetConfigFile().string().c_str(),
3175 EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str()),
3176 _("Error"), wxOK | wxMODAL);
3181 bool fUseSSL = GetBoolArg("-rpcssl");
3182 asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
3184 asio::io_service io_service;
3185 ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", RPC_PORT));
3186 ip::tcp::acceptor acceptor(io_service);
3189 acceptor.open(endpoint.protocol());
3190 acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
3191 acceptor.bind(endpoint);
3192 acceptor.listen(socket_base::max_connections);
3194 catch(boost::system::system_error &e)
3196 ThreadSafeMessageBox(strprintf(_("An error occured while setting up the RPC port %i for listening: %s"), endpoint.port(), e.what()),
3197 _("Error"), wxOK | wxMODAL);
3202 ssl::context context(io_service, ssl::context::sslv23);
3205 context.set_options(ssl::context::no_sslv2);
3207 filesystem::path pathCertFile(GetArg("-rpcsslcertificatechainfile", "server.cert"));
3208 if (!pathCertFile.is_complete()) pathCertFile = filesystem::path(GetDataDir()) / pathCertFile;
3209 if (filesystem::exists(pathCertFile)) context.use_certificate_chain_file(pathCertFile.string());
3210 else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", pathCertFile.string().c_str());
3212 filesystem::path pathPKFile(GetArg("-rpcsslprivatekeyfile", "server.pem"));
3213 if (!pathPKFile.is_complete()) pathPKFile = filesystem::path(GetDataDir()) / pathPKFile;
3214 if (filesystem::exists(pathPKFile)) context.use_private_key_file(pathPKFile.string(), ssl::context::pem);
3215 else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pathPKFile.string().c_str());
3217 string strCiphers = GetArg("-rpcsslciphers", "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
3218 SSL_CTX_set_cipher_list(context.impl(), strCiphers.c_str());
3223 // Accept connection
3224 SSLStream sslStream(io_service, context);
3225 SSLIOStreamDevice d(sslStream, fUseSSL);
3226 iostreams::stream<SSLIOStreamDevice> stream(d);
3228 ip::tcp::endpoint peer;
3229 vnThreadsRunning[THREAD_RPCSERVER]--;
3230 acceptor.accept(sslStream.lowest_layer(), peer);
3231 vnThreadsRunning[4]++;
3235 // Restrict callers by IP
3236 if (!ClientAllowed(peer.address().to_string()))
3238 // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
3240 stream << HTTPReply(403, "") << std::flush;
3244 map<string, string> mapHeaders;
3247 boost::thread api_caller(ReadHTTP, boost::ref(stream), boost::ref(mapHeaders), boost::ref(strRequest));
3248 if (!api_caller.timed_join(boost::posix_time::seconds(GetArg("-rpctimeout", 30))))
3251 printf("ThreadRPCServer ReadHTTP timeout\n");
3255 // Check authorization
3256 if (mapHeaders.count("authorization") == 0)
3258 stream << HTTPReply(401, "") << std::flush;
3261 if (!HTTPAuthorized(mapHeaders))
3263 printf("ThreadRPCServer incorrect password attempt from %s\n",peer.address().to_string().c_str());
3264 /* Deter brute-forcing short passwords.
3265 If this results in a DOS the user really
3266 shouldn't have their RPC port exposed.*/
3267 if (mapArgs["-rpcpassword"].size() < 20)
3270 stream << HTTPReply(401, "") << std::flush;
3274 Value id = Value::null;
3279 if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
3280 throw JSONRPCError(-32700, "Parse error");
3281 const Object& request = valRequest.get_obj();
3283 // Parse id now so errors from here on will have the id
3284 id = find_value(request, "id");
3287 Value valMethod = find_value(request, "method");
3288 if (valMethod.type() == null_type)
3289 throw JSONRPCError(-32600, "Missing method");
3290 if (valMethod.type() != str_type)
3291 throw JSONRPCError(-32600, "Method must be a string");
3292 string strMethod = valMethod.get_str();
3293 if (strMethod != "getwork" && strMethod != "getmemorypool")
3294 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
3297 Value valParams = find_value(request, "params");
3299 if (valParams.type() == array_type)
3300 params = valParams.get_array();
3301 else if (valParams.type() == null_type)
3304 throw JSONRPCError(-32600, "Params must be an array");
3307 const CRPCCommand *pcmd = tableRPC[strMethod];
3309 throw JSONRPCError(-32601, "Method not found");
3311 // Observe safe mode
3312 string strWarning = GetWarnings("rpc");
3313 if (strWarning != "" && !GetBoolArg("-disablesafemode") &&
3315 throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
3322 LOCK2(cs_main, pwalletMain->cs_wallet);
3323 result = pcmd->actor(params, false);
3327 string strReply = JSONRPCReply(result, Value::null, id);
3328 stream << HTTPReply(200, strReply) << std::flush;
3330 catch (std::exception& e)
3332 ErrorReply(stream, JSONRPCError(-1, e.what()), id);
3335 catch (Object& objError)
3337 ErrorReply(stream, objError, id);
3339 catch (std::exception& e)
3341 ErrorReply(stream, JSONRPCError(-32700, e.what()), id);
3349 Object CallRPC(const string& strMethod, const Array& params)
3351 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
3352 throw runtime_error(strprintf(
3353 _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
3354 "If the file does not exist, create it with owner-readable-only file permissions."),
3355 GetConfigFile().string().c_str()));
3357 // Connect to localhost
3358 bool fUseSSL = GetBoolArg("-rpcssl");
3359 asio::io_service io_service;
3360 ssl::context context(io_service, ssl::context::sslv23);
3361 context.set_options(ssl::context::no_sslv2);
3362 SSLStream sslStream(io_service, context);
3363 SSLIOStreamDevice d(sslStream, fUseSSL);
3364 iostreams::stream<SSLIOStreamDevice> stream(d);
3365 if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", CBigNum(RPC_PORT).ToString().c_str())))
3366 throw runtime_error("couldn't connect to server");
3368 // HTTP basic authentication
3369 string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
3370 map<string, string> mapRequestHeaders;
3371 mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
3374 string strRequest = JSONRPCRequest(strMethod, params, 1);
3375 string strPost = HTTPPost(strRequest, mapRequestHeaders);
3376 stream << strPost << std::flush;
3379 map<string, string> mapHeaders;
3381 int nStatus = ReadHTTP(stream, mapHeaders, strReply);
3383 throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
3384 else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
3385 throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
3386 else if (strReply.empty())
3387 throw runtime_error("no response from server");
3391 if (!read_string(strReply, valReply))
3392 throw runtime_error("couldn't parse reply from server");
3393 const Object& reply = valReply.get_obj();
3395 throw runtime_error("expected reply to have result, error and id properties");
3403 template<typename T>
3404 void ConvertTo(Value& value)
3406 if (value.type() == str_type)
3408 // reinterpret string as unquoted json value
3410 if (!read_string(value.get_str(), value2))
3411 throw runtime_error("type mismatch");
3412 value = value2.get_value<T>();
3416 value = value.get_value<T>();
3420 int CommandLineRPC(int argc, char *argv[])
3427 while (argc > 1 && IsSwitchChar(argv[1][0]))
3435 throw runtime_error("too few parameters");
3436 string strMethod = argv[1];
3438 // Parameters default to strings
3440 for (int i = 2; i < argc; i++)
3441 params.push_back(argv[i]);
3442 int n = params.size();
3445 // Special case non-string parameter types
3447 if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
3448 if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
3449 if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
3450 if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]);
3451 if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
3452 if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]);
3453 if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
3454 if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
3455 if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]);
3456 if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
3457 if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]);
3458 if (strMethod == "getblockhash" && n > 0) ConvertTo<boost::int64_t>(params[0]);
3459 if (strMethod == "getblockbynumber" && n > 0) ConvertTo<boost::int64_t>(params[0]);
3460 if (strMethod == "getblockbynumber" && n > 1) ConvertTo<bool>(params[1]);
3461 if (strMethod == "getblock" && n > 1) ConvertTo<bool>(params[1]);
3462 if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]);
3463 if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]);
3464 if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]);
3465 if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]);
3466 if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
3467 if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]);
3468 if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]);
3469 if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]);
3470 if (strMethod == "walletpassphrase" && n > 2) ConvertTo<bool>(params[2]);
3471 if (strMethod == "listsinceblock" && n > 1) ConvertTo<boost::int64_t>(params[1]);
3472 if (strMethod == "sendalert" && n > 2) ConvertTo<boost::int64_t>(params[2]);
3473 if (strMethod == "sendalert" && n > 3) ConvertTo<boost::int64_t>(params[3]);
3474 if (strMethod == "sendalert" && n > 4) ConvertTo<boost::int64_t>(params[4]);
3475 if (strMethod == "sendalert" && n > 5) ConvertTo<boost::int64_t>(params[5]);
3476 if (strMethod == "sendalert" && n > 6) ConvertTo<boost::int64_t>(params[6]);
3477 if (strMethod == "sendmany" && n > 1)
3479 string s = params[1].get_str();
3481 if (!read_string(s, v) || v.type() != obj_type)
3482 throw runtime_error("type mismatch");
3483 params[1] = v.get_obj();
3485 if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]);
3486 if (strMethod == "reservebalance" && n > 0) ConvertTo<bool>(params[0]);
3487 if (strMethod == "reservebalance" && n > 1) ConvertTo<double>(params[1]);
3488 if (strMethod == "addmultisigaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
3489 if (strMethod == "addmultisigaddress" && n > 1)
3491 string s = params[1].get_str();
3493 if (!read_string(s, v) || v.type() != array_type)
3494 throw runtime_error("type mismatch "+s);
3495 params[1] = v.get_array();
3499 Object reply = CallRPC(strMethod, params);
3502 const Value& result = find_value(reply, "result");
3503 const Value& error = find_value(reply, "error");
3505 if (error.type() != null_type)
3508 strPrint = "error: " + write_string(error, false);
3509 int code = find_value(error.get_obj(), "code").get_int();
3515 if (result.type() == null_type)
3517 else if (result.type() == str_type)
3518 strPrint = result.get_str();
3520 strPrint = write_string(result, true);
3523 catch (std::exception& e)
3525 strPrint = string("error: ") + e.what();
3530 PrintException(NULL, "CommandLineRPC()");
3535 fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
3544 int main(int argc, char *argv[])
3547 // Turn off microsoft heap dump noise
3548 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
3549 _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
3551 setbuf(stdin, NULL);
3552 setbuf(stdout, NULL);
3553 setbuf(stderr, NULL);
3557 if (argc >= 2 && string(argv[1]) == "-server")
3559 printf("server ready\n");
3560 ThreadRPCServer(NULL);
3564 return CommandLineRPC(argc, argv);
3567 catch (std::exception& e) {
3568 PrintException(&e, "main()");
3570 PrintException(NULL, "main()");
3576 const CRPCTable tableRPC;