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 void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
119 int confirms = wtx.GetDepthInMainChain();
120 entry.push_back(Pair("confirmations", confirms));
123 entry.push_back(Pair("blockhash", wtx.hashBlock.GetHex()));
124 entry.push_back(Pair("blockindex", wtx.nIndex));
126 entry.push_back(Pair("txid", wtx.GetHash().GetHex()));
127 entry.push_back(Pair("time", (boost::int64_t)wtx.GetTxTime()));
128 BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
129 entry.push_back(Pair(item.first, item.second));
132 string AccountFromValue(const Value& value)
134 string strAccount = value.get_str();
135 if (strAccount == "*")
136 throw JSONRPCError(-11, "Invalid account name");
140 Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool fPrintTransactionDetail)
143 result.push_back(Pair("hash", block.GetHash().GetHex()));
144 result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION)));
145 result.push_back(Pair("height", blockindex->nHeight));
146 result.push_back(Pair("version", block.nVersion));
147 result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex()));
148 result.push_back(Pair("time", DateTimeStrFormat(block.GetBlockTime())));
149 result.push_back(Pair("nonce", (boost::uint64_t)block.nNonce));
150 result.push_back(Pair("bits", HexBits(block.nBits)));
151 result.push_back(Pair("difficulty", GetDifficulty(blockindex)));
152 result.push_back(Pair("mint", ValueFromAmount(blockindex->nMint)));
153 if (blockindex->pprev)
154 result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex()));
155 if (blockindex->pnext)
156 result.push_back(Pair("nextblockhash", blockindex->pnext->GetBlockHash().GetHex()));
157 result.push_back(Pair("flags", strprintf("%s%s", blockindex->IsProofOfStake()? "proof-of-stake" : "proof-of-work", blockindex->GeneratedStakeModifier()? " stake-modifier": "")));
158 result.push_back(Pair("proofhash", blockindex->IsProofOfStake()? blockindex->hashProofOfStake.GetHex() : blockindex->GetBlockHash().GetHex()));
159 result.push_back(Pair("entropybit", (int)blockindex->GetStakeEntropyBit()));
160 result.push_back(Pair("modifier", strprintf("%016"PRI64x, blockindex->nStakeModifier)));
161 result.push_back(Pair("modifierchecksum", strprintf("%08x", blockindex->nStakeModifierChecksum)));
163 BOOST_FOREACH (const CTransaction& tx, block.vtx)
165 if (fPrintTransactionDetail)
167 txinfo.push_back(tx.ToStringShort());
168 txinfo.push_back(DateTimeStrFormat(tx.nTime));
169 BOOST_FOREACH(const CTxIn& txin, tx.vin)
170 txinfo.push_back(txin.ToStringShort());
171 BOOST_FOREACH(const CTxOut& txout, tx.vout)
172 txinfo.push_back(txout.ToStringShort());
175 txinfo.push_back(tx.GetHash().GetHex());
177 result.push_back(Pair("tx", txinfo));
184 /// Note: This interface may still be subject to change.
187 string CRPCTable::help(string strCommand) const
190 set<rpcfn_type> setDone;
191 for (map<string, const CRPCCommand*>::const_iterator mi = mapCommands.begin(); mi != mapCommands.end(); ++mi)
193 const CRPCCommand *pcmd = mi->second;
194 string strMethod = mi->first;
195 // We already filter duplicates, but these deprecated screw up the sort order
196 if (strMethod == "getamountreceived" ||
197 strMethod == "getallreceived" ||
198 strMethod == "getblocknumber" || // deprecated
199 (strMethod.find("label") != string::npos))
201 if (strCommand != "" && strMethod != strCommand)
206 rpcfn_type pfn = pcmd->actor;
207 if (setDone.insert(pfn).second)
208 (*pfn)(params, true);
210 catch (std::exception& e)
212 // Help text is returned in an exception
213 string strHelp = string(e.what());
214 if (strCommand == "")
215 if (strHelp.find('\n') != string::npos)
216 strHelp = strHelp.substr(0, strHelp.find('\n'));
217 strRet += strHelp + "\n";
221 strRet = strprintf("help: unknown command: %s\n", strCommand.c_str());
222 strRet = strRet.substr(0,strRet.size()-1);
226 Value help(const Array& params, bool fHelp)
228 if (fHelp || params.size() > 1)
231 "List commands, or get help for a command.");
234 if (params.size() > 0)
235 strCommand = params[0].get_str();
237 return tableRPC.help(strCommand);
241 Value stop(const Array& params, bool fHelp)
243 if (fHelp || params.size() != 0)
246 "Stop novacoin server.");
247 // Shutdown will take long enough that the response should get back
249 return "novacoin server stopping";
253 Value getblockcount(const Array& params, bool fHelp)
255 if (fHelp || params.size() != 0)
258 "Returns the number of blocks in the longest block chain.");
265 Value getblocknumber(const Array& params, bool fHelp)
267 if (fHelp || params.size() != 0)
270 "Deprecated. Use getblockcount.");
276 Value getconnectioncount(const Array& params, bool fHelp)
278 if (fHelp || params.size() != 0)
280 "getconnectioncount\n"
281 "Returns the number of connections to other nodes.");
283 return (int)vNodes.size();
287 Value getdifficulty(const Array& params, bool fHelp)
289 if (fHelp || params.size() != 0)
292 "Returns difficulty as a multiple of the minimum difficulty.");
295 obj.push_back(Pair("proof-of-work", GetDifficulty()));
296 obj.push_back(Pair("proof-of-stake", GetDifficulty(GetLastBlockIndex(pindexBest, true))));
297 obj.push_back(Pair("search-interval", (int)nLastCoinStakeSearchInterval));
302 Value getgenerate(const Array& params, bool fHelp)
304 if (fHelp || params.size() != 0)
307 "Returns true or false.");
309 return GetBoolArg("-gen");
313 Value setgenerate(const Array& params, bool fHelp)
315 if (fHelp || params.size() < 1 || params.size() > 2)
317 "setgenerate <generate> [genproclimit]\n"
318 "<generate> is true or false to turn generation on or off.\n"
319 "Generation is limited to [genproclimit] processors, -1 is unlimited.");
321 bool fGenerate = true;
322 if (params.size() > 0)
323 fGenerate = params[0].get_bool();
325 if (params.size() > 1)
327 int nGenProcLimit = params[1].get_int();
328 mapArgs["-genproclimit"] = itostr(nGenProcLimit);
329 if (nGenProcLimit == 0)
332 mapArgs["-gen"] = (fGenerate ? "1" : "0");
334 GenerateBitcoins(fGenerate, pwalletMain);
339 Value gethashespersec(const Array& params, bool fHelp)
341 if (fHelp || params.size() != 0)
344 "Returns a recent hashes per second performance measurement while generating.");
346 if (GetTimeMillis() - nHPSTimerStart > 8000)
347 return (boost::int64_t)0;
348 return (boost::int64_t)dHashesPerSec;
352 Value getinfo(const Array& params, bool fHelp)
354 if (fHelp || params.size() != 0)
357 "Returns an object containing various state info.");
360 obj.push_back(Pair("version", FormatFullVersion()));
361 obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION));
362 obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
363 obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
364 obj.push_back(Pair("newmint", ValueFromAmount(pwalletMain->GetNewMint())));
365 obj.push_back(Pair("stake", ValueFromAmount(pwalletMain->GetStake())));
366 obj.push_back(Pair("blocks", (int)nBestHeight));
367 obj.push_back(Pair("moneysupply", ValueFromAmount(pindexBest->nMoneySupply)));
368 obj.push_back(Pair("connections", (int)vNodes.size()));
369 obj.push_back(Pair("proxy", (fUseProxy ? addrProxy.ToStringIPPort() : string())));
370 obj.push_back(Pair("ip", addrSeenByPeer.ToStringIP()));
371 obj.push_back(Pair("difficulty", (double)GetDifficulty()));
372 obj.push_back(Pair("testnet", fTestNet));
373 obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));
374 obj.push_back(Pair("keypoolsize", pwalletMain->GetKeyPoolSize()));
375 obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee)));
376 if (pwalletMain->IsCrypted())
377 obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime / 1000));
378 obj.push_back(Pair("errors", GetWarnings("statusbar")));
383 Value getmininginfo(const Array& params, bool fHelp)
385 if (fHelp || params.size() != 0)
388 "Returns an object containing mining-related information.");
391 obj.push_back(Pair("blocks", (int)nBestHeight));
392 obj.push_back(Pair("currentblocksize",(uint64_t)nLastBlockSize));
393 obj.push_back(Pair("currentblocktx",(uint64_t)nLastBlockTx));
394 obj.push_back(Pair("difficulty", (double)GetDifficulty()));
395 obj.push_back(Pair("errors", GetWarnings("statusbar")));
396 obj.push_back(Pair("generate", GetBoolArg("-gen")));
397 obj.push_back(Pair("genproclimit", (int)GetArg("-genproclimit", -1)));
398 obj.push_back(Pair("hashespersec", gethashespersec(params, false)));
399 obj.push_back(Pair("pooledtx", (uint64_t)mempool.size()));
400 obj.push_back(Pair("testnet", fTestNet));
405 Value getnewaddress(const Array& params, bool fHelp)
407 if (fHelp || params.size() > 1)
409 "getnewaddress [account]\n"
410 "Returns a new novacoin address for receiving payments. "
411 "If [account] is specified (recommended), it is added to the address book "
412 "so payments received with the address will be credited to [account].");
414 // Parse the account first so we don't generate a key if there's an error
416 if (params.size() > 0)
417 strAccount = AccountFromValue(params[0]);
419 if (!pwalletMain->IsLocked())
420 pwalletMain->TopUpKeyPool();
422 // Generate a new key that is added to wallet
423 std::vector<unsigned char> newKey;
424 if (!pwalletMain->GetKeyFromPool(newKey, false))
425 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
426 CBitcoinAddress address(newKey);
428 pwalletMain->SetAddressBookName(address, strAccount);
430 return address.ToString();
434 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
436 CWalletDB walletdb(pwalletMain->strWalletFile);
439 walletdb.ReadAccount(strAccount, account);
441 bool bKeyUsed = false;
443 // Check if the current key has been used
444 if (!account.vchPubKey.empty())
446 CScript scriptPubKey;
447 scriptPubKey.SetBitcoinAddress(account.vchPubKey);
448 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
449 it != pwalletMain->mapWallet.end() && !account.vchPubKey.empty();
452 const CWalletTx& wtx = (*it).second;
453 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
454 if (txout.scriptPubKey == scriptPubKey)
459 // Generate a new key
460 if (account.vchPubKey.empty() || bForceNew || bKeyUsed)
462 if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false))
463 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
465 pwalletMain->SetAddressBookName(CBitcoinAddress(account.vchPubKey), strAccount);
466 walletdb.WriteAccount(strAccount, account);
469 return CBitcoinAddress(account.vchPubKey);
472 Value getaccountaddress(const Array& params, bool fHelp)
474 if (fHelp || params.size() != 1)
476 "getaccountaddress <account>\n"
477 "Returns the current novacoin address for receiving payments to this account.");
479 // Parse the account first so we don't generate a key if there's an error
480 string strAccount = AccountFromValue(params[0]);
484 ret = GetAccountAddress(strAccount).ToString();
491 Value setaccount(const Array& params, bool fHelp)
493 if (fHelp || params.size() < 1 || params.size() > 2)
495 "setaccount <novacoinaddress> <account>\n"
496 "Sets the account associated with the given address.");
498 CBitcoinAddress address(params[0].get_str());
499 if (!address.IsValid())
500 throw JSONRPCError(-5, "Invalid novacoin address");
504 if (params.size() > 1)
505 strAccount = AccountFromValue(params[1]);
507 // Detect when changing the account of an address that is the 'unused current key' of another account:
508 if (pwalletMain->mapAddressBook.count(address))
510 string strOldAccount = pwalletMain->mapAddressBook[address];
511 if (address == GetAccountAddress(strOldAccount))
512 GetAccountAddress(strOldAccount, true);
515 pwalletMain->SetAddressBookName(address, strAccount);
521 Value getaccount(const Array& params, bool fHelp)
523 if (fHelp || params.size() != 1)
525 "getaccount <novacoinaddress>\n"
526 "Returns the account associated with the given address.");
528 CBitcoinAddress address(params[0].get_str());
529 if (!address.IsValid())
530 throw JSONRPCError(-5, "Invalid novacoin address");
533 map<CBitcoinAddress, string>::iterator mi = pwalletMain->mapAddressBook.find(address);
534 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
535 strAccount = (*mi).second;
540 Value getaddressesbyaccount(const Array& params, bool fHelp)
542 if (fHelp || params.size() != 1)
544 "getaddressesbyaccount <account>\n"
545 "Returns the list of addresses for the given account.");
547 string strAccount = AccountFromValue(params[0]);
549 // Find all addresses that have the given account
551 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
553 const CBitcoinAddress& address = item.first;
554 const string& strName = item.second;
555 if (strName == strAccount)
556 ret.push_back(address.ToString());
561 Value settxfee(const Array& params, bool fHelp)
563 if (fHelp || params.size() < 1 || params.size() > 1 || AmountFromValue(params[0]) < MIN_TX_FEE)
565 "settxfee <amount>\n"
566 "<amount> is a real and is rounded to 0.01 (cent)\n"
567 "Minimum and default transaction fee per KB is 1 cent");
569 nTransactionFee = AmountFromValue(params[0]);
570 nTransactionFee = (nTransactionFee / CENT) * CENT; // round to cent
574 Value sendtoaddress(const Array& params, bool fHelp)
576 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
578 "sendtoaddress <novacoinaddress> <amount> [comment] [comment-to]\n"
579 "<amount> is a real and is rounded to the nearest 0.000001\n"
580 "requires wallet passphrase to be set with walletpassphrase first");
581 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
583 "sendtoaddress <novacoinaddress> <amount> [comment] [comment-to]\n"
584 "<amount> is a real and is rounded to the nearest 0.000001");
586 CBitcoinAddress address(params[0].get_str());
587 if (!address.IsValid())
588 throw JSONRPCError(-5, "Invalid novacoin address");
591 int64 nAmount = AmountFromValue(params[1]);
592 if (nAmount < MIN_TXOUT_AMOUNT)
593 throw JSONRPCError(-101, "Send amount too small");
597 if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
598 wtx.mapValue["comment"] = params[2].get_str();
599 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
600 wtx.mapValue["to"] = params[3].get_str();
602 if (pwalletMain->IsLocked())
603 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
605 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
607 throw JSONRPCError(-4, strError);
609 return wtx.GetHash().GetHex();
612 Value signmessage(const Array& params, bool fHelp)
614 if (fHelp || params.size() != 2)
616 "signmessage <novacoinaddress> <message>\n"
617 "Sign a message with the private key of an address");
619 if (pwalletMain->IsLocked())
620 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
622 string strAddress = params[0].get_str();
623 string strMessage = params[1].get_str();
625 CBitcoinAddress addr(strAddress);
627 throw JSONRPCError(-3, "Invalid address");
630 if (!pwalletMain->GetKey(addr, key))
631 throw JSONRPCError(-4, "Private key not available");
633 CDataStream ss(SER_GETHASH, 0);
634 ss << strMessageMagic;
637 vector<unsigned char> vchSig;
638 if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig))
639 throw JSONRPCError(-5, "Sign failed");
641 return EncodeBase64(&vchSig[0], vchSig.size());
644 Value verifymessage(const Array& params, bool fHelp)
646 if (fHelp || params.size() != 3)
648 "verifymessage <novacoinaddress> <signature> <message>\n"
649 "Verify a signed message");
651 string strAddress = params[0].get_str();
652 string strSign = params[1].get_str();
653 string strMessage = params[2].get_str();
655 CBitcoinAddress addr(strAddress);
657 throw JSONRPCError(-3, "Invalid address");
659 bool fInvalid = false;
660 vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
663 throw JSONRPCError(-5, "Malformed base64 encoding");
665 CDataStream ss(SER_GETHASH, 0);
666 ss << strMessageMagic;
670 if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
673 return (CBitcoinAddress(key.GetPubKey()) == addr);
677 Value getreceivedbyaddress(const Array& params, bool fHelp)
679 if (fHelp || params.size() < 1 || params.size() > 2)
681 "getreceivedbyaddress <novacoinaddress> [minconf=1]\n"
682 "Returns the total amount received by <novacoinaddress> in transactions with at least [minconf] confirmations.");
685 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
686 CScript scriptPubKey;
687 if (!address.IsValid())
688 throw JSONRPCError(-5, "Invalid novacoin address");
689 scriptPubKey.SetBitcoinAddress(address);
690 if (!IsMine(*pwalletMain,scriptPubKey))
693 // Minimum confirmations
695 if (params.size() > 1)
696 nMinDepth = params[1].get_int();
700 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
702 const CWalletTx& wtx = (*it).second;
703 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
706 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
707 if (txout.scriptPubKey == scriptPubKey)
708 if (wtx.GetDepthInMainChain() >= nMinDepth)
709 nAmount += txout.nValue;
712 return ValueFromAmount(nAmount);
716 void GetAccountAddresses(string strAccount, set<CBitcoinAddress>& setAddress)
718 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
720 const CBitcoinAddress& address = item.first;
721 const string& strName = item.second;
722 if (strName == strAccount)
723 setAddress.insert(address);
728 Value getreceivedbyaccount(const Array& params, bool fHelp)
730 if (fHelp || params.size() < 1 || params.size() > 2)
732 "getreceivedbyaccount <account> [minconf=1]\n"
733 "Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.");
735 // Minimum confirmations
737 if (params.size() > 1)
738 nMinDepth = params[1].get_int();
740 // Get the set of pub keys assigned to account
741 string strAccount = AccountFromValue(params[0]);
742 set<CBitcoinAddress> setAddress;
743 GetAccountAddresses(strAccount, setAddress);
747 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
749 const CWalletTx& wtx = (*it).second;
750 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
753 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
755 CBitcoinAddress address;
756 if (ExtractAddress(txout.scriptPubKey, address) && pwalletMain->HaveKey(address) && setAddress.count(address))
757 if (wtx.GetDepthInMainChain() >= nMinDepth)
758 nAmount += txout.nValue;
762 return (double)nAmount / (double)COIN;
766 int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth)
770 // Tally wallet transactions
771 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
773 const CWalletTx& wtx = (*it).second;
777 int64 nGenerated, nReceived, nSent, nFee;
778 wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee);
780 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
781 nBalance += nReceived;
782 nBalance += nGenerated - nSent - nFee;
785 // Tally internal accounting entries
786 nBalance += walletdb.GetAccountCreditDebit(strAccount);
791 int64 GetAccountBalance(const string& strAccount, int nMinDepth)
793 CWalletDB walletdb(pwalletMain->strWalletFile);
794 return GetAccountBalance(walletdb, strAccount, nMinDepth);
798 Value getbalance(const Array& params, bool fHelp)
800 if (fHelp || params.size() > 2)
802 "getbalance [account] [minconf=1]\n"
803 "If [account] is not specified, returns the server's total available balance.\n"
804 "If [account] is specified, returns the balance in the account.");
806 if (params.size() == 0)
807 return ValueFromAmount(pwalletMain->GetBalance());
810 if (params.size() > 1)
811 nMinDepth = params[1].get_int();
813 if (params[0].get_str() == "*") {
814 // Calculate total balance a different way from GetBalance()
815 // (GetBalance() sums up all unspent TxOuts)
816 // getbalance and getbalance '*' should always return the same number.
818 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
820 const CWalletTx& wtx = (*it).second;
824 int64 allGeneratedImmature, allGeneratedMature, allFee;
825 allGeneratedImmature = allGeneratedMature = allFee = 0;
826 string strSentAccount;
827 list<pair<CBitcoinAddress, int64> > listReceived;
828 list<pair<CBitcoinAddress, int64> > listSent;
829 wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
830 if (wtx.GetDepthInMainChain() >= nMinDepth)
832 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listReceived)
833 nBalance += r.second;
835 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listSent)
836 nBalance -= r.second;
838 nBalance += allGeneratedMature;
840 return ValueFromAmount(nBalance);
843 string strAccount = AccountFromValue(params[0]);
845 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
847 return ValueFromAmount(nBalance);
851 Value movecmd(const Array& params, bool fHelp)
853 if (fHelp || params.size() < 3 || params.size() > 5)
855 "move <fromaccount> <toaccount> <amount> [minconf=1] [comment]\n"
856 "Move from one account in your wallet to another.");
858 string strFrom = AccountFromValue(params[0]);
859 string strTo = AccountFromValue(params[1]);
860 int64 nAmount = AmountFromValue(params[2]);
861 if (params.size() > 3)
862 // unused parameter, used to be nMinDepth, keep type-checking it though
863 (void)params[3].get_int();
865 if (params.size() > 4)
866 strComment = params[4].get_str();
868 CWalletDB walletdb(pwalletMain->strWalletFile);
869 if (!walletdb.TxnBegin())
870 throw JSONRPCError(-20, "database error");
872 int64 nNow = GetAdjustedTime();
875 CAccountingEntry debit;
876 debit.strAccount = strFrom;
877 debit.nCreditDebit = -nAmount;
879 debit.strOtherAccount = strTo;
880 debit.strComment = strComment;
881 walletdb.WriteAccountingEntry(debit);
884 CAccountingEntry credit;
885 credit.strAccount = strTo;
886 credit.nCreditDebit = nAmount;
888 credit.strOtherAccount = strFrom;
889 credit.strComment = strComment;
890 walletdb.WriteAccountingEntry(credit);
892 if (!walletdb.TxnCommit())
893 throw JSONRPCError(-20, "database error");
899 Value sendfrom(const Array& params, bool fHelp)
901 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
903 "sendfrom <fromaccount> <tonovacoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
904 "<amount> is a real and is rounded to the nearest 0.000001\n"
905 "requires wallet passphrase to be set with walletpassphrase first");
906 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
908 "sendfrom <fromaccount> <tonovacoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
909 "<amount> is a real and is rounded to the nearest 0.000001");
911 string strAccount = AccountFromValue(params[0]);
912 CBitcoinAddress address(params[1].get_str());
913 if (!address.IsValid())
914 throw JSONRPCError(-5, "Invalid novacoin address");
915 int64 nAmount = AmountFromValue(params[2]);
916 if (nAmount < MIN_TXOUT_AMOUNT)
917 throw JSONRPCError(-101, "Send amount too small");
919 if (params.size() > 3)
920 nMinDepth = params[3].get_int();
923 wtx.strFromAccount = strAccount;
924 if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
925 wtx.mapValue["comment"] = params[4].get_str();
926 if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
927 wtx.mapValue["to"] = params[5].get_str();
929 if (pwalletMain->IsLocked())
930 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
933 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
934 if (nAmount > nBalance)
935 throw JSONRPCError(-6, "Account has insufficient funds");
938 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
940 throw JSONRPCError(-4, strError);
942 return wtx.GetHash().GetHex();
946 Value sendmany(const Array& params, bool fHelp)
948 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
950 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
951 "amounts are double-precision floating point numbers\n"
952 "requires wallet passphrase to be set with walletpassphrase first");
953 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
955 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
956 "amounts are double-precision floating point numbers");
958 string strAccount = AccountFromValue(params[0]);
959 Object sendTo = params[1].get_obj();
961 if (params.size() > 2)
962 nMinDepth = params[2].get_int();
965 wtx.strFromAccount = strAccount;
966 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
967 wtx.mapValue["comment"] = params[3].get_str();
969 set<CBitcoinAddress> setAddress;
970 vector<pair<CScript, int64> > vecSend;
972 int64 totalAmount = 0;
973 BOOST_FOREACH(const Pair& s, sendTo)
975 CBitcoinAddress address(s.name_);
976 if (!address.IsValid())
977 throw JSONRPCError(-5, string("Invalid novacoin address:")+s.name_);
979 if (setAddress.count(address))
980 throw JSONRPCError(-8, string("Invalid parameter, duplicated address: ")+s.name_);
981 setAddress.insert(address);
983 CScript scriptPubKey;
984 scriptPubKey.SetBitcoinAddress(address);
985 int64 nAmount = AmountFromValue(s.value_);
986 if (nAmount < MIN_TXOUT_AMOUNT)
987 throw JSONRPCError(-101, "Send amount too small");
988 totalAmount += nAmount;
990 vecSend.push_back(make_pair(scriptPubKey, nAmount));
993 if (pwalletMain->IsLocked())
994 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
995 if (fWalletUnlockMintOnly)
996 throw JSONRPCError(-13, "Error: Wallet unlocked for block minting only.");
999 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
1000 if (totalAmount > nBalance)
1001 throw JSONRPCError(-6, "Account has insufficient funds");
1004 CReserveKey keyChange(pwalletMain);
1005 int64 nFeeRequired = 0;
1006 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
1009 if (totalAmount + nFeeRequired > pwalletMain->GetBalance())
1010 throw JSONRPCError(-6, "Insufficient funds");
1011 throw JSONRPCError(-4, "Transaction creation failed");
1013 if (!pwalletMain->CommitTransaction(wtx, keyChange))
1014 throw JSONRPCError(-4, "Transaction commit failed");
1016 return wtx.GetHash().GetHex();
1019 Value addmultisigaddress(const Array& params, bool fHelp)
1021 if (fHelp || params.size() < 2 || params.size() > 3)
1023 string msg = "addmultisigaddress <nrequired> <'[\"key\",\"key\"]'> [account]\n"
1024 "Add a nrequired-to-sign multisignature address to the wallet\"\n"
1025 "each key is a bitcoin address or hex-encoded public key\n"
1026 "If [account] is specified, assign address to [account].";
1027 throw runtime_error(msg);
1030 int nRequired = params[0].get_int();
1031 const Array& keys = params[1].get_array();
1033 if (params.size() > 2)
1034 strAccount = AccountFromValue(params[2]);
1036 // Gather public keys
1038 throw runtime_error("a multisignature address must require at least one key to redeem");
1039 if ((int)keys.size() < nRequired)
1040 throw runtime_error(
1041 strprintf("not enough keys supplied "
1042 "(got %d keys, but need at least %d to redeem)", keys.size(), nRequired));
1043 std::vector<CKey> pubkeys;
1044 pubkeys.resize(keys.size());
1045 for (unsigned int i = 0; i < keys.size(); i++)
1047 const std::string& ks = keys[i].get_str();
1049 // Case 1: bitcoin address and we have full public key:
1050 CBitcoinAddress address(ks);
1051 if (address.IsValid())
1053 if (address.IsScript())
1054 throw runtime_error(
1055 strprintf("%s is a pay-to-script address",ks.c_str()));
1056 std::vector<unsigned char> vchPubKey;
1057 if (!pwalletMain->GetPubKey(address, vchPubKey))
1058 throw runtime_error(
1059 strprintf("no full public key for address %s",ks.c_str()));
1060 if (vchPubKey.empty() || !pubkeys[i].SetPubKey(vchPubKey))
1061 throw runtime_error(" Invalid public key: "+ks);
1064 // Case 2: hex public key
1067 vector<unsigned char> vchPubKey = ParseHex(ks);
1068 if (vchPubKey.empty() || !pubkeys[i].SetPubKey(vchPubKey))
1069 throw runtime_error(" Invalid public key: "+ks);
1073 throw runtime_error(" Invalid public key: "+ks);
1077 // Construct using pay-to-script-hash:
1079 inner.SetMultisig(nRequired, pubkeys);
1081 uint160 scriptHash = Hash160(inner);
1082 CScript scriptPubKey;
1083 scriptPubKey.SetPayToScriptHash(inner);
1084 pwalletMain->AddCScript(inner);
1085 CBitcoinAddress address;
1086 address.SetScriptHash160(scriptHash);
1088 pwalletMain->SetAddressBookName(address, strAccount);
1089 return address.ToString();
1100 nConf = std::numeric_limits<int>::max();
1104 Value ListReceived(const Array& params, bool fByAccounts)
1106 // Minimum confirmations
1108 if (params.size() > 0)
1109 nMinDepth = params[0].get_int();
1111 // Whether to include empty accounts
1112 bool fIncludeEmpty = false;
1113 if (params.size() > 1)
1114 fIncludeEmpty = params[1].get_bool();
1117 map<CBitcoinAddress, tallyitem> mapTally;
1118 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1120 const CWalletTx& wtx = (*it).second;
1122 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
1125 int nDepth = wtx.GetDepthInMainChain();
1126 if (nDepth < nMinDepth)
1129 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
1131 CBitcoinAddress address;
1132 if (!ExtractAddress(txout.scriptPubKey, address) || !pwalletMain->HaveKey(address) || !address.IsValid())
1135 tallyitem& item = mapTally[address];
1136 item.nAmount += txout.nValue;
1137 item.nConf = min(item.nConf, nDepth);
1143 map<string, tallyitem> mapAccountTally;
1144 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
1146 const CBitcoinAddress& address = item.first;
1147 const string& strAccount = item.second;
1148 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
1149 if (it == mapTally.end() && !fIncludeEmpty)
1153 int nConf = std::numeric_limits<int>::max();
1154 if (it != mapTally.end())
1156 nAmount = (*it).second.nAmount;
1157 nConf = (*it).second.nConf;
1162 tallyitem& item = mapAccountTally[strAccount];
1163 item.nAmount += nAmount;
1164 item.nConf = min(item.nConf, nConf);
1169 obj.push_back(Pair("address", address.ToString()));
1170 obj.push_back(Pair("account", strAccount));
1171 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1172 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1179 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
1181 int64 nAmount = (*it).second.nAmount;
1182 int nConf = (*it).second.nConf;
1184 obj.push_back(Pair("account", (*it).first));
1185 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1186 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1194 Value listreceivedbyaddress(const Array& params, bool fHelp)
1196 if (fHelp || params.size() > 2)
1197 throw runtime_error(
1198 "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
1199 "[minconf] is the minimum number of confirmations before payments are included.\n"
1200 "[includeempty] whether to include addresses that haven't received any payments.\n"
1201 "Returns an array of objects containing:\n"
1202 " \"address\" : receiving address\n"
1203 " \"account\" : the account of the receiving address\n"
1204 " \"amount\" : total amount received by the address\n"
1205 " \"confirmations\" : number of confirmations of the most recent transaction included");
1207 return ListReceived(params, false);
1210 Value listreceivedbyaccount(const Array& params, bool fHelp)
1212 if (fHelp || params.size() > 2)
1213 throw runtime_error(
1214 "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
1215 "[minconf] is the minimum number of confirmations before payments are included.\n"
1216 "[includeempty] whether to include accounts that haven't received any payments.\n"
1217 "Returns an array of objects containing:\n"
1218 " \"account\" : the account of the receiving addresses\n"
1219 " \"amount\" : total amount received by addresses with this account\n"
1220 " \"confirmations\" : number of confirmations of the most recent transaction included");
1222 return ListReceived(params, true);
1225 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret)
1227 int64 nGeneratedImmature, nGeneratedMature, nFee;
1228 string strSentAccount;
1229 list<pair<CBitcoinAddress, int64> > listReceived;
1230 list<pair<CBitcoinAddress, int64> > listSent;
1232 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1234 bool fAllAccounts = (strAccount == string("*"));
1236 // Generated blocks assigned to account ""
1237 if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == ""))
1240 entry.push_back(Pair("account", string("")));
1241 if (nGeneratedImmature)
1243 entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
1244 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
1248 entry.push_back(Pair("category", "generate"));
1249 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
1252 WalletTxToJSON(wtx, entry);
1253 ret.push_back(entry);
1257 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1259 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1262 entry.push_back(Pair("account", strSentAccount));
1263 entry.push_back(Pair("address", s.first.ToString()));
1264 entry.push_back(Pair("category", "send"));
1265 entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1266 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1268 WalletTxToJSON(wtx, entry);
1269 ret.push_back(entry);
1274 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1276 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1279 if (pwalletMain->mapAddressBook.count(r.first))
1280 account = pwalletMain->mapAddressBook[r.first];
1281 if (fAllAccounts || (account == strAccount))
1284 entry.push_back(Pair("account", account));
1285 entry.push_back(Pair("address", r.first.ToString()));
1286 entry.push_back(Pair("category", "receive"));
1287 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1289 WalletTxToJSON(wtx, entry);
1290 ret.push_back(entry);
1296 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1298 bool fAllAccounts = (strAccount == string("*"));
1300 if (fAllAccounts || acentry.strAccount == strAccount)
1303 entry.push_back(Pair("account", acentry.strAccount));
1304 entry.push_back(Pair("category", "move"));
1305 entry.push_back(Pair("time", (boost::int64_t)acentry.nTime));
1306 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1307 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1308 entry.push_back(Pair("comment", acentry.strComment));
1309 ret.push_back(entry);
1313 Value listtransactions(const Array& params, bool fHelp)
1315 if (fHelp || params.size() > 3)
1316 throw runtime_error(
1317 "listtransactions [account] [count=10] [from=0]\n"
1318 "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1320 string strAccount = "*";
1321 if (params.size() > 0)
1322 strAccount = params[0].get_str();
1324 if (params.size() > 1)
1325 nCount = params[1].get_int();
1327 if (params.size() > 2)
1328 nFrom = params[2].get_int();
1331 throw JSONRPCError(-8, "Negative count");
1333 throw JSONRPCError(-8, "Negative from");
1336 CWalletDB walletdb(pwalletMain->strWalletFile);
1338 // First: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap.
1339 typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
1340 typedef multimap<int64, TxPair > TxItems;
1343 // Note: maintaining indices in the database of (account,time) --> txid and (account, time) --> acentry
1344 // would make this much faster for applications that do this a lot.
1345 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1347 CWalletTx* wtx = &((*it).second);
1348 txByTime.insert(make_pair(wtx->GetTxTime(), TxPair(wtx, (CAccountingEntry*)0)));
1350 list<CAccountingEntry> acentries;
1351 walletdb.ListAccountCreditDebit(strAccount, acentries);
1352 BOOST_FOREACH(CAccountingEntry& entry, acentries)
1354 txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
1357 // iterate backwards until we have nCount items to return:
1358 for (TxItems::reverse_iterator it = txByTime.rbegin(); it != txByTime.rend(); ++it)
1360 CWalletTx *const pwtx = (*it).second.first;
1362 ListTransactions(*pwtx, strAccount, 0, true, ret);
1363 CAccountingEntry *const pacentry = (*it).second.second;
1365 AcentryToJSON(*pacentry, strAccount, ret);
1367 if (ret.size() >= (nCount+nFrom)) break;
1369 // ret is newest to oldest
1371 if (nFrom > (int)ret.size())
1373 if ((nFrom + nCount) > (int)ret.size())
1374 nCount = ret.size() - nFrom;
1375 Array::iterator first = ret.begin();
1376 std::advance(first, nFrom);
1377 Array::iterator last = ret.begin();
1378 std::advance(last, nFrom+nCount);
1380 if (last != ret.end()) ret.erase(last, ret.end());
1381 if (first != ret.begin()) ret.erase(ret.begin(), first);
1383 std::reverse(ret.begin(), ret.end()); // Return oldest to newest
1388 Value listaccounts(const Array& params, bool fHelp)
1390 if (fHelp || params.size() > 1)
1391 throw runtime_error(
1392 "listaccounts [minconf=1]\n"
1393 "Returns Object that has account names as keys, account balances as values.");
1396 if (params.size() > 0)
1397 nMinDepth = params[0].get_int();
1399 map<string, int64> mapAccountBalances;
1400 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& entry, pwalletMain->mapAddressBook) {
1401 if (pwalletMain->HaveKey(entry.first)) // This address belongs to me
1402 mapAccountBalances[entry.second] = 0;
1405 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1407 const CWalletTx& wtx = (*it).second;
1408 int64 nGeneratedImmature, nGeneratedMature, nFee;
1409 string strSentAccount;
1410 list<pair<CBitcoinAddress, int64> > listReceived;
1411 list<pair<CBitcoinAddress, int64> > listSent;
1412 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1413 mapAccountBalances[strSentAccount] -= nFee;
1414 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1415 mapAccountBalances[strSentAccount] -= s.second;
1416 if (wtx.GetDepthInMainChain() >= nMinDepth)
1418 mapAccountBalances[""] += nGeneratedMature;
1419 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1420 if (pwalletMain->mapAddressBook.count(r.first))
1421 mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1423 mapAccountBalances[""] += r.second;
1427 list<CAccountingEntry> acentries;
1428 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1429 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1430 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1433 BOOST_FOREACH(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) {
1434 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1439 Value listsinceblock(const Array& params, bool fHelp)
1442 throw runtime_error(
1443 "listsinceblock [blockhash] [target-confirmations]\n"
1444 "Get all transactions in blocks since block [blockhash], or all transactions if omitted");
1446 CBlockIndex *pindex = NULL;
1447 int target_confirms = 1;
1449 if (params.size() > 0)
1451 uint256 blockId = 0;
1453 blockId.SetHex(params[0].get_str());
1454 pindex = CBlockLocator(blockId).GetBlockIndex();
1457 if (params.size() > 1)
1459 target_confirms = params[1].get_int();
1461 if (target_confirms < 1)
1462 throw JSONRPCError(-8, "Invalid parameter");
1465 int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1;
1469 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1471 CWalletTx tx = (*it).second;
1473 if (depth == -1 || tx.GetDepthInMainChain() < depth)
1474 ListTransactions(tx, "*", 0, true, transactions);
1479 if (target_confirms == 1)
1481 lastblock = hashBestChain;
1485 int target_height = pindexBest->nHeight + 1 - target_confirms;
1488 for (block = pindexBest;
1489 block && block->nHeight > target_height;
1490 block = block->pprev) { }
1492 lastblock = block ? block->GetBlockHash() : 0;
1496 ret.push_back(Pair("transactions", transactions));
1497 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1502 Value gettransaction(const Array& params, bool fHelp)
1504 if (fHelp || params.size() != 1)
1505 throw runtime_error(
1506 "gettransaction <txid>\n"
1507 "Get detailed information about <txid>");
1510 hash.SetHex(params[0].get_str());
1514 if (!pwalletMain->mapWallet.count(hash))
1515 throw JSONRPCError(-5, "Invalid or non-wallet transaction id");
1516 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1518 int64 nCredit = wtx.GetCredit();
1519 int64 nDebit = wtx.GetDebit();
1520 int64 nNet = nCredit - nDebit;
1521 int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
1523 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1525 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1527 WalletTxToJSON(pwalletMain->mapWallet[hash], entry);
1530 ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
1531 entry.push_back(Pair("details", details));
1537 Value backupwallet(const Array& params, bool fHelp)
1539 if (fHelp || params.size() != 1)
1540 throw runtime_error(
1541 "backupwallet <destination>\n"
1542 "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1544 string strDest = params[0].get_str();
1545 BackupWallet(*pwalletMain, strDest);
1551 Value keypoolrefill(const Array& params, bool fHelp)
1553 if (pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1554 throw runtime_error(
1556 "Fills the keypool, requires wallet passphrase to be set.");
1557 if (!pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1558 throw runtime_error(
1560 "Fills the keypool.");
1562 if (pwalletMain->IsLocked())
1563 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
1565 pwalletMain->TopUpKeyPool();
1567 if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100))
1568 throw JSONRPCError(-4, "Error refreshing keypool.");
1574 void ThreadTopUpKeyPool(void* parg)
1576 pwalletMain->TopUpKeyPool();
1579 void ThreadCleanWalletPassphrase(void* parg)
1581 int64 nMyWakeTime = GetTimeMillis() + *((int64*)parg) * 1000;
1583 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1585 if (nWalletUnlockTime == 0)
1587 nWalletUnlockTime = nMyWakeTime;
1591 if (nWalletUnlockTime==0)
1593 int64 nToSleep = nWalletUnlockTime - GetTimeMillis();
1597 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1599 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1603 if (nWalletUnlockTime)
1605 nWalletUnlockTime = 0;
1606 pwalletMain->Lock();
1611 if (nWalletUnlockTime < nMyWakeTime)
1612 nWalletUnlockTime = nMyWakeTime;
1615 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1617 delete (int64*)parg;
1620 Value walletpassphrase(const Array& params, bool fHelp)
1622 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 3))
1623 throw runtime_error(
1624 "walletpassphrase <passphrase> <timeout> [mintonly]\n"
1625 "Stores the wallet decryption key in memory for <timeout> seconds.\n"
1626 "mintonly is optional true/false allowing only block minting.");
1629 if (!pwalletMain->IsCrypted())
1630 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1632 if (!pwalletMain->IsLocked())
1633 throw JSONRPCError(-17, "Error: Wallet is already unlocked, use walletlock first if need to change unlock settings.");
1635 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1636 SecureString strWalletPass;
1637 strWalletPass.reserve(100);
1638 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1639 // Alternately, find a way to make params[0] mlock()'d to begin with.
1640 strWalletPass = params[0].get_str().c_str();
1642 if (strWalletPass.length() > 0)
1644 if (!pwalletMain->Unlock(strWalletPass))
1645 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1648 throw runtime_error(
1649 "walletpassphrase <passphrase> <timeout>\n"
1650 "Stores the wallet decryption key in memory for <timeout> seconds.");
1652 CreateThread(ThreadTopUpKeyPool, NULL);
1653 int64* pnSleepTime = new int64(params[1].get_int64());
1654 CreateThread(ThreadCleanWalletPassphrase, pnSleepTime);
1656 // ppcoin: if user OS account compromised prevent trivial sendmoney commands
1657 if (params.size() > 2)
1658 fWalletUnlockMintOnly = params[2].get_bool();
1660 fWalletUnlockMintOnly = false;
1666 Value walletpassphrasechange(const Array& params, bool fHelp)
1668 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1669 throw runtime_error(
1670 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1671 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1674 if (!pwalletMain->IsCrypted())
1675 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1677 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1678 // Alternately, find a way to make params[0] mlock()'d to begin with.
1679 SecureString strOldWalletPass;
1680 strOldWalletPass.reserve(100);
1681 strOldWalletPass = params[0].get_str().c_str();
1683 SecureString strNewWalletPass;
1684 strNewWalletPass.reserve(100);
1685 strNewWalletPass = params[1].get_str().c_str();
1687 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1688 throw runtime_error(
1689 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1690 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1692 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1693 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1699 Value walletlock(const Array& params, bool fHelp)
1701 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1702 throw runtime_error(
1704 "Removes the wallet encryption key from memory, locking the wallet.\n"
1705 "After calling this method, you will need to call walletpassphrase again\n"
1706 "before being able to call any methods which require the wallet to be unlocked.");
1709 if (!pwalletMain->IsCrypted())
1710 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called.");
1713 LOCK(cs_nWalletUnlockTime);
1714 pwalletMain->Lock();
1715 nWalletUnlockTime = 0;
1722 Value encryptwallet(const Array& params, bool fHelp)
1724 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1725 throw runtime_error(
1726 "encryptwallet <passphrase>\n"
1727 "Encrypts the wallet with <passphrase>.");
1730 if (pwalletMain->IsCrypted())
1731 throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
1733 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1734 // Alternately, find a way to make params[0] mlock()'d to begin with.
1735 SecureString strWalletPass;
1736 strWalletPass.reserve(100);
1737 strWalletPass = params[0].get_str().c_str();
1739 if (strWalletPass.length() < 1)
1740 throw runtime_error(
1741 "encryptwallet <passphrase>\n"
1742 "Encrypts the wallet with <passphrase>.");
1744 if (!pwalletMain->EncryptWallet(strWalletPass))
1745 throw JSONRPCError(-16, "Error: Failed to encrypt the wallet.");
1747 // BDB seems to have a bad habit of writing old data into
1748 // slack space in .dat files; that is bad if the old data is
1749 // unencrypted private keys. So:
1751 return "wallet encrypted; novacoin server stopping, restart to run with encrypted wallet";
1755 Value validateaddress(const Array& params, bool fHelp)
1757 if (fHelp || params.size() != 1)
1758 throw runtime_error(
1759 "validateaddress <novacoinaddress>\n"
1760 "Return information about <novacoinaddress>.");
1762 CBitcoinAddress address(params[0].get_str());
1763 bool isValid = address.IsValid();
1766 ret.push_back(Pair("isvalid", isValid));
1769 // Call Hash160ToAddress() so we always return current ADDRESSVERSION
1770 // version of the address:
1771 string currentAddress = address.ToString();
1772 ret.push_back(Pair("address", currentAddress));
1773 if (pwalletMain->HaveKey(address))
1775 ret.push_back(Pair("ismine", true));
1776 std::vector<unsigned char> vchPubKey;
1777 pwalletMain->GetPubKey(address, vchPubKey);
1778 ret.push_back(Pair("pubkey", HexStr(vchPubKey)));
1780 key.SetPubKey(vchPubKey);
1781 ret.push_back(Pair("iscompressed", key.IsCompressed()));
1783 else if (pwalletMain->HaveCScript(address.GetHash160()))
1785 ret.push_back(Pair("isscript", true));
1787 pwalletMain->GetCScript(address.GetHash160(), subscript);
1788 ret.push_back(Pair("ismine", ::IsMine(*pwalletMain, subscript)));
1789 std::vector<CBitcoinAddress> addresses;
1790 txnouttype whichType;
1792 ExtractAddresses(subscript, whichType, addresses, nRequired);
1793 ret.push_back(Pair("script", GetTxnOutputType(whichType)));
1795 BOOST_FOREACH(const CBitcoinAddress& addr, addresses)
1796 a.push_back(addr.ToString());
1797 ret.push_back(Pair("addresses", a));
1798 if (whichType == TX_MULTISIG)
1799 ret.push_back(Pair("sigsrequired", nRequired));
1802 ret.push_back(Pair("ismine", false));
1803 if (pwalletMain->mapAddressBook.count(address))
1804 ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
1809 Value getwork(const Array& params, bool fHelp)
1811 if (fHelp || params.size() > 1)
1812 throw runtime_error(
1814 "If [data] is not specified, returns formatted hash data to work on:\n"
1815 " \"midstate\" : precomputed hash state after hashing the first half of the data (DEPRECATED)\n" // deprecated
1816 " \"data\" : block data\n"
1817 " \"hash1\" : formatted hash buffer for second hash (DEPRECATED)\n" // deprecated
1818 " \"target\" : little endian hash target\n"
1819 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1822 throw JSONRPCError(-9, "NovaCoin is not connected!");
1824 if (IsInitialBlockDownload())
1825 throw JSONRPCError(-10, "NovaCoin is downloading blocks...");
1827 typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
1828 static mapNewBlock_t mapNewBlock;
1829 static vector<CBlock*> vNewBlock;
1830 static CReserveKey reservekey(pwalletMain);
1832 if (params.size() == 0)
1835 static unsigned int nTransactionsUpdatedLast;
1836 static CBlockIndex* pindexPrev;
1837 static int64 nStart;
1838 static CBlock* pblock;
1839 if (pindexPrev != pindexBest ||
1840 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
1842 if (pindexPrev != pindexBest)
1844 // Deallocate old blocks since they're obsolete now
1845 mapNewBlock.clear();
1846 BOOST_FOREACH(CBlock* pblock, vNewBlock)
1850 nTransactionsUpdatedLast = nTransactionsUpdated;
1851 pindexPrev = pindexBest;
1855 pblock = CreateNewBlock(pwalletMain);
1857 throw JSONRPCError(-7, "Out of memory");
1858 vNewBlock.push_back(pblock);
1862 pblock->UpdateTime(pindexPrev);
1865 // Update nExtraNonce
1866 static unsigned int nExtraNonce = 0;
1867 IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
1870 mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
1872 // Prebuild hash buffers
1876 FormatHashBuffers(pblock, pmidstate, pdata, phash1);
1878 uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
1881 result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate)))); // deprecated
1882 result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata))));
1883 result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1)))); // deprecated
1884 result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
1890 vector<unsigned char> vchData = ParseHex(params[0].get_str());
1891 if (vchData.size() != 128)
1892 throw JSONRPCError(-8, "Invalid parameter");
1893 CBlock* pdata = (CBlock*)&vchData[0];
1896 for (int i = 0; i < 128/4; i++)
1897 ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]);
1900 if (!mapNewBlock.count(pdata->hashMerkleRoot))
1902 CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
1904 pblock->nTime = pdata->nTime;
1905 pblock->nNonce = pdata->nNonce;
1906 pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
1907 pblock->hashMerkleRoot = pblock->BuildMerkleTree();
1908 if (!pblock->SignBlock(*pwalletMain))
1909 throw JSONRPCError(-100, "Unable to sign block, wallet locked?");
1911 return CheckWork(pblock, *pwalletMain, reservekey);
1915 Value getblocktemplate(const Array& params, bool fHelp)
1917 if (fHelp || params.size() > 1)
1918 throw runtime_error(
1919 "getblocktemplate [params]\n"
1920 "Returns data needed to construct a block to work on:\n"
1921 " \"version\" : block version\n"
1922 " \"previousblockhash\" : hash of current highest block\n"
1923 " \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
1924 " \"coinbaseaux\" : data that should be included in coinbase\n"
1925 " \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
1926 " \"target\" : hash target\n"
1927 " \"mintime\" : minimum timestamp appropriate for next block\n"
1928 " \"curtime\" : current timestamp\n"
1929 " \"mutable\" : list of ways the block template may be changed\n"
1930 " \"noncerange\" : range of valid nonces\n"
1931 " \"sigoplimit\" : limit of sigops in blocks\n"
1932 " \"sizelimit\" : limit of block size\n"
1933 " \"bits\" : compressed target of next block\n"
1934 " \"height\" : height of the next block\n"
1935 "See https://en.bitcoin.it/wiki/BIP_0022 for full specification.");
1937 std::string strMode = "template";
1938 if (params.size() > 0)
1940 const Object& oparam = params[0].get_obj();
1941 const Value& modeval = find_value(oparam, "mode");
1942 if (modeval.type() == str_type)
1943 strMode = modeval.get_str();
1945 throw JSONRPCError(-8, "Invalid mode");
1948 if (strMode != "template")
1949 throw JSONRPCError(-8, "Invalid mode");
1952 throw JSONRPCError(-9, "NovaCoin is not connected!");
1954 if (IsInitialBlockDownload())
1955 throw JSONRPCError(-10, "NovaCoin is downloading blocks...");
1957 static CReserveKey reservekey(pwalletMain);
1960 static unsigned int nTransactionsUpdatedLast;
1961 static CBlockIndex* pindexPrev;
1962 static int64 nStart;
1963 static CBlock* pblock;
1964 if (pindexPrev != pindexBest ||
1965 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5))
1967 // Clear pindexPrev so future calls make a new block, despite any failures from here on
1970 // Store the pindexBest used before CreateNewBlock, to avoid races
1971 nTransactionsUpdatedLast = nTransactionsUpdated;
1972 CBlockIndex* pindexPrevNew = pindexBest;
1981 pblock = CreateNewBlock(pwalletMain);
1983 throw JSONRPCError(-7, "Out of memory");
1985 // Need to update only after we know CreateNewBlock succeeded
1986 pindexPrev = pindexPrevNew;
1990 pblock->UpdateTime(pindexPrev);
1994 map<uint256, int64_t> setTxIndex;
1997 BOOST_FOREACH (CTransaction& tx, pblock->vtx)
1999 uint256 txHash = tx.GetHash();
2000 setTxIndex[txHash] = i++;
2002 if (tx.IsCoinBase() || tx.IsCoinStake())
2007 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
2009 entry.push_back(Pair("data", HexStr(ssTx.begin(), ssTx.end())));
2011 entry.push_back(Pair("hash", txHash.GetHex()));
2013 MapPrevTx mapInputs;
2014 map<uint256, CTxIndex> mapUnused;
2015 bool fInvalid = false;
2016 if (tx.FetchInputs(txdb, mapUnused, false, false, mapInputs, fInvalid))
2018 entry.push_back(Pair("fee", (int64_t)(tx.GetValueIn(mapInputs) - tx.GetValueOut())));
2021 BOOST_FOREACH (MapPrevTx::value_type& inp, mapInputs)
2023 if (setTxIndex.count(inp.first))
2024 deps.push_back(setTxIndex[inp.first]);
2026 entry.push_back(Pair("depends", deps));
2028 int64_t nSigOps = tx.GetLegacySigOpCount();
2029 nSigOps += tx.GetP2SHSigOpCount(mapInputs);
2030 entry.push_back(Pair("sigops", nSigOps));
2033 transactions.push_back(entry);
2037 aux.push_back(Pair("flags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end())));
2039 uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
2041 static Array aMutable;
2042 if (aMutable.empty())
2044 aMutable.push_back("time");
2045 aMutable.push_back("transactions");
2046 aMutable.push_back("prevblock");
2050 result.push_back(Pair("version", pblock->nVersion));
2051 result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
2052 result.push_back(Pair("transactions", transactions));
2053 result.push_back(Pair("coinbaseaux", aux));
2054 result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
2055 result.push_back(Pair("target", hashTarget.GetHex()));
2056 result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1));
2057 result.push_back(Pair("mutable", aMutable));
2058 result.push_back(Pair("noncerange", "00000000ffffffff"));
2059 result.push_back(Pair("sigoplimit", (int64_t)MAX_BLOCK_SIGOPS));
2060 result.push_back(Pair("sizelimit", (int64_t)MAX_BLOCK_SIZE));
2061 result.push_back(Pair("curtime", (int64_t)pblock->nTime));
2062 result.push_back(Pair("bits", HexBits(pblock->nBits)));
2063 result.push_back(Pair("height", (int64_t)(pindexPrev->nHeight+1)));
2068 Value submitblock(const Array& params, bool fHelp)
2070 if (fHelp || params.size() < 1 || params.size() > 2)
2071 throw runtime_error(
2072 "submitblock <hex data> [optional-params-obj]\n"
2073 "[optional-params-obj] parameter is currently ignored.\n"
2074 "Attempts to submit new block to network.\n"
2075 "See https://en.bitcoin.it/wiki/BIP_0022 for full specification.");
2077 vector<unsigned char> blockData(ParseHex(params[0].get_str()));
2078 CDataStream ssBlock(blockData, SER_NETWORK, PROTOCOL_VERSION);
2083 catch (std::exception &e) {
2084 throw JSONRPCError(-22, "Block decode failed");
2087 static CReserveKey reservekey(pwalletMain);
2089 if(!block.SignBlock(*pwalletMain))
2090 throw JSONRPCError(-100, "Unable to sign block, wallet locked?");
2092 bool fAccepted = CheckWork(&block, *pwalletMain, reservekey);
2100 Value getmemorypool(const Array& params, bool fHelp)
2102 if (fHelp || params.size() > 1)
2103 throw runtime_error(
2104 "getmemorypool [data]\n"
2105 "If [data] is not specified, returns data needed to construct a block to work on:\n"
2106 " \"version\" : block version\n"
2107 " \"previousblockhash\" : hash of current highest block\n"
2108 " \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
2109 " \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
2110 " \"coinbaseflags\" : data that should be included in coinbase so support for new features can be judged\n"
2111 " \"time\" : timestamp appropriate for next block\n"
2112 " \"mintime\" : minimum timestamp appropriate for next block\n"
2113 " \"curtime\" : current timestamp\n"
2114 " \"bits\" : compressed target of next block\n"
2115 "If [data] is specified, tries to solve the block and returns true if it was successful.");
2117 if (params.size() == 0)
2120 throw JSONRPCError(-9, "NovaCoin is not connected!");
2122 if (IsInitialBlockDownload())
2123 throw JSONRPCError(-10, "NovaCoin is downloading blocks...");
2125 static CReserveKey reservekey(pwalletMain);
2128 static unsigned int nTransactionsUpdatedLast;
2129 static CBlockIndex* pindexPrev;
2130 static int64 nStart;
2131 static CBlock* pblock;
2132 if (pindexPrev != pindexBest ||
2133 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5))
2135 nTransactionsUpdatedLast = nTransactionsUpdated;
2136 pindexPrev = pindexBest;
2142 pblock = CreateNewBlock(pwalletMain);
2144 throw JSONRPCError(-7, "Out of memory");
2148 pblock->UpdateTime(pindexPrev);
2152 BOOST_FOREACH(CTransaction tx, pblock->vtx) {
2153 if(tx.IsCoinBase() || tx.IsCoinStake())
2156 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
2159 transactions.push_back(HexStr(ssTx.begin(), ssTx.end()));
2163 result.push_back(Pair("version", pblock->nVersion));
2164 result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
2165 result.push_back(Pair("transactions", transactions));
2166 result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
2167 result.push_back(Pair("coinbaseflags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end())));
2168 result.push_back(Pair("time", (int64_t)pblock->nTime));
2169 result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1));
2170 result.push_back(Pair("curtime", (int64_t)GetAdjustedTime()));
2171 result.push_back(Pair("bits", HexBits(pblock->nBits)));
2178 CDataStream ssBlock(ParseHex(params[0].get_str()), SER_NETWORK, PROTOCOL_VERSION);
2182 static CReserveKey reservekey(pwalletMain);
2184 if(!pblock.SignBlock(*pwalletMain))
2185 throw JSONRPCError(-100, "Unable to sign block, wallet locked?");
2187 return CheckWork(&pblock, *pwalletMain, reservekey);
2191 Value getnewpubkey(const Array& params, bool fHelp)
2193 if (fHelp || params.size() > 1)
2194 throw runtime_error(
2195 "getnewpubkey [account]\n"
2196 "Returns new public key for coinbase generation.");
2198 // Parse the account first so we don't generate a key if there's an error
2200 if (params.size() > 0)
2201 strAccount = AccountFromValue(params[0]);
2203 if (!pwalletMain->IsLocked())
2204 pwalletMain->TopUpKeyPool();
2206 // Generate a new key that is added to wallet
2207 std::vector<unsigned char> newKey = pwalletMain->GenerateNewKey(false);
2210 throw JSONRPCError(-12, "Error: Unable to create key");
2212 CBitcoinAddress address(newKey);
2213 pwalletMain->SetAddressBookName(address, strAccount);
2215 return HexStr(newKey.begin(), newKey.end());
2218 Value getblockhash(const Array& params, bool fHelp)
2220 if (fHelp || params.size() != 1)
2221 throw runtime_error(
2222 "getblockhash <index>\n"
2223 "Returns hash of block in best-block-chain at <index>.");
2225 int nHeight = params[0].get_int();
2226 if (nHeight < 0 || nHeight > nBestHeight)
2227 throw runtime_error("Block number out of range.");
2230 CBlockIndex* pblockindex = mapBlockIndex[hashBestChain];
2231 while (pblockindex->nHeight > nHeight)
2232 pblockindex = pblockindex->pprev;
2233 return pblockindex->phashBlock->GetHex();
2236 Value getblock(const Array& params, bool fHelp)
2238 if (fHelp || params.size() < 1 || params.size() > 2)
2239 throw runtime_error(
2240 "getblock <hash> [txinfo]\n"
2241 "txinfo optional to print more detailed tx info\n"
2242 "Returns details of a block with given block-hash.");
2244 std::string strHash = params[0].get_str();
2245 uint256 hash(strHash);
2247 if (mapBlockIndex.count(hash) == 0)
2248 throw JSONRPCError(-5, "Block not found");
2251 CBlockIndex* pblockindex = mapBlockIndex[hash];
2252 block.ReadFromDisk(pblockindex, true);
2254 return blockToJSON(block, pblockindex, params.size() > 1 ? params[1].get_bool() : false);
2257 Value getblockbynumber(const Array& params, bool fHelp)
2259 if (fHelp || params.size() < 1 || params.size() > 2)
2260 throw runtime_error(
2261 "getblock <number> [txinfo]\n"
2262 "txinfo optional to print more detailed tx info\n"
2263 "Returns details of a block with given block-number.");
2265 int nHeight = params[0].get_int();
2266 if (nHeight < 0 || nHeight > nBestHeight)
2267 throw runtime_error("Block number out of range.");
2270 CBlockIndex* pblockindex = mapBlockIndex[hashBestChain];
2271 while (pblockindex->nHeight > nHeight)
2272 pblockindex = pblockindex->pprev;
2274 uint256 hash = *pblockindex->phashBlock;
2276 pblockindex = mapBlockIndex[hash];
2277 block.ReadFromDisk(pblockindex, true);
2279 return blockToJSON(block, pblockindex, params.size() > 1 ? params[1].get_bool() : false);
2282 // ppcoin: get information of sync-checkpoint
2283 Value getcheckpoint(const Array& params, bool fHelp)
2285 if (fHelp || params.size() != 0)
2286 throw runtime_error(
2288 "Show info of synchronized checkpoint.\n");
2291 CBlockIndex* pindexCheckpoint;
2293 result.push_back(Pair("synccheckpoint", Checkpoints::hashSyncCheckpoint.ToString().c_str()));
2294 pindexCheckpoint = mapBlockIndex[Checkpoints::hashSyncCheckpoint];
2295 result.push_back(Pair("height", pindexCheckpoint->nHeight));
2296 result.push_back(Pair("timestamp", DateTimeStrFormat(pindexCheckpoint->GetBlockTime()).c_str()));
2297 if (mapArgs.count("-checkpointkey"))
2298 result.push_back(Pair("checkpointmaster", true));
2304 // ppcoin: reserve balance from being staked for network protection
2305 Value reservebalance(const Array& params, bool fHelp)
2307 if (fHelp || params.size() > 2)
2308 throw runtime_error(
2309 "reservebalance [<reserve> [amount]]\n"
2310 "<reserve> is true or false to turn balance reserve on or off.\n"
2311 "<amount> is a real and rounded to cent.\n"
2312 "Set reserve amount not participating in network protection.\n"
2313 "If no parameters provided current setting is printed.\n");
2315 if (params.size() > 0)
2317 bool fReserve = params[0].get_bool();
2320 if (params.size() == 1)
2321 throw runtime_error("must provide amount to reserve balance.\n");
2322 int64 nAmount = AmountFromValue(params[1]);
2323 nAmount = (nAmount / CENT) * CENT; // round to cent
2325 throw runtime_error("amount cannot be negative.\n");
2326 mapArgs["-reservebalance"] = FormatMoney(nAmount).c_str();
2330 if (params.size() > 1)
2331 throw runtime_error("cannot specify amount to turn off reserve.\n");
2332 mapArgs["-reservebalance"] = "0";
2337 int64 nReserveBalance = 0;
2338 if (mapArgs.count("-reservebalance") && !ParseMoney(mapArgs["-reservebalance"], nReserveBalance))
2339 throw runtime_error("invalid reserve balance amount\n");
2340 result.push_back(Pair("reserve", (nReserveBalance > 0)));
2341 result.push_back(Pair("amount", ValueFromAmount(nReserveBalance)));
2346 // ppcoin: check wallet integrity
2347 Value checkwallet(const Array& params, bool fHelp)
2349 if (fHelp || params.size() > 0)
2350 throw runtime_error(
2352 "Check wallet for integrity.\n");
2355 int64 nBalanceInQuestion;
2356 pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion, true);
2358 if (nMismatchSpent == 0)
2359 result.push_back(Pair("wallet check passed", true));
2362 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
2363 result.push_back(Pair("amount in question", ValueFromAmount(nBalanceInQuestion)));
2369 // ppcoin: repair wallet
2370 Value repairwallet(const Array& params, bool fHelp)
2372 if (fHelp || params.size() > 0)
2373 throw runtime_error(
2375 "Repair wallet if checkwallet reports any problem.\n");
2378 int64 nBalanceInQuestion;
2379 pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion);
2381 if (nMismatchSpent == 0)
2382 result.push_back(Pair("wallet check passed", true));
2385 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
2386 result.push_back(Pair("amount affected by repair", ValueFromAmount(nBalanceInQuestion)));
2391 // NovaCoin: resend unconfirmed wallet transactions
2392 Value resendtx(const Array& params, bool fHelp)
2394 if (fHelp || params.size() > 1)
2395 throw runtime_error(
2397 "Re-send unconfirmed transactions.\n"
2400 ResendWalletTransactions();
2406 // ppcoin: make a public-private key pair
2407 Value makekeypair(const Array& params, bool fHelp)
2409 if (fHelp || params.size() > 1)
2410 throw runtime_error(
2411 "makekeypair [prefix]\n"
2412 "Make a public/private key pair.\n"
2413 "[prefix] is optional preferred prefix for the public key.\n");
2415 string strPrefix = "";
2416 if (params.size() > 0)
2417 strPrefix = params[0].get_str();
2423 key.MakeNewKey(false);
2425 } while (nCount < 10000 && strPrefix != HexStr(key.GetPubKey()).substr(0, strPrefix.size()));
2427 if (strPrefix != HexStr(key.GetPubKey()).substr(0, strPrefix.size()))
2430 CPrivKey vchPrivKey = key.GetPrivKey();
2432 result.push_back(Pair("PrivateKey", HexStr<CPrivKey::iterator>(vchPrivKey.begin(), vchPrivKey.end())));
2433 result.push_back(Pair("PublicKey", HexStr(key.GetPubKey())));
2437 extern CCriticalSection cs_mapAlerts;
2438 extern map<uint256, CAlert> mapAlerts;
2440 // ppcoin: send alert.
2441 // There is a known deadlock situation with ThreadMessageHandler
2442 // ThreadMessageHandler: holds cs_vSend and acquiring cs_main in SendMessages()
2443 // ThreadRPCServer: holds cs_main and acquiring cs_vSend in alert.RelayTo()/PushMessage()/BeginMessage()
2444 Value sendalert(const Array& params, bool fHelp)
2446 if (fHelp || params.size() < 6)
2447 throw runtime_error(
2448 "sendalert <message> <privatekey> <minver> <maxver> <priority> <id> [cancelupto]\n"
2449 "<message> is the alert text message\n"
2450 "<privatekey> is hex string of alert master private key\n"
2451 "<minver> is the minimum applicable internal client version\n"
2452 "<maxver> is the maximum applicable internal client version\n"
2453 "<priority> is integer priority number\n"
2454 "<id> is the alert id\n"
2455 "[cancelupto] cancels all alert id's up to this number\n"
2456 "Returns true or false.");
2461 alert.strStatusBar = params[0].get_str();
2462 alert.nMinVer = params[2].get_int();
2463 alert.nMaxVer = params[3].get_int();
2464 alert.nPriority = params[4].get_int();
2465 alert.nID = params[5].get_int();
2466 if (params.size() > 6)
2467 alert.nCancel = params[6].get_int();
2468 alert.nVersion = PROTOCOL_VERSION;
2469 alert.nRelayUntil = GetAdjustedTime() + 365*24*60*60;
2470 alert.nExpiration = GetAdjustedTime() + 365*24*60*60;
2472 CDataStream sMsg(SER_NETWORK, PROTOCOL_VERSION);
2473 sMsg << (CUnsignedAlert)alert;
2474 alert.vchMsg = vector<unsigned char>(sMsg.begin(), sMsg.end());
2476 vector<unsigned char> vchPrivKey = ParseHex(params[1].get_str());
2477 key.SetPrivKey(CPrivKey(vchPrivKey.begin(), vchPrivKey.end())); // if key is not correct openssl may crash
2478 if (!key.Sign(Hash(alert.vchMsg.begin(), alert.vchMsg.end()), alert.vchSig))
2479 throw runtime_error(
2480 "Unable to sign alert, check private key?\n");
2481 if(!alert.ProcessAlert())
2482 throw runtime_error(
2483 "Failed to process alert.\n");
2487 BOOST_FOREACH(CNode* pnode, vNodes)
2488 alert.RelayTo(pnode);
2492 result.push_back(Pair("strStatusBar", alert.strStatusBar));
2493 result.push_back(Pair("nVersion", alert.nVersion));
2494 result.push_back(Pair("nMinVer", alert.nMinVer));
2495 result.push_back(Pair("nMaxVer", alert.nMaxVer));
2496 result.push_back(Pair("nPriority", alert.nPriority));
2497 result.push_back(Pair("nID", alert.nID));
2498 if (alert.nCancel > 0)
2499 result.push_back(Pair("nCancel", alert.nCancel));
2510 static const CRPCCommand vRPCCommands[] =
2511 { // name function safe mode?
2512 // ------------------------ ----------------------- ----------
2513 { "help", &help, true },
2514 { "stop", &stop, true },
2515 { "getblockcount", &getblockcount, true },
2516 { "getblocknumber", &getblocknumber, true },
2517 { "getconnectioncount", &getconnectioncount, true },
2518 { "getdifficulty", &getdifficulty, true },
2519 { "getgenerate", &getgenerate, true },
2520 { "setgenerate", &setgenerate, true },
2521 { "gethashespersec", &gethashespersec, true },
2522 { "getinfo", &getinfo, true },
2523 { "getmininginfo", &getmininginfo, true },
2524 { "getnewaddress", &getnewaddress, true },
2525 { "getnewpubkey", &getnewpubkey, true },
2526 { "getaccountaddress", &getaccountaddress, true },
2527 { "setaccount", &setaccount, true },
2528 { "getaccount", &getaccount, false },
2529 { "getaddressesbyaccount", &getaddressesbyaccount, true },
2530 { "sendtoaddress", &sendtoaddress, false },
2531 { "getreceivedbyaddress", &getreceivedbyaddress, false },
2532 { "getreceivedbyaccount", &getreceivedbyaccount, false },
2533 { "listreceivedbyaddress", &listreceivedbyaddress, false },
2534 { "listreceivedbyaccount", &listreceivedbyaccount, false },
2535 { "backupwallet", &backupwallet, true },
2536 { "keypoolrefill", &keypoolrefill, true },
2537 { "walletpassphrase", &walletpassphrase, true },
2538 { "walletpassphrasechange", &walletpassphrasechange, false },
2539 { "walletlock", &walletlock, true },
2540 { "encryptwallet", &encryptwallet, false },
2541 { "validateaddress", &validateaddress, true },
2542 { "getbalance", &getbalance, false },
2543 { "move", &movecmd, false },
2544 { "sendfrom", &sendfrom, false },
2545 { "sendmany", &sendmany, false },
2546 { "addmultisigaddress", &addmultisigaddress, false },
2547 { "getblock", &getblock, false },
2548 { "getblockhash", &getblockhash, false },
2549 { "getblockbynumber", &getblockbynumber, false },
2550 { "gettransaction", &gettransaction, false },
2551 { "listtransactions", &listtransactions, false },
2552 { "signmessage", &signmessage, false },
2553 { "verifymessage", &verifymessage, false },
2554 { "getwork", &getwork, true },
2555 { "listaccounts", &listaccounts, false },
2556 { "settxfee", &settxfee, false },
2557 { "getmemorypool", &getmemorypool, true },
2558 { "getblocktemplate", &getblocktemplate, true },
2559 { "submitblock", &submitblock, false },
2560 { "listsinceblock", &listsinceblock, false },
2561 { "dumpprivkey", &dumpprivkey, false },
2562 { "importprivkey", &importprivkey, false },
2563 { "getcheckpoint", &getcheckpoint, true },
2564 { "reservebalance", &reservebalance, false},
2565 { "checkwallet", &checkwallet, false},
2566 { "repairwallet", &repairwallet, false},
2567 { "resendtx", &resendtx, false},
2568 { "makekeypair", &makekeypair, false},
2569 { "sendalert", &sendalert, false},
2572 CRPCTable::CRPCTable()
2575 for (vcidx = 0; vcidx < (sizeof(vRPCCommands) / sizeof(vRPCCommands[0])); vcidx++)
2577 const CRPCCommand *pcmd;
2579 pcmd = &vRPCCommands[vcidx];
2580 mapCommands[pcmd->name] = pcmd;
2584 const CRPCCommand *CRPCTable::operator[](string name) const
2586 map<string, const CRPCCommand*>::const_iterator it = mapCommands.find(name);
2587 if (it == mapCommands.end())
2589 return (*it).second;
2595 // This ain't Apache. We're just using HTTP header for the length field
2596 // and to be compatible with other JSON-RPC implementations.
2599 string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
2602 s << "POST / HTTP/1.1\r\n"
2603 << "User-Agent: novacoin-json-rpc/" << FormatFullVersion() << "\r\n"
2604 << "Host: 127.0.0.1\r\n"
2605 << "Content-Type: application/json\r\n"
2606 << "Content-Length: " << strMsg.size() << "\r\n"
2607 << "Connection: close\r\n"
2608 << "Accept: application/json\r\n";
2609 BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
2610 s << item.first << ": " << item.second << "\r\n";
2611 s << "\r\n" << strMsg;
2616 string rfc1123Time()
2621 struct tm* now_gmt = gmtime(&now);
2622 string locale(setlocale(LC_TIME, NULL));
2623 setlocale(LC_TIME, "C"); // we want posix (aka "C") weekday/month strings
2624 strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt);
2625 setlocale(LC_TIME, locale.c_str());
2626 return string(buffer);
2629 static string HTTPReply(int nStatus, const string& strMsg)
2632 return strprintf("HTTP/1.0 401 Authorization Required\r\n"
2634 "Server: novacoin-json-rpc/%s\r\n"
2635 "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
2636 "Content-Type: text/html\r\n"
2637 "Content-Length: 296\r\n"
2639 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
2640 "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
2643 "<TITLE>Error</TITLE>\r\n"
2644 "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
2646 "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
2647 "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
2648 const char *cStatus;
2649 if (nStatus == 200) cStatus = "OK";
2650 else if (nStatus == 400) cStatus = "Bad Request";
2651 else if (nStatus == 403) cStatus = "Forbidden";
2652 else if (nStatus == 404) cStatus = "Not Found";
2653 else if (nStatus == 500) cStatus = "Internal Server Error";
2656 "HTTP/1.1 %d %s\r\n"
2658 "Connection: close\r\n"
2659 "Content-Length: %d\r\n"
2660 "Content-Type: application/json\r\n"
2661 "Server: novacoin-json-rpc/%s\r\n"
2666 rfc1123Time().c_str(),
2668 FormatFullVersion().c_str(),
2672 int ReadHTTPStatus(std::basic_istream<char>& stream)
2675 getline(stream, str);
2676 vector<string> vWords;
2677 boost::split(vWords, str, boost::is_any_of(" "));
2678 if (vWords.size() < 2)
2680 return atoi(vWords[1].c_str());
2683 int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
2689 std::getline(stream, str);
2690 if (str.empty() || str == "\r")
2692 string::size_type nColon = str.find(":");
2693 if (nColon != string::npos)
2695 string strHeader = str.substr(0, nColon);
2696 boost::trim(strHeader);
2697 boost::to_lower(strHeader);
2698 string strValue = str.substr(nColon+1);
2699 boost::trim(strValue);
2700 mapHeadersRet[strHeader] = strValue;
2701 if (strHeader == "content-length")
2702 nLen = atoi(strValue.c_str());
2708 int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
2710 mapHeadersRet.clear();
2714 int nStatus = ReadHTTPStatus(stream);
2717 int nLen = ReadHTTPHeader(stream, mapHeadersRet);
2718 if (nLen < 0 || nLen > (int)MAX_SIZE)
2724 vector<char> vch(nLen);
2725 stream.read(&vch[0], nLen);
2726 strMessageRet = string(vch.begin(), vch.end());
2732 bool HTTPAuthorized(map<string, string>& mapHeaders)
2734 string strAuth = mapHeaders["authorization"];
2735 if (strAuth.substr(0,6) != "Basic ")
2737 string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
2738 string strUserPass = DecodeBase64(strUserPass64);
2739 return strUserPass == strRPCUserColonPass;
2743 // JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
2744 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
2745 // unspecified (HTTP errors and contents of 'error').
2747 // 1.0 spec: http://json-rpc.org/wiki/specification
2748 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
2749 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
2752 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
2755 request.push_back(Pair("method", strMethod));
2756 request.push_back(Pair("params", params));
2757 request.push_back(Pair("id", id));
2758 return write_string(Value(request), false) + "\n";
2761 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
2764 if (error.type() != null_type)
2765 reply.push_back(Pair("result", Value::null));
2767 reply.push_back(Pair("result", result));
2768 reply.push_back(Pair("error", error));
2769 reply.push_back(Pair("id", id));
2770 return write_string(Value(reply), false) + "\n";
2773 void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
2775 // Send error reply from json-rpc error object
2777 int code = find_value(objError, "code").get_int();
2778 if (code == -32600) nStatus = 400;
2779 else if (code == -32601) nStatus = 404;
2780 string strReply = JSONRPCReply(Value::null, objError, id);
2781 stream << HTTPReply(nStatus, strReply) << std::flush;
2784 bool ClientAllowed(const string& strAddress)
2786 if (strAddress == asio::ip::address_v4::loopback().to_string())
2788 const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
2789 BOOST_FOREACH(string strAllow, vAllow)
2790 if (WildcardMatch(strAddress, strAllow))
2796 // IOStream device that speaks SSL but can also speak non-SSL
2798 class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
2800 SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
2802 fUseSSL = fUseSSLIn;
2803 fNeedHandshake = fUseSSLIn;
2806 void handshake(ssl::stream_base::handshake_type role)
2808 if (!fNeedHandshake) return;
2809 fNeedHandshake = false;
2810 stream.handshake(role);
2812 std::streamsize read(char* s, std::streamsize n)
2814 handshake(ssl::stream_base::server); // HTTPS servers read first
2815 if (fUseSSL) return stream.read_some(asio::buffer(s, n));
2816 return stream.next_layer().read_some(asio::buffer(s, n));
2818 std::streamsize write(const char* s, std::streamsize n)
2820 handshake(ssl::stream_base::client); // HTTPS clients write first
2821 if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
2822 return asio::write(stream.next_layer(), asio::buffer(s, n));
2824 bool connect(const std::string& server, const std::string& port)
2826 ip::tcp::resolver resolver(stream.get_io_service());
2827 ip::tcp::resolver::query query(server.c_str(), port.c_str());
2828 ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
2829 ip::tcp::resolver::iterator end;
2830 boost::system::error_code error = asio::error::host_not_found;
2831 while (error && endpoint_iterator != end)
2833 stream.lowest_layer().close();
2834 stream.lowest_layer().connect(*endpoint_iterator++, error);
2842 bool fNeedHandshake;
2847 void ThreadRPCServer(void* parg)
2849 IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
2852 vnThreadsRunning[THREAD_RPCSERVER]++;
2853 ThreadRPCServer2(parg);
2854 vnThreadsRunning[THREAD_RPCSERVER]--;
2856 catch (std::exception& e) {
2857 vnThreadsRunning[THREAD_RPCSERVER]--;
2858 PrintException(&e, "ThreadRPCServer()");
2860 vnThreadsRunning[THREAD_RPCSERVER]--;
2861 PrintException(NULL, "ThreadRPCServer()");
2863 printf("ThreadRPCServer exiting\n");
2866 void ThreadRPCServer2(void* parg)
2868 printf("ThreadRPCServer started\n");
2870 strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
2871 if (mapArgs["-rpcpassword"] == "")
2873 unsigned char rand_pwd[32];
2874 RAND_bytes(rand_pwd, 32);
2875 string strWhatAmI = "To use novacoind";
2876 if (mapArgs.count("-server"))
2877 strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
2878 else if (mapArgs.count("-daemon"))
2879 strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
2880 ThreadSafeMessageBox(strprintf(
2881 _("%s, you must set a rpcpassword in the configuration file:\n %s\n"
2882 "It is recommended you use the following random password:\n"
2885 "(you do not need to remember this password)\n"
2886 "If the file does not exist, create it with owner-readable-only file permissions.\n"),
2888 GetConfigFile().string().c_str(),
2889 EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str()),
2890 _("Error"), wxOK | wxMODAL);
2895 bool fUseSSL = GetBoolArg("-rpcssl");
2896 asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
2898 asio::io_service io_service;
2899 ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", RPC_PORT));
2900 ip::tcp::acceptor acceptor(io_service);
2903 acceptor.open(endpoint.protocol());
2904 acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
2905 acceptor.bind(endpoint);
2906 acceptor.listen(socket_base::max_connections);
2908 catch(boost::system::system_error &e)
2910 ThreadSafeMessageBox(strprintf(_("An error occured while setting up the RPC port %i for listening: %s"), endpoint.port(), e.what()),
2911 _("Error"), wxOK | wxMODAL);
2916 ssl::context context(io_service, ssl::context::sslv23);
2919 context.set_options(ssl::context::no_sslv2);
2921 filesystem::path pathCertFile(GetArg("-rpcsslcertificatechainfile", "server.cert"));
2922 if (!pathCertFile.is_complete()) pathCertFile = filesystem::path(GetDataDir()) / pathCertFile;
2923 if (filesystem::exists(pathCertFile)) context.use_certificate_chain_file(pathCertFile.string());
2924 else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", pathCertFile.string().c_str());
2926 filesystem::path pathPKFile(GetArg("-rpcsslprivatekeyfile", "server.pem"));
2927 if (!pathPKFile.is_complete()) pathPKFile = filesystem::path(GetDataDir()) / pathPKFile;
2928 if (filesystem::exists(pathPKFile)) context.use_private_key_file(pathPKFile.string(), ssl::context::pem);
2929 else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pathPKFile.string().c_str());
2931 string strCiphers = GetArg("-rpcsslciphers", "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
2932 SSL_CTX_set_cipher_list(context.impl(), strCiphers.c_str());
2937 // Accept connection
2938 SSLStream sslStream(io_service, context);
2939 SSLIOStreamDevice d(sslStream, fUseSSL);
2940 iostreams::stream<SSLIOStreamDevice> stream(d);
2942 ip::tcp::endpoint peer;
2943 vnThreadsRunning[THREAD_RPCSERVER]--;
2944 acceptor.accept(sslStream.lowest_layer(), peer);
2945 vnThreadsRunning[4]++;
2949 // Restrict callers by IP
2950 if (!ClientAllowed(peer.address().to_string()))
2952 // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
2954 stream << HTTPReply(403, "") << std::flush;
2958 map<string, string> mapHeaders;
2961 boost::thread api_caller(ReadHTTP, boost::ref(stream), boost::ref(mapHeaders), boost::ref(strRequest));
2962 if (!api_caller.timed_join(boost::posix_time::seconds(GetArg("-rpctimeout", 30))))
2965 printf("ThreadRPCServer ReadHTTP timeout\n");
2969 // Check authorization
2970 if (mapHeaders.count("authorization") == 0)
2972 stream << HTTPReply(401, "") << std::flush;
2975 if (!HTTPAuthorized(mapHeaders))
2977 printf("ThreadRPCServer incorrect password attempt from %s\n",peer.address().to_string().c_str());
2978 /* Deter brute-forcing short passwords.
2979 If this results in a DOS the user really
2980 shouldn't have their RPC port exposed.*/
2981 if (mapArgs["-rpcpassword"].size() < 20)
2984 stream << HTTPReply(401, "") << std::flush;
2988 Value id = Value::null;
2993 if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
2994 throw JSONRPCError(-32700, "Parse error");
2995 const Object& request = valRequest.get_obj();
2997 // Parse id now so errors from here on will have the id
2998 id = find_value(request, "id");
3001 Value valMethod = find_value(request, "method");
3002 if (valMethod.type() == null_type)
3003 throw JSONRPCError(-32600, "Missing method");
3004 if (valMethod.type() != str_type)
3005 throw JSONRPCError(-32600, "Method must be a string");
3006 string strMethod = valMethod.get_str();
3007 if (strMethod != "getwork" && strMethod != "getmemorypool")
3008 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
3011 Value valParams = find_value(request, "params");
3013 if (valParams.type() == array_type)
3014 params = valParams.get_array();
3015 else if (valParams.type() == null_type)
3018 throw JSONRPCError(-32600, "Params must be an array");
3021 const CRPCCommand *pcmd = tableRPC[strMethod];
3023 throw JSONRPCError(-32601, "Method not found");
3025 // Observe safe mode
3026 string strWarning = GetWarnings("rpc");
3027 if (strWarning != "" && !GetBoolArg("-disablesafemode") &&
3029 throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
3036 LOCK2(cs_main, pwalletMain->cs_wallet);
3037 result = pcmd->actor(params, false);
3041 string strReply = JSONRPCReply(result, Value::null, id);
3042 stream << HTTPReply(200, strReply) << std::flush;
3044 catch (std::exception& e)
3046 ErrorReply(stream, JSONRPCError(-1, e.what()), id);
3049 catch (Object& objError)
3051 ErrorReply(stream, objError, id);
3053 catch (std::exception& e)
3055 ErrorReply(stream, JSONRPCError(-32700, e.what()), id);
3063 Object CallRPC(const string& strMethod, const Array& params)
3065 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
3066 throw runtime_error(strprintf(
3067 _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
3068 "If the file does not exist, create it with owner-readable-only file permissions."),
3069 GetConfigFile().string().c_str()));
3071 // Connect to localhost
3072 bool fUseSSL = GetBoolArg("-rpcssl");
3073 asio::io_service io_service;
3074 ssl::context context(io_service, ssl::context::sslv23);
3075 context.set_options(ssl::context::no_sslv2);
3076 SSLStream sslStream(io_service, context);
3077 SSLIOStreamDevice d(sslStream, fUseSSL);
3078 iostreams::stream<SSLIOStreamDevice> stream(d);
3079 if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", CBigNum(RPC_PORT).ToString().c_str())))
3080 throw runtime_error("couldn't connect to server");
3082 // HTTP basic authentication
3083 string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
3084 map<string, string> mapRequestHeaders;
3085 mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
3088 string strRequest = JSONRPCRequest(strMethod, params, 1);
3089 string strPost = HTTPPost(strRequest, mapRequestHeaders);
3090 stream << strPost << std::flush;
3093 map<string, string> mapHeaders;
3095 int nStatus = ReadHTTP(stream, mapHeaders, strReply);
3097 throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
3098 else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
3099 throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
3100 else if (strReply.empty())
3101 throw runtime_error("no response from server");
3105 if (!read_string(strReply, valReply))
3106 throw runtime_error("couldn't parse reply from server");
3107 const Object& reply = valReply.get_obj();
3109 throw runtime_error("expected reply to have result, error and id properties");
3117 template<typename T>
3118 void ConvertTo(Value& value)
3120 if (value.type() == str_type)
3122 // reinterpret string as unquoted json value
3124 if (!read_string(value.get_str(), value2))
3125 throw runtime_error("type mismatch");
3126 value = value2.get_value<T>();
3130 value = value.get_value<T>();
3134 int CommandLineRPC(int argc, char *argv[])
3141 while (argc > 1 && IsSwitchChar(argv[1][0]))
3149 throw runtime_error("too few parameters");
3150 string strMethod = argv[1];
3152 // Parameters default to strings
3154 for (int i = 2; i < argc; i++)
3155 params.push_back(argv[i]);
3156 int n = params.size();
3159 // Special case non-string parameter types
3161 if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
3162 if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
3163 if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
3164 if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]);
3165 if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
3166 if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]);
3167 if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
3168 if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
3169 if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]);
3170 if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
3171 if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]);
3172 if (strMethod == "getblockhash" && n > 0) ConvertTo<boost::int64_t>(params[0]);
3173 if (strMethod == "getblockbynumber" && n > 0) ConvertTo<boost::int64_t>(params[0]);
3174 if (strMethod == "getblockbynumber" && n > 1) ConvertTo<bool>(params[1]);
3175 if (strMethod == "getblock" && n > 1) ConvertTo<bool>(params[1]);
3176 if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]);
3177 if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]);
3178 if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]);
3179 if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]);
3180 if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
3181 if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]);
3182 if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]);
3183 if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]);
3184 if (strMethod == "walletpassphrase" && n > 2) ConvertTo<bool>(params[2]);
3185 if (strMethod == "listsinceblock" && n > 1) ConvertTo<boost::int64_t>(params[1]);
3186 if (strMethod == "sendalert" && n > 2) ConvertTo<boost::int64_t>(params[2]);
3187 if (strMethod == "sendalert" && n > 3) ConvertTo<boost::int64_t>(params[3]);
3188 if (strMethod == "sendalert" && n > 4) ConvertTo<boost::int64_t>(params[4]);
3189 if (strMethod == "sendalert" && n > 5) ConvertTo<boost::int64_t>(params[5]);
3190 if (strMethod == "sendalert" && n > 6) ConvertTo<boost::int64_t>(params[6]);
3191 if (strMethod == "sendmany" && n > 1)
3193 string s = params[1].get_str();
3195 if (!read_string(s, v) || v.type() != obj_type)
3196 throw runtime_error("type mismatch");
3197 params[1] = v.get_obj();
3199 if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]);
3200 if (strMethod == "reservebalance" && n > 0) ConvertTo<bool>(params[0]);
3201 if (strMethod == "reservebalance" && n > 1) ConvertTo<double>(params[1]);
3202 if (strMethod == "addmultisigaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
3203 if (strMethod == "addmultisigaddress" && n > 1)
3205 string s = params[1].get_str();
3207 if (!read_string(s, v) || v.type() != array_type)
3208 throw runtime_error("type mismatch "+s);
3209 params[1] = v.get_array();
3213 Object reply = CallRPC(strMethod, params);
3216 const Value& result = find_value(reply, "result");
3217 const Value& error = find_value(reply, "error");
3219 if (error.type() != null_type)
3222 strPrint = "error: " + write_string(error, false);
3223 int code = find_value(error.get_obj(), "code").get_int();
3229 if (result.type() == null_type)
3231 else if (result.type() == str_type)
3232 strPrint = result.get_str();
3234 strPrint = write_string(result, true);
3237 catch (std::exception& e)
3239 strPrint = string("error: ") + e.what();
3244 PrintException(NULL, "CommandLineRPC()");
3249 fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
3258 int main(int argc, char *argv[])
3261 // Turn off microsoft heap dump noise
3262 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
3263 _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
3265 setbuf(stdin, NULL);
3266 setbuf(stdout, NULL);
3267 setbuf(stderr, NULL);
3271 if (argc >= 2 && string(argv[1]) == "-server")
3273 printf("server ready\n");
3274 ThreadRPCServer(NULL);
3278 return CommandLineRPC(argc, argv);
3281 catch (std::exception& e) {
3282 PrintException(&e, "main()");
3284 PrintException(NULL, "main()");
3290 const CRPCTable tableRPC;