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]));
1960 Value getwork(const Array& params, bool fHelp)
1962 if (fHelp || params.size() > 1)
1963 throw runtime_error(
1965 "If [data] is not specified, returns formatted hash data to work on:\n"
1966 " \"midstate\" : precomputed hash state after hashing the first half of the data (DEPRECATED)\n" // deprecated
1967 " \"data\" : block data\n"
1968 " \"hash1\" : formatted hash buffer for second hash (DEPRECATED)\n" // deprecated
1969 " \"target\" : little endian hash target\n"
1970 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1973 throw JSONRPCError(-9, "NovaCoin is not connected!");
1975 if (IsInitialBlockDownload())
1976 throw JSONRPCError(-10, "NovaCoin is downloading blocks...");
1978 typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
1979 static mapNewBlock_t mapNewBlock;
1980 static vector<CBlock*> vNewBlock;
1981 static CReserveKey reservekey(pwalletMain);
1983 if (params.size() == 0)
1986 static unsigned int nTransactionsUpdatedLast;
1987 static CBlockIndex* pindexPrev;
1988 static int64 nStart;
1989 static CBlock* pblock;
1990 if (pindexPrev != pindexBest ||
1991 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
1993 if (pindexPrev != pindexBest)
1995 // Deallocate old blocks since they're obsolete now
1996 mapNewBlock.clear();
1997 BOOST_FOREACH(CBlock* pblock, vNewBlock)
2001 nTransactionsUpdatedLast = nTransactionsUpdated;
2002 pindexPrev = pindexBest;
2006 pblock = CreateNewBlock(pwalletMain);
2008 throw JSONRPCError(-7, "Out of memory");
2009 vNewBlock.push_back(pblock);
2013 pblock->UpdateTime(pindexPrev);
2016 // Update nExtraNonce
2017 static unsigned int nExtraNonce = 0;
2018 IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
2021 mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
2023 // Prebuild hash buffers
2027 FormatHashBuffers(pblock, pmidstate, pdata, phash1);
2029 uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
2032 result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate)))); // deprecated
2033 result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata))));
2034 result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1)))); // deprecated
2035 result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
2041 vector<unsigned char> vchData = ParseHex(params[0].get_str());
2042 if (vchData.size() != 128)
2043 throw JSONRPCError(-8, "Invalid parameter");
2044 CBlock* pdata = (CBlock*)&vchData[0];
2047 for (int i = 0; i < 128/4; i++)
2048 ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]);
2051 if (!mapNewBlock.count(pdata->hashMerkleRoot))
2053 CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
2055 pblock->nTime = pdata->nTime;
2056 pblock->nNonce = pdata->nNonce;
2057 pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
2058 pblock->hashMerkleRoot = pblock->BuildMerkleTree();
2059 if (!pblock->SignBlock(*pwalletMain))
2060 throw JSONRPCError(-100, "Unable to sign block, wallet locked?");
2062 return CheckWork(pblock, *pwalletMain, reservekey);
2066 Value getblocktemplate(const Array& params, bool fHelp)
2068 if (fHelp || params.size() > 1)
2069 throw runtime_error(
2070 "getblocktemplate [params]\n"
2071 "Returns data needed to construct a block to work on:\n"
2072 " \"version\" : block version\n"
2073 " \"previousblockhash\" : hash of current highest block\n"
2074 " \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
2075 " \"coinbaseaux\" : data that should be included in coinbase\n"
2076 " \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
2077 " \"target\" : hash target\n"
2078 " \"mintime\" : minimum timestamp appropriate for next block\n"
2079 " \"curtime\" : current timestamp\n"
2080 " \"mutable\" : list of ways the block template may be changed\n"
2081 " \"noncerange\" : range of valid nonces\n"
2082 " \"sigoplimit\" : limit of sigops in blocks\n"
2083 " \"sizelimit\" : limit of block size\n"
2084 " \"bits\" : compressed target of next block\n"
2085 " \"height\" : height of the next block\n"
2086 "See https://en.bitcoin.it/wiki/BIP_0022 for full specification.");
2088 std::string strMode = "template";
2089 if (params.size() > 0)
2091 const Object& oparam = params[0].get_obj();
2092 const Value& modeval = find_value(oparam, "mode");
2093 if (modeval.type() == str_type)
2094 strMode = modeval.get_str();
2096 throw JSONRPCError(-8, "Invalid mode");
2099 if (strMode != "template")
2100 throw JSONRPCError(-8, "Invalid mode");
2103 throw JSONRPCError(-9, "NovaCoin is not connected!");
2105 if (IsInitialBlockDownload())
2106 throw JSONRPCError(-10, "NovaCoin is downloading blocks...");
2108 static CReserveKey reservekey(pwalletMain);
2111 static unsigned int nTransactionsUpdatedLast;
2112 static CBlockIndex* pindexPrev;
2113 static int64 nStart;
2114 static CBlock* pblock;
2115 if (pindexPrev != pindexBest ||
2116 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5))
2118 // Clear pindexPrev so future calls make a new block, despite any failures from here on
2121 // Store the pindexBest used before CreateNewBlock, to avoid races
2122 nTransactionsUpdatedLast = nTransactionsUpdated;
2123 CBlockIndex* pindexPrevNew = pindexBest;
2132 pblock = CreateNewBlock(pwalletMain);
2134 throw JSONRPCError(-7, "Out of memory");
2136 // Need to update only after we know CreateNewBlock succeeded
2137 pindexPrev = pindexPrevNew;
2141 pblock->UpdateTime(pindexPrev);
2145 map<uint256, int64_t> setTxIndex;
2148 BOOST_FOREACH (CTransaction& tx, pblock->vtx)
2150 uint256 txHash = tx.GetHash();
2151 setTxIndex[txHash] = i++;
2153 if (tx.IsCoinBase() || tx.IsCoinStake())
2158 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
2160 entry.push_back(Pair("data", HexStr(ssTx.begin(), ssTx.end())));
2162 entry.push_back(Pair("hash", txHash.GetHex()));
2164 MapPrevTx mapInputs;
2165 map<uint256, CTxIndex> mapUnused;
2166 bool fInvalid = false;
2167 if (tx.FetchInputs(txdb, mapUnused, false, false, mapInputs, fInvalid))
2169 entry.push_back(Pair("fee", (int64_t)(tx.GetValueIn(mapInputs) - tx.GetValueOut())));
2172 BOOST_FOREACH (MapPrevTx::value_type& inp, mapInputs)
2174 if (setTxIndex.count(inp.first))
2175 deps.push_back(setTxIndex[inp.first]);
2177 entry.push_back(Pair("depends", deps));
2179 int64_t nSigOps = tx.GetLegacySigOpCount();
2180 nSigOps += tx.GetP2SHSigOpCount(mapInputs);
2181 entry.push_back(Pair("sigops", nSigOps));
2184 transactions.push_back(entry);
2188 aux.push_back(Pair("flags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end())));
2190 uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
2192 static Array aMutable;
2193 if (aMutable.empty())
2195 aMutable.push_back("time");
2196 aMutable.push_back("transactions");
2197 aMutable.push_back("prevblock");
2201 result.push_back(Pair("version", pblock->nVersion));
2202 result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
2203 result.push_back(Pair("transactions", transactions));
2204 result.push_back(Pair("coinbaseaux", aux));
2205 result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
2206 result.push_back(Pair("target", hashTarget.GetHex()));
2207 result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1));
2208 result.push_back(Pair("mutable", aMutable));
2209 result.push_back(Pair("noncerange", "00000000ffffffff"));
2210 result.push_back(Pair("sigoplimit", (int64_t)MAX_BLOCK_SIGOPS));
2211 result.push_back(Pair("sizelimit", (int64_t)MAX_BLOCK_SIZE));
2212 result.push_back(Pair("curtime", (int64_t)pblock->nTime));
2213 result.push_back(Pair("bits", HexBits(pblock->nBits)));
2214 result.push_back(Pair("height", (int64_t)(pindexPrev->nHeight+1)));
2219 Value submitblock(const Array& params, bool fHelp)
2221 if (fHelp || params.size() < 1 || params.size() > 2)
2222 throw runtime_error(
2223 "submitblock <hex data> [optional-params-obj]\n"
2224 "[optional-params-obj] parameter is currently ignored.\n"
2225 "Attempts to submit new block to network.\n"
2226 "See https://en.bitcoin.it/wiki/BIP_0022 for full specification.");
2228 vector<unsigned char> blockData(ParseHex(params[0].get_str()));
2229 CDataStream ssBlock(blockData, SER_NETWORK, PROTOCOL_VERSION);
2234 catch (std::exception &e) {
2235 throw JSONRPCError(-22, "Block decode failed");
2238 static CReserveKey reservekey(pwalletMain);
2240 if(!block.SignBlock(*pwalletMain))
2241 throw JSONRPCError(-100, "Unable to sign block, wallet locked?");
2243 bool fAccepted = CheckWork(&block, *pwalletMain, reservekey);
2251 Value getmemorypool(const Array& params, bool fHelp)
2253 if (fHelp || params.size() > 1)
2254 throw runtime_error(
2255 "getmemorypool [data]\n"
2256 "If [data] is not specified, returns data needed to construct a block to work on:\n"
2257 " \"version\" : block version\n"
2258 " \"previousblockhash\" : hash of current highest block\n"
2259 " \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
2260 " \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
2261 " \"coinbaseflags\" : data that should be included in coinbase so support for new features can be judged\n"
2262 " \"time\" : timestamp appropriate for next block\n"
2263 " \"mintime\" : minimum timestamp appropriate for next block\n"
2264 " \"curtime\" : current timestamp\n"
2265 " \"bits\" : compressed target of next block\n"
2266 "If [data] is specified, tries to solve the block and returns true if it was successful.");
2268 if (params.size() == 0)
2271 throw JSONRPCError(-9, "NovaCoin is not connected!");
2273 if (IsInitialBlockDownload())
2274 throw JSONRPCError(-10, "NovaCoin is downloading blocks...");
2276 static CReserveKey reservekey(pwalletMain);
2279 static unsigned int nTransactionsUpdatedLast;
2280 static CBlockIndex* pindexPrev;
2281 static int64 nStart;
2282 static CBlock* pblock;
2283 if (pindexPrev != pindexBest ||
2284 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5))
2286 nTransactionsUpdatedLast = nTransactionsUpdated;
2287 pindexPrev = pindexBest;
2293 pblock = CreateNewBlock(pwalletMain);
2295 throw JSONRPCError(-7, "Out of memory");
2299 pblock->UpdateTime(pindexPrev);
2303 BOOST_FOREACH(CTransaction tx, pblock->vtx) {
2304 if(tx.IsCoinBase() || tx.IsCoinStake())
2307 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
2310 transactions.push_back(HexStr(ssTx.begin(), ssTx.end()));
2314 result.push_back(Pair("version", pblock->nVersion));
2315 result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
2316 result.push_back(Pair("transactions", transactions));
2317 result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
2318 result.push_back(Pair("coinbaseflags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end())));
2319 result.push_back(Pair("time", (int64_t)pblock->nTime));
2320 result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1));
2321 result.push_back(Pair("curtime", (int64_t)GetAdjustedTime()));
2322 result.push_back(Pair("bits", HexBits(pblock->nBits)));
2329 CDataStream ssBlock(ParseHex(params[0].get_str()), SER_NETWORK, PROTOCOL_VERSION);
2333 static CReserveKey reservekey(pwalletMain);
2335 if(!pblock.SignBlock(*pwalletMain))
2336 throw JSONRPCError(-100, "Unable to sign block, wallet locked?");
2338 return CheckWork(&pblock, *pwalletMain, reservekey);
2342 Value getnewpubkey(const Array& params, bool fHelp)
2344 if (fHelp || params.size() > 1)
2345 throw runtime_error(
2346 "getnewpubkey [account]\n"
2347 "Returns new public key for coinbase generation.");
2349 // Parse the account first so we don't generate a key if there's an error
2351 if (params.size() > 0)
2352 strAccount = AccountFromValue(params[0]);
2354 if (!pwalletMain->IsLocked())
2355 pwalletMain->TopUpKeyPool();
2357 // Generate a new key that is added to wallet
2358 std::vector<unsigned char> newKey = pwalletMain->GenerateNewKey(true);
2361 throw JSONRPCError(-12, "Error: Unable to create key");
2363 CBitcoinAddress address(newKey);
2364 pwalletMain->SetAddressBookName(address, strAccount);
2366 return HexStr(newKey.begin(), newKey.end());
2369 Value getblockhash(const Array& params, bool fHelp)
2371 if (fHelp || params.size() != 1)
2372 throw runtime_error(
2373 "getblockhash <index>\n"
2374 "Returns hash of block in best-block-chain at <index>.");
2376 int nHeight = params[0].get_int();
2377 if (nHeight < 0 || nHeight > nBestHeight)
2378 throw runtime_error("Block number out of range.");
2381 CBlockIndex* pblockindex = mapBlockIndex[hashBestChain];
2382 while (pblockindex->nHeight > nHeight)
2383 pblockindex = pblockindex->pprev;
2384 return pblockindex->phashBlock->GetHex();
2387 Value getblock(const Array& params, bool fHelp)
2389 if (fHelp || params.size() < 1 || params.size() > 2)
2390 throw runtime_error(
2391 "getblock <hash> [txinfo]\n"
2392 "txinfo optional to print more detailed tx info\n"
2393 "Returns details of a block with given block-hash.");
2395 std::string strHash = params[0].get_str();
2396 uint256 hash(strHash);
2398 if (mapBlockIndex.count(hash) == 0)
2399 throw JSONRPCError(-5, "Block not found");
2402 CBlockIndex* pblockindex = mapBlockIndex[hash];
2403 block.ReadFromDisk(pblockindex, true);
2405 return blockToJSON(block, pblockindex, params.size() > 1 ? params[1].get_bool() : false);
2408 Value getblockbynumber(const Array& params, bool fHelp)
2410 if (fHelp || params.size() < 1 || params.size() > 2)
2411 throw runtime_error(
2412 "getblock <number> [txinfo]\n"
2413 "txinfo optional to print more detailed tx info\n"
2414 "Returns details of a block with given block-number.");
2416 int nHeight = params[0].get_int();
2417 if (nHeight < 0 || nHeight > nBestHeight)
2418 throw runtime_error("Block number out of range.");
2421 CBlockIndex* pblockindex = mapBlockIndex[hashBestChain];
2422 while (pblockindex->nHeight > nHeight)
2423 pblockindex = pblockindex->pprev;
2425 uint256 hash = *pblockindex->phashBlock;
2427 pblockindex = mapBlockIndex[hash];
2428 block.ReadFromDisk(pblockindex, true);
2430 return blockToJSON(block, pblockindex, params.size() > 1 ? params[1].get_bool() : false);
2433 // ppcoin: get information of sync-checkpoint
2434 Value getcheckpoint(const Array& params, bool fHelp)
2436 if (fHelp || params.size() != 0)
2437 throw runtime_error(
2439 "Show info of synchronized checkpoint.\n");
2442 CBlockIndex* pindexCheckpoint;
2444 result.push_back(Pair("synccheckpoint", Checkpoints::hashSyncCheckpoint.ToString().c_str()));
2445 pindexCheckpoint = mapBlockIndex[Checkpoints::hashSyncCheckpoint];
2446 result.push_back(Pair("height", pindexCheckpoint->nHeight));
2447 result.push_back(Pair("timestamp", DateTimeStrFormat(pindexCheckpoint->GetBlockTime()).c_str()));
2448 if (mapArgs.count("-checkpointkey"))
2449 result.push_back(Pair("checkpointmaster", true));
2455 // ppcoin: reserve balance from being staked for network protection
2456 Value reservebalance(const Array& params, bool fHelp)
2458 if (fHelp || params.size() > 2)
2459 throw runtime_error(
2460 "reservebalance [<reserve> [amount]]\n"
2461 "<reserve> is true or false to turn balance reserve on or off.\n"
2462 "<amount> is a real and rounded to cent.\n"
2463 "Set reserve amount not participating in network protection.\n"
2464 "If no parameters provided current setting is printed.\n");
2466 if (params.size() > 0)
2468 bool fReserve = params[0].get_bool();
2471 if (params.size() == 1)
2472 throw runtime_error("must provide amount to reserve balance.\n");
2473 int64 nAmount = AmountFromValue(params[1]);
2474 nAmount = (nAmount / CENT) * CENT; // round to cent
2476 throw runtime_error("amount cannot be negative.\n");
2477 mapArgs["-reservebalance"] = FormatMoney(nAmount).c_str();
2481 if (params.size() > 1)
2482 throw runtime_error("cannot specify amount to turn off reserve.\n");
2483 mapArgs["-reservebalance"] = "0";
2488 int64 nReserveBalance = 0;
2489 if (mapArgs.count("-reservebalance") && !ParseMoney(mapArgs["-reservebalance"], nReserveBalance))
2490 throw runtime_error("invalid reserve balance amount\n");
2491 result.push_back(Pair("reserve", (nReserveBalance > 0)));
2492 result.push_back(Pair("amount", ValueFromAmount(nReserveBalance)));
2497 // ppcoin: check wallet integrity
2498 Value checkwallet(const Array& params, bool fHelp)
2500 if (fHelp || params.size() > 0)
2501 throw runtime_error(
2503 "Check wallet for integrity.\n");
2506 int64 nBalanceInQuestion;
2507 pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion, true);
2509 if (nMismatchSpent == 0)
2510 result.push_back(Pair("wallet check passed", true));
2513 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
2514 result.push_back(Pair("amount in question", ValueFromAmount(nBalanceInQuestion)));
2520 // ppcoin: repair wallet
2521 Value repairwallet(const Array& params, bool fHelp)
2523 if (fHelp || params.size() > 0)
2524 throw runtime_error(
2526 "Repair wallet if checkwallet reports any problem.\n");
2529 int64 nBalanceInQuestion;
2530 pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion);
2532 if (nMismatchSpent == 0)
2533 result.push_back(Pair("wallet check passed", true));
2536 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
2537 result.push_back(Pair("amount affected by repair", ValueFromAmount(nBalanceInQuestion)));
2542 // NovaCoin: resend unconfirmed wallet transactions
2543 Value resendtx(const Array& params, bool fHelp)
2545 if (fHelp || params.size() > 1)
2546 throw runtime_error(
2548 "Re-send unconfirmed transactions.\n"
2551 ResendWalletTransactions();
2557 // ppcoin: make a public-private key pair
2558 Value makekeypair(const Array& params, bool fHelp)
2560 if (fHelp || params.size() > 1)
2561 throw runtime_error(
2562 "makekeypair [prefix]\n"
2563 "Make a public/private key pair.\n"
2564 "[prefix] is optional preferred prefix for the public key.\n");
2566 string strPrefix = "";
2567 if (params.size() > 0)
2568 strPrefix = params[0].get_str();
2574 key.MakeNewKey(false);
2576 } while (nCount < 10000 && strPrefix != HexStr(key.GetPubKey()).substr(0, strPrefix.size()));
2578 if (strPrefix != HexStr(key.GetPubKey()).substr(0, strPrefix.size()))
2581 CPrivKey vchPrivKey = key.GetPrivKey();
2583 result.push_back(Pair("PrivateKey", HexStr<CPrivKey::iterator>(vchPrivKey.begin(), vchPrivKey.end())));
2584 result.push_back(Pair("PublicKey", HexStr(key.GetPubKey())));
2588 extern CCriticalSection cs_mapAlerts;
2589 extern map<uint256, CAlert> mapAlerts;
2591 // ppcoin: send alert.
2592 // There is a known deadlock situation with ThreadMessageHandler
2593 // ThreadMessageHandler: holds cs_vSend and acquiring cs_main in SendMessages()
2594 // ThreadRPCServer: holds cs_main and acquiring cs_vSend in alert.RelayTo()/PushMessage()/BeginMessage()
2595 Value sendalert(const Array& params, bool fHelp)
2597 if (fHelp || params.size() < 6)
2598 throw runtime_error(
2599 "sendalert <message> <privatekey> <minver> <maxver> <priority> <id> [cancelupto]\n"
2600 "<message> is the alert text message\n"
2601 "<privatekey> is hex string of alert master private key\n"
2602 "<minver> is the minimum applicable internal client version\n"
2603 "<maxver> is the maximum applicable internal client version\n"
2604 "<priority> is integer priority number\n"
2605 "<id> is the alert id\n"
2606 "[cancelupto] cancels all alert id's up to this number\n"
2607 "Returns true or false.");
2612 alert.strStatusBar = params[0].get_str();
2613 alert.nMinVer = params[2].get_int();
2614 alert.nMaxVer = params[3].get_int();
2615 alert.nPriority = params[4].get_int();
2616 alert.nID = params[5].get_int();
2617 if (params.size() > 6)
2618 alert.nCancel = params[6].get_int();
2619 alert.nVersion = PROTOCOL_VERSION;
2620 alert.nRelayUntil = GetAdjustedTime() + 365*24*60*60;
2621 alert.nExpiration = GetAdjustedTime() + 365*24*60*60;
2623 CDataStream sMsg(SER_NETWORK, PROTOCOL_VERSION);
2624 sMsg << (CUnsignedAlert)alert;
2625 alert.vchMsg = vector<unsigned char>(sMsg.begin(), sMsg.end());
2627 vector<unsigned char> vchPrivKey = ParseHex(params[1].get_str());
2628 key.SetPrivKey(CPrivKey(vchPrivKey.begin(), vchPrivKey.end())); // if key is not correct openssl may crash
2629 if (!key.Sign(Hash(alert.vchMsg.begin(), alert.vchMsg.end()), alert.vchSig))
2630 throw runtime_error(
2631 "Unable to sign alert, check private key?\n");
2632 if(!alert.ProcessAlert())
2633 throw runtime_error(
2634 "Failed to process alert.\n");
2638 BOOST_FOREACH(CNode* pnode, vNodes)
2639 alert.RelayTo(pnode);
2643 result.push_back(Pair("strStatusBar", alert.strStatusBar));
2644 result.push_back(Pair("nVersion", alert.nVersion));
2645 result.push_back(Pair("nMinVer", alert.nMinVer));
2646 result.push_back(Pair("nMaxVer", alert.nMaxVer));
2647 result.push_back(Pair("nPriority", alert.nPriority));
2648 result.push_back(Pair("nID", alert.nID));
2649 if (alert.nCancel > 0)
2650 result.push_back(Pair("nCancel", alert.nCancel));
2661 static const CRPCCommand vRPCCommands[] =
2662 { // name function safe mode?
2663 // ------------------------ ----------------------- ----------
2664 { "help", &help, true },
2665 { "stop", &stop, true },
2666 { "getblockcount", &getblockcount, true },
2667 { "getblocknumber", &getblocknumber, true },
2668 { "getconnectioncount", &getconnectioncount, true },
2669 { "getdifficulty", &getdifficulty, true },
2670 { "getpowreward", &getpowreward, true },
2671 { "getgenerate", &getgenerate, true },
2672 { "setgenerate", &setgenerate, true },
2673 { "gethashespersec", &gethashespersec, true },
2674 { "getinfo", &getinfo, true },
2675 { "getmininginfo", &getmininginfo, true },
2676 { "getnewaddress", &getnewaddress, true },
2677 { "getnewpubkey", &getnewpubkey, true },
2678 { "getaccountaddress", &getaccountaddress, true },
2679 { "setaccount", &setaccount, true },
2680 { "getaccount", &getaccount, false },
2681 { "getaddressesbyaccount", &getaddressesbyaccount, true },
2682 { "sendtoaddress", &sendtoaddress, false },
2683 { "getreceivedbyaddress", &getreceivedbyaddress, false },
2684 { "getreceivedbyaccount", &getreceivedbyaccount, false },
2685 { "listreceivedbyaddress", &listreceivedbyaddress, false },
2686 { "listreceivedbyaccount", &listreceivedbyaccount, false },
2687 { "backupwallet", &backupwallet, true },
2688 { "keypoolrefill", &keypoolrefill, true },
2689 { "walletpassphrase", &walletpassphrase, true },
2690 { "walletpassphrasechange", &walletpassphrasechange, false },
2691 { "walletlock", &walletlock, true },
2692 { "encryptwallet", &encryptwallet, false },
2693 { "validateaddress", &validateaddress, true },
2694 { "validatepubkey", &validatepubkey, true },
2695 { "getbalance", &getbalance, false },
2696 { "move", &movecmd, false },
2697 { "sendfrom", &sendfrom, false },
2698 { "sendmany", &sendmany, false },
2699 { "addmultisigaddress", &addmultisigaddress, false },
2700 { "getblock", &getblock, false },
2701 { "getblockhash", &getblockhash, false },
2702 { "getblockbynumber", &getblockbynumber, false },
2703 { "gettransaction", &gettransaction, false },
2704 { "listtransactions", &listtransactions, false },
2705 { "signmessage", &signmessage, false },
2706 { "verifymessage", &verifymessage, false },
2707 { "getwork", &getwork, true },
2708 { "listaccounts", &listaccounts, false },
2709 { "settxfee", &settxfee, false },
2710 { "getmemorypool", &getmemorypool, true },
2711 { "getblocktemplate", &getblocktemplate, true },
2712 { "submitblock", &submitblock, false },
2713 { "listsinceblock", &listsinceblock, false },
2714 { "dumpprivkey", &dumpprivkey, false },
2715 { "importprivkey", &importprivkey, false },
2716 { "getcheckpoint", &getcheckpoint, true },
2717 { "reservebalance", &reservebalance, false},
2718 { "checkwallet", &checkwallet, false},
2719 { "repairwallet", &repairwallet, false},
2720 { "resendtx", &resendtx, false},
2721 { "makekeypair", &makekeypair, false},
2722 { "sendalert", &sendalert, false},
2725 CRPCTable::CRPCTable()
2728 for (vcidx = 0; vcidx < (sizeof(vRPCCommands) / sizeof(vRPCCommands[0])); vcidx++)
2730 const CRPCCommand *pcmd;
2732 pcmd = &vRPCCommands[vcidx];
2733 mapCommands[pcmd->name] = pcmd;
2737 const CRPCCommand *CRPCTable::operator[](string name) const
2739 map<string, const CRPCCommand*>::const_iterator it = mapCommands.find(name);
2740 if (it == mapCommands.end())
2742 return (*it).second;
2748 // This ain't Apache. We're just using HTTP header for the length field
2749 // and to be compatible with other JSON-RPC implementations.
2752 string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
2755 s << "POST / HTTP/1.1\r\n"
2756 << "User-Agent: novacoin-json-rpc/" << FormatFullVersion() << "\r\n"
2757 << "Host: 127.0.0.1\r\n"
2758 << "Content-Type: application/json\r\n"
2759 << "Content-Length: " << strMsg.size() << "\r\n"
2760 << "Connection: close\r\n"
2761 << "Accept: application/json\r\n";
2762 BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
2763 s << item.first << ": " << item.second << "\r\n";
2764 s << "\r\n" << strMsg;
2769 string rfc1123Time()
2774 struct tm* now_gmt = gmtime(&now);
2775 string locale(setlocale(LC_TIME, NULL));
2776 setlocale(LC_TIME, "C"); // we want posix (aka "C") weekday/month strings
2777 strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt);
2778 setlocale(LC_TIME, locale.c_str());
2779 return string(buffer);
2782 static string HTTPReply(int nStatus, const string& strMsg)
2785 return strprintf("HTTP/1.0 401 Authorization Required\r\n"
2787 "Server: novacoin-json-rpc/%s\r\n"
2788 "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
2789 "Content-Type: text/html\r\n"
2790 "Content-Length: 296\r\n"
2792 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
2793 "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
2796 "<TITLE>Error</TITLE>\r\n"
2797 "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
2799 "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
2800 "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
2801 const char *cStatus;
2802 if (nStatus == 200) cStatus = "OK";
2803 else if (nStatus == 400) cStatus = "Bad Request";
2804 else if (nStatus == 403) cStatus = "Forbidden";
2805 else if (nStatus == 404) cStatus = "Not Found";
2806 else if (nStatus == 500) cStatus = "Internal Server Error";
2809 "HTTP/1.1 %d %s\r\n"
2811 "Connection: close\r\n"
2812 "Content-Length: %d\r\n"
2813 "Content-Type: application/json\r\n"
2814 "Server: novacoin-json-rpc/%s\r\n"
2819 rfc1123Time().c_str(),
2821 FormatFullVersion().c_str(),
2825 int ReadHTTPStatus(std::basic_istream<char>& stream)
2828 getline(stream, str);
2829 vector<string> vWords;
2830 boost::split(vWords, str, boost::is_any_of(" "));
2831 if (vWords.size() < 2)
2833 return atoi(vWords[1].c_str());
2836 int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
2842 std::getline(stream, str);
2843 if (str.empty() || str == "\r")
2845 string::size_type nColon = str.find(":");
2846 if (nColon != string::npos)
2848 string strHeader = str.substr(0, nColon);
2849 boost::trim(strHeader);
2850 boost::to_lower(strHeader);
2851 string strValue = str.substr(nColon+1);
2852 boost::trim(strValue);
2853 mapHeadersRet[strHeader] = strValue;
2854 if (strHeader == "content-length")
2855 nLen = atoi(strValue.c_str());
2861 int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
2863 mapHeadersRet.clear();
2867 int nStatus = ReadHTTPStatus(stream);
2870 int nLen = ReadHTTPHeader(stream, mapHeadersRet);
2871 if (nLen < 0 || nLen > (int)MAX_SIZE)
2877 vector<char> vch(nLen);
2878 stream.read(&vch[0], nLen);
2879 strMessageRet = string(vch.begin(), vch.end());
2885 bool HTTPAuthorized(map<string, string>& mapHeaders)
2887 string strAuth = mapHeaders["authorization"];
2888 if (strAuth.substr(0,6) != "Basic ")
2890 string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
2891 string strUserPass = DecodeBase64(strUserPass64);
2892 return strUserPass == strRPCUserColonPass;
2896 // JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
2897 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
2898 // unspecified (HTTP errors and contents of 'error').
2900 // 1.0 spec: http://json-rpc.org/wiki/specification
2901 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
2902 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
2905 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
2908 request.push_back(Pair("method", strMethod));
2909 request.push_back(Pair("params", params));
2910 request.push_back(Pair("id", id));
2911 return write_string(Value(request), false) + "\n";
2914 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
2917 if (error.type() != null_type)
2918 reply.push_back(Pair("result", Value::null));
2920 reply.push_back(Pair("result", result));
2921 reply.push_back(Pair("error", error));
2922 reply.push_back(Pair("id", id));
2923 return write_string(Value(reply), false) + "\n";
2926 void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
2928 // Send error reply from json-rpc error object
2930 int code = find_value(objError, "code").get_int();
2931 if (code == -32600) nStatus = 400;
2932 else if (code == -32601) nStatus = 404;
2933 string strReply = JSONRPCReply(Value::null, objError, id);
2934 stream << HTTPReply(nStatus, strReply) << std::flush;
2937 bool ClientAllowed(const string& strAddress)
2939 if (strAddress == asio::ip::address_v4::loopback().to_string())
2941 const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
2942 BOOST_FOREACH(string strAllow, vAllow)
2943 if (WildcardMatch(strAddress, strAllow))
2949 // IOStream device that speaks SSL but can also speak non-SSL
2951 class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
2953 SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
2955 fUseSSL = fUseSSLIn;
2956 fNeedHandshake = fUseSSLIn;
2959 void handshake(ssl::stream_base::handshake_type role)
2961 if (!fNeedHandshake) return;
2962 fNeedHandshake = false;
2963 stream.handshake(role);
2965 std::streamsize read(char* s, std::streamsize n)
2967 handshake(ssl::stream_base::server); // HTTPS servers read first
2968 if (fUseSSL) return stream.read_some(asio::buffer(s, n));
2969 return stream.next_layer().read_some(asio::buffer(s, n));
2971 std::streamsize write(const char* s, std::streamsize n)
2973 handshake(ssl::stream_base::client); // HTTPS clients write first
2974 if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
2975 return asio::write(stream.next_layer(), asio::buffer(s, n));
2977 bool connect(const std::string& server, const std::string& port)
2979 ip::tcp::resolver resolver(stream.get_io_service());
2980 ip::tcp::resolver::query query(server.c_str(), port.c_str());
2981 ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
2982 ip::tcp::resolver::iterator end;
2983 boost::system::error_code error = asio::error::host_not_found;
2984 while (error && endpoint_iterator != end)
2986 stream.lowest_layer().close();
2987 stream.lowest_layer().connect(*endpoint_iterator++, error);
2995 bool fNeedHandshake;
3000 void ThreadRPCServer(void* parg)
3002 IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
3005 vnThreadsRunning[THREAD_RPCSERVER]++;
3006 ThreadRPCServer2(parg);
3007 vnThreadsRunning[THREAD_RPCSERVER]--;
3009 catch (std::exception& e) {
3010 vnThreadsRunning[THREAD_RPCSERVER]--;
3011 PrintException(&e, "ThreadRPCServer()");
3013 vnThreadsRunning[THREAD_RPCSERVER]--;
3014 PrintException(NULL, "ThreadRPCServer()");
3016 printf("ThreadRPCServer exiting\n");
3019 void ThreadRPCServer2(void* parg)
3021 printf("ThreadRPCServer started\n");
3023 strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
3024 if (mapArgs["-rpcpassword"] == "")
3026 unsigned char rand_pwd[32];
3027 RAND_bytes(rand_pwd, 32);
3028 string strWhatAmI = "To use novacoind";
3029 if (mapArgs.count("-server"))
3030 strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
3031 else if (mapArgs.count("-daemon"))
3032 strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
3033 ThreadSafeMessageBox(strprintf(
3034 _("%s, you must set a rpcpassword in the configuration file:\n %s\n"
3035 "It is recommended you use the following random password:\n"
3038 "(you do not need to remember this password)\n"
3039 "If the file does not exist, create it with owner-readable-only file permissions.\n"),
3041 GetConfigFile().string().c_str(),
3042 EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str()),
3043 _("Error"), wxOK | wxMODAL);
3048 bool fUseSSL = GetBoolArg("-rpcssl");
3049 asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
3051 asio::io_service io_service;
3052 ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", RPC_PORT));
3053 ip::tcp::acceptor acceptor(io_service);
3056 acceptor.open(endpoint.protocol());
3057 acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
3058 acceptor.bind(endpoint);
3059 acceptor.listen(socket_base::max_connections);
3061 catch(boost::system::system_error &e)
3063 ThreadSafeMessageBox(strprintf(_("An error occured while setting up the RPC port %i for listening: %s"), endpoint.port(), e.what()),
3064 _("Error"), wxOK | wxMODAL);
3069 ssl::context context(io_service, ssl::context::sslv23);
3072 context.set_options(ssl::context::no_sslv2);
3074 filesystem::path pathCertFile(GetArg("-rpcsslcertificatechainfile", "server.cert"));
3075 if (!pathCertFile.is_complete()) pathCertFile = filesystem::path(GetDataDir()) / pathCertFile;
3076 if (filesystem::exists(pathCertFile)) context.use_certificate_chain_file(pathCertFile.string());
3077 else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", pathCertFile.string().c_str());
3079 filesystem::path pathPKFile(GetArg("-rpcsslprivatekeyfile", "server.pem"));
3080 if (!pathPKFile.is_complete()) pathPKFile = filesystem::path(GetDataDir()) / pathPKFile;
3081 if (filesystem::exists(pathPKFile)) context.use_private_key_file(pathPKFile.string(), ssl::context::pem);
3082 else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pathPKFile.string().c_str());
3084 string strCiphers = GetArg("-rpcsslciphers", "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
3085 SSL_CTX_set_cipher_list(context.impl(), strCiphers.c_str());
3090 // Accept connection
3091 SSLStream sslStream(io_service, context);
3092 SSLIOStreamDevice d(sslStream, fUseSSL);
3093 iostreams::stream<SSLIOStreamDevice> stream(d);
3095 ip::tcp::endpoint peer;
3096 vnThreadsRunning[THREAD_RPCSERVER]--;
3097 acceptor.accept(sslStream.lowest_layer(), peer);
3098 vnThreadsRunning[4]++;
3102 // Restrict callers by IP
3103 if (!ClientAllowed(peer.address().to_string()))
3105 // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
3107 stream << HTTPReply(403, "") << std::flush;
3111 map<string, string> mapHeaders;
3114 boost::thread api_caller(ReadHTTP, boost::ref(stream), boost::ref(mapHeaders), boost::ref(strRequest));
3115 if (!api_caller.timed_join(boost::posix_time::seconds(GetArg("-rpctimeout", 30))))
3118 printf("ThreadRPCServer ReadHTTP timeout\n");
3122 // Check authorization
3123 if (mapHeaders.count("authorization") == 0)
3125 stream << HTTPReply(401, "") << std::flush;
3128 if (!HTTPAuthorized(mapHeaders))
3130 printf("ThreadRPCServer incorrect password attempt from %s\n",peer.address().to_string().c_str());
3131 /* Deter brute-forcing short passwords.
3132 If this results in a DOS the user really
3133 shouldn't have their RPC port exposed.*/
3134 if (mapArgs["-rpcpassword"].size() < 20)
3137 stream << HTTPReply(401, "") << std::flush;
3141 Value id = Value::null;
3146 if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
3147 throw JSONRPCError(-32700, "Parse error");
3148 const Object& request = valRequest.get_obj();
3150 // Parse id now so errors from here on will have the id
3151 id = find_value(request, "id");
3154 Value valMethod = find_value(request, "method");
3155 if (valMethod.type() == null_type)
3156 throw JSONRPCError(-32600, "Missing method");
3157 if (valMethod.type() != str_type)
3158 throw JSONRPCError(-32600, "Method must be a string");
3159 string strMethod = valMethod.get_str();
3160 if (strMethod != "getwork" && strMethod != "getmemorypool")
3161 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
3164 Value valParams = find_value(request, "params");
3166 if (valParams.type() == array_type)
3167 params = valParams.get_array();
3168 else if (valParams.type() == null_type)
3171 throw JSONRPCError(-32600, "Params must be an array");
3174 const CRPCCommand *pcmd = tableRPC[strMethod];
3176 throw JSONRPCError(-32601, "Method not found");
3178 // Observe safe mode
3179 string strWarning = GetWarnings("rpc");
3180 if (strWarning != "" && !GetBoolArg("-disablesafemode") &&
3182 throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
3189 LOCK2(cs_main, pwalletMain->cs_wallet);
3190 result = pcmd->actor(params, false);
3194 string strReply = JSONRPCReply(result, Value::null, id);
3195 stream << HTTPReply(200, strReply) << std::flush;
3197 catch (std::exception& e)
3199 ErrorReply(stream, JSONRPCError(-1, e.what()), id);
3202 catch (Object& objError)
3204 ErrorReply(stream, objError, id);
3206 catch (std::exception& e)
3208 ErrorReply(stream, JSONRPCError(-32700, e.what()), id);
3216 Object CallRPC(const string& strMethod, const Array& params)
3218 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
3219 throw runtime_error(strprintf(
3220 _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
3221 "If the file does not exist, create it with owner-readable-only file permissions."),
3222 GetConfigFile().string().c_str()));
3224 // Connect to localhost
3225 bool fUseSSL = GetBoolArg("-rpcssl");
3226 asio::io_service io_service;
3227 ssl::context context(io_service, ssl::context::sslv23);
3228 context.set_options(ssl::context::no_sslv2);
3229 SSLStream sslStream(io_service, context);
3230 SSLIOStreamDevice d(sslStream, fUseSSL);
3231 iostreams::stream<SSLIOStreamDevice> stream(d);
3232 if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", CBigNum(RPC_PORT).ToString().c_str())))
3233 throw runtime_error("couldn't connect to server");
3235 // HTTP basic authentication
3236 string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
3237 map<string, string> mapRequestHeaders;
3238 mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
3241 string strRequest = JSONRPCRequest(strMethod, params, 1);
3242 string strPost = HTTPPost(strRequest, mapRequestHeaders);
3243 stream << strPost << std::flush;
3246 map<string, string> mapHeaders;
3248 int nStatus = ReadHTTP(stream, mapHeaders, strReply);
3250 throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
3251 else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
3252 throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
3253 else if (strReply.empty())
3254 throw runtime_error("no response from server");
3258 if (!read_string(strReply, valReply))
3259 throw runtime_error("couldn't parse reply from server");
3260 const Object& reply = valReply.get_obj();
3262 throw runtime_error("expected reply to have result, error and id properties");
3270 template<typename T>
3271 void ConvertTo(Value& value)
3273 if (value.type() == str_type)
3275 // reinterpret string as unquoted json value
3277 if (!read_string(value.get_str(), value2))
3278 throw runtime_error("type mismatch");
3279 value = value2.get_value<T>();
3283 value = value.get_value<T>();
3287 int CommandLineRPC(int argc, char *argv[])
3294 while (argc > 1 && IsSwitchChar(argv[1][0]))
3302 throw runtime_error("too few parameters");
3303 string strMethod = argv[1];
3305 // Parameters default to strings
3307 for (int i = 2; i < argc; i++)
3308 params.push_back(argv[i]);
3309 int n = params.size();
3312 // Special case non-string parameter types
3314 if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
3315 if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
3316 if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
3317 if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]);
3318 if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
3319 if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]);
3320 if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
3321 if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
3322 if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]);
3323 if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
3324 if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]);
3325 if (strMethod == "getblockhash" && n > 0) ConvertTo<boost::int64_t>(params[0]);
3326 if (strMethod == "getblockbynumber" && n > 0) ConvertTo<boost::int64_t>(params[0]);
3327 if (strMethod == "getblockbynumber" && n > 1) ConvertTo<bool>(params[1]);
3328 if (strMethod == "getblock" && n > 1) ConvertTo<bool>(params[1]);
3329 if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]);
3330 if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]);
3331 if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]);
3332 if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]);
3333 if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
3334 if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]);
3335 if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]);
3336 if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]);
3337 if (strMethod == "walletpassphrase" && n > 2) ConvertTo<bool>(params[2]);
3338 if (strMethod == "listsinceblock" && n > 1) ConvertTo<boost::int64_t>(params[1]);
3339 if (strMethod == "sendalert" && n > 2) ConvertTo<boost::int64_t>(params[2]);
3340 if (strMethod == "sendalert" && n > 3) ConvertTo<boost::int64_t>(params[3]);
3341 if (strMethod == "sendalert" && n > 4) ConvertTo<boost::int64_t>(params[4]);
3342 if (strMethod == "sendalert" && n > 5) ConvertTo<boost::int64_t>(params[5]);
3343 if (strMethod == "sendalert" && n > 6) ConvertTo<boost::int64_t>(params[6]);
3344 if (strMethod == "sendmany" && n > 1)
3346 string s = params[1].get_str();
3348 if (!read_string(s, v) || v.type() != obj_type)
3349 throw runtime_error("type mismatch");
3350 params[1] = v.get_obj();
3352 if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]);
3353 if (strMethod == "reservebalance" && n > 0) ConvertTo<bool>(params[0]);
3354 if (strMethod == "reservebalance" && n > 1) ConvertTo<double>(params[1]);
3355 if (strMethod == "addmultisigaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
3356 if (strMethod == "addmultisigaddress" && n > 1)
3358 string s = params[1].get_str();
3360 if (!read_string(s, v) || v.type() != array_type)
3361 throw runtime_error("type mismatch "+s);
3362 params[1] = v.get_array();
3366 Object reply = CallRPC(strMethod, params);
3369 const Value& result = find_value(reply, "result");
3370 const Value& error = find_value(reply, "error");
3372 if (error.type() != null_type)
3375 strPrint = "error: " + write_string(error, false);
3376 int code = find_value(error.get_obj(), "code").get_int();
3382 if (result.type() == null_type)
3384 else if (result.type() == str_type)
3385 strPrint = result.get_str();
3387 strPrint = write_string(result, true);
3390 catch (std::exception& e)
3392 strPrint = string("error: ") + e.what();
3397 PrintException(NULL, "CommandLineRPC()");
3402 fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
3411 int main(int argc, char *argv[])
3414 // Turn off microsoft heap dump noise
3415 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
3416 _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
3418 setbuf(stdin, NULL);
3419 setbuf(stdout, NULL);
3420 setbuf(stderr, NULL);
3424 if (argc >= 2 && string(argv[1]) == "-server")
3426 printf("server ready\n");
3427 ThreadRPCServer(NULL);
3431 return CommandLineRPC(argc, argv);
3434 catch (std::exception& e) {
3435 PrintException(&e, "main()");
3437 PrintException(NULL, "main()");
3443 const CRPCTable tableRPC;