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 validatepubkey(const Array& params, bool fHelp)
1811 if (fHelp || !params.size() || params.size() > 2)
1812 throw runtime_error(
1813 "validatepubkey <novacoinpubkey>\n"
1814 "Return information about <novacoinpubkey>.");
1816 std::vector<unsigned char> vchPubKey = ParseHex(params[0].get_str());
1819 if(vchPubKey.size() == 33) // Compressed key
1820 isValid = (vchPubKey[0] == 0x02 || vchPubKey[0] == 0x03);
1821 else if(vchPubKey.size() == 65) // Uncompressed key
1822 isValid = vchPubKey[0] == 0x04;
1826 CBitcoinAddress address(vchPubKey);
1827 isValid = isValid ? address.IsValid() : false;
1830 ret.push_back(Pair("isvalid", isValid));
1833 // Call Hash160ToAddress() so we always return current ADDRESSVERSION
1834 // version of the address:
1835 string currentAddress = address.ToString();
1836 ret.push_back(Pair("address", currentAddress));
1837 if (pwalletMain->HaveKey(address))
1839 ret.push_back(Pair("ismine", true));
1841 key.SetPubKey(vchPubKey);
1842 ret.push_back(Pair("iscompressed", key.IsCompressed()));
1845 ret.push_back(Pair("ismine", false));
1846 if (pwalletMain->mapAddressBook.count(address))
1847 ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
1853 Value getwork(const Array& params, bool fHelp)
1855 if (fHelp || params.size() > 1)
1856 throw runtime_error(
1858 "If [data] is not specified, returns formatted hash data to work on:\n"
1859 " \"midstate\" : precomputed hash state after hashing the first half of the data (DEPRECATED)\n" // deprecated
1860 " \"data\" : block data\n"
1861 " \"hash1\" : formatted hash buffer for second hash (DEPRECATED)\n" // deprecated
1862 " \"target\" : little endian hash target\n"
1863 "If [data] is specified, tries to solve the block and returns true if it was successful.");
1866 throw JSONRPCError(-9, "NovaCoin is not connected!");
1868 if (IsInitialBlockDownload())
1869 throw JSONRPCError(-10, "NovaCoin is downloading blocks...");
1871 typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
1872 static mapNewBlock_t mapNewBlock;
1873 static vector<CBlock*> vNewBlock;
1874 static CReserveKey reservekey(pwalletMain);
1876 if (params.size() == 0)
1879 static unsigned int nTransactionsUpdatedLast;
1880 static CBlockIndex* pindexPrev;
1881 static int64 nStart;
1882 static CBlock* pblock;
1883 if (pindexPrev != pindexBest ||
1884 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
1886 if (pindexPrev != pindexBest)
1888 // Deallocate old blocks since they're obsolete now
1889 mapNewBlock.clear();
1890 BOOST_FOREACH(CBlock* pblock, vNewBlock)
1894 nTransactionsUpdatedLast = nTransactionsUpdated;
1895 pindexPrev = pindexBest;
1899 pblock = CreateNewBlock(pwalletMain);
1901 throw JSONRPCError(-7, "Out of memory");
1902 vNewBlock.push_back(pblock);
1906 pblock->UpdateTime(pindexPrev);
1909 // Update nExtraNonce
1910 static unsigned int nExtraNonce = 0;
1911 IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
1914 mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
1916 // Prebuild hash buffers
1920 FormatHashBuffers(pblock, pmidstate, pdata, phash1);
1922 uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
1925 result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate)))); // deprecated
1926 result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata))));
1927 result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1)))); // deprecated
1928 result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
1934 vector<unsigned char> vchData = ParseHex(params[0].get_str());
1935 if (vchData.size() != 128)
1936 throw JSONRPCError(-8, "Invalid parameter");
1937 CBlock* pdata = (CBlock*)&vchData[0];
1940 for (int i = 0; i < 128/4; i++)
1941 ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]);
1944 if (!mapNewBlock.count(pdata->hashMerkleRoot))
1946 CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
1948 pblock->nTime = pdata->nTime;
1949 pblock->nNonce = pdata->nNonce;
1950 pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
1951 pblock->hashMerkleRoot = pblock->BuildMerkleTree();
1952 if (!pblock->SignBlock(*pwalletMain))
1953 throw JSONRPCError(-100, "Unable to sign block, wallet locked?");
1955 return CheckWork(pblock, *pwalletMain, reservekey);
1959 Value getblocktemplate(const Array& params, bool fHelp)
1961 if (fHelp || params.size() > 1)
1962 throw runtime_error(
1963 "getblocktemplate [params]\n"
1964 "Returns data needed to construct a block to work on:\n"
1965 " \"version\" : block version\n"
1966 " \"previousblockhash\" : hash of current highest block\n"
1967 " \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
1968 " \"coinbaseaux\" : data that should be included in coinbase\n"
1969 " \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
1970 " \"target\" : hash target\n"
1971 " \"mintime\" : minimum timestamp appropriate for next block\n"
1972 " \"curtime\" : current timestamp\n"
1973 " \"mutable\" : list of ways the block template may be changed\n"
1974 " \"noncerange\" : range of valid nonces\n"
1975 " \"sigoplimit\" : limit of sigops in blocks\n"
1976 " \"sizelimit\" : limit of block size\n"
1977 " \"bits\" : compressed target of next block\n"
1978 " \"height\" : height of the next block\n"
1979 "See https://en.bitcoin.it/wiki/BIP_0022 for full specification.");
1981 std::string strMode = "template";
1982 if (params.size() > 0)
1984 const Object& oparam = params[0].get_obj();
1985 const Value& modeval = find_value(oparam, "mode");
1986 if (modeval.type() == str_type)
1987 strMode = modeval.get_str();
1989 throw JSONRPCError(-8, "Invalid mode");
1992 if (strMode != "template")
1993 throw JSONRPCError(-8, "Invalid mode");
1996 throw JSONRPCError(-9, "NovaCoin is not connected!");
1998 if (IsInitialBlockDownload())
1999 throw JSONRPCError(-10, "NovaCoin is downloading blocks...");
2001 static CReserveKey reservekey(pwalletMain);
2004 static unsigned int nTransactionsUpdatedLast;
2005 static CBlockIndex* pindexPrev;
2006 static int64 nStart;
2007 static CBlock* pblock;
2008 if (pindexPrev != pindexBest ||
2009 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5))
2011 // Clear pindexPrev so future calls make a new block, despite any failures from here on
2014 // Store the pindexBest used before CreateNewBlock, to avoid races
2015 nTransactionsUpdatedLast = nTransactionsUpdated;
2016 CBlockIndex* pindexPrevNew = pindexBest;
2025 pblock = CreateNewBlock(pwalletMain);
2027 throw JSONRPCError(-7, "Out of memory");
2029 // Need to update only after we know CreateNewBlock succeeded
2030 pindexPrev = pindexPrevNew;
2034 pblock->UpdateTime(pindexPrev);
2038 map<uint256, int64_t> setTxIndex;
2041 BOOST_FOREACH (CTransaction& tx, pblock->vtx)
2043 uint256 txHash = tx.GetHash();
2044 setTxIndex[txHash] = i++;
2046 if (tx.IsCoinBase() || tx.IsCoinStake())
2051 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
2053 entry.push_back(Pair("data", HexStr(ssTx.begin(), ssTx.end())));
2055 entry.push_back(Pair("hash", txHash.GetHex()));
2057 MapPrevTx mapInputs;
2058 map<uint256, CTxIndex> mapUnused;
2059 bool fInvalid = false;
2060 if (tx.FetchInputs(txdb, mapUnused, false, false, mapInputs, fInvalid))
2062 entry.push_back(Pair("fee", (int64_t)(tx.GetValueIn(mapInputs) - tx.GetValueOut())));
2065 BOOST_FOREACH (MapPrevTx::value_type& inp, mapInputs)
2067 if (setTxIndex.count(inp.first))
2068 deps.push_back(setTxIndex[inp.first]);
2070 entry.push_back(Pair("depends", deps));
2072 int64_t nSigOps = tx.GetLegacySigOpCount();
2073 nSigOps += tx.GetP2SHSigOpCount(mapInputs);
2074 entry.push_back(Pair("sigops", nSigOps));
2077 transactions.push_back(entry);
2081 aux.push_back(Pair("flags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end())));
2083 uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
2085 static Array aMutable;
2086 if (aMutable.empty())
2088 aMutable.push_back("time");
2089 aMutable.push_back("transactions");
2090 aMutable.push_back("prevblock");
2094 result.push_back(Pair("version", pblock->nVersion));
2095 result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
2096 result.push_back(Pair("transactions", transactions));
2097 result.push_back(Pair("coinbaseaux", aux));
2098 result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
2099 result.push_back(Pair("target", hashTarget.GetHex()));
2100 result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1));
2101 result.push_back(Pair("mutable", aMutable));
2102 result.push_back(Pair("noncerange", "00000000ffffffff"));
2103 result.push_back(Pair("sigoplimit", (int64_t)MAX_BLOCK_SIGOPS));
2104 result.push_back(Pair("sizelimit", (int64_t)MAX_BLOCK_SIZE));
2105 result.push_back(Pair("curtime", (int64_t)pblock->nTime));
2106 result.push_back(Pair("bits", HexBits(pblock->nBits)));
2107 result.push_back(Pair("height", (int64_t)(pindexPrev->nHeight+1)));
2112 Value submitblock(const Array& params, bool fHelp)
2114 if (fHelp || params.size() < 1 || params.size() > 2)
2115 throw runtime_error(
2116 "submitblock <hex data> [optional-params-obj]\n"
2117 "[optional-params-obj] parameter is currently ignored.\n"
2118 "Attempts to submit new block to network.\n"
2119 "See https://en.bitcoin.it/wiki/BIP_0022 for full specification.");
2121 vector<unsigned char> blockData(ParseHex(params[0].get_str()));
2122 CDataStream ssBlock(blockData, SER_NETWORK, PROTOCOL_VERSION);
2127 catch (std::exception &e) {
2128 throw JSONRPCError(-22, "Block decode failed");
2131 static CReserveKey reservekey(pwalletMain);
2133 if(!block.SignBlock(*pwalletMain))
2134 throw JSONRPCError(-100, "Unable to sign block, wallet locked?");
2136 bool fAccepted = CheckWork(&block, *pwalletMain, reservekey);
2144 Value getmemorypool(const Array& params, bool fHelp)
2146 if (fHelp || params.size() > 1)
2147 throw runtime_error(
2148 "getmemorypool [data]\n"
2149 "If [data] is not specified, returns data needed to construct a block to work on:\n"
2150 " \"version\" : block version\n"
2151 " \"previousblockhash\" : hash of current highest block\n"
2152 " \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
2153 " \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
2154 " \"coinbaseflags\" : data that should be included in coinbase so support for new features can be judged\n"
2155 " \"time\" : timestamp appropriate for next block\n"
2156 " \"mintime\" : minimum timestamp appropriate for next block\n"
2157 " \"curtime\" : current timestamp\n"
2158 " \"bits\" : compressed target of next block\n"
2159 "If [data] is specified, tries to solve the block and returns true if it was successful.");
2161 if (params.size() == 0)
2164 throw JSONRPCError(-9, "NovaCoin is not connected!");
2166 if (IsInitialBlockDownload())
2167 throw JSONRPCError(-10, "NovaCoin is downloading blocks...");
2169 static CReserveKey reservekey(pwalletMain);
2172 static unsigned int nTransactionsUpdatedLast;
2173 static CBlockIndex* pindexPrev;
2174 static int64 nStart;
2175 static CBlock* pblock;
2176 if (pindexPrev != pindexBest ||
2177 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5))
2179 nTransactionsUpdatedLast = nTransactionsUpdated;
2180 pindexPrev = pindexBest;
2186 pblock = CreateNewBlock(pwalletMain);
2188 throw JSONRPCError(-7, "Out of memory");
2192 pblock->UpdateTime(pindexPrev);
2196 BOOST_FOREACH(CTransaction tx, pblock->vtx) {
2197 if(tx.IsCoinBase() || tx.IsCoinStake())
2200 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
2203 transactions.push_back(HexStr(ssTx.begin(), ssTx.end()));
2207 result.push_back(Pair("version", pblock->nVersion));
2208 result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
2209 result.push_back(Pair("transactions", transactions));
2210 result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
2211 result.push_back(Pair("coinbaseflags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end())));
2212 result.push_back(Pair("time", (int64_t)pblock->nTime));
2213 result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1));
2214 result.push_back(Pair("curtime", (int64_t)GetAdjustedTime()));
2215 result.push_back(Pair("bits", HexBits(pblock->nBits)));
2222 CDataStream ssBlock(ParseHex(params[0].get_str()), SER_NETWORK, PROTOCOL_VERSION);
2226 static CReserveKey reservekey(pwalletMain);
2228 if(!pblock.SignBlock(*pwalletMain))
2229 throw JSONRPCError(-100, "Unable to sign block, wallet locked?");
2231 return CheckWork(&pblock, *pwalletMain, reservekey);
2235 Value getnewpubkey(const Array& params, bool fHelp)
2237 if (fHelp || params.size() > 1)
2238 throw runtime_error(
2239 "getnewpubkey [account]\n"
2240 "Returns new public key for coinbase generation.");
2242 // Parse the account first so we don't generate a key if there's an error
2244 if (params.size() > 0)
2245 strAccount = AccountFromValue(params[0]);
2247 if (!pwalletMain->IsLocked())
2248 pwalletMain->TopUpKeyPool();
2250 // Generate a new key that is added to wallet
2251 std::vector<unsigned char> newKey = pwalletMain->GenerateNewKey(false);
2254 throw JSONRPCError(-12, "Error: Unable to create key");
2256 CBitcoinAddress address(newKey);
2257 pwalletMain->SetAddressBookName(address, strAccount);
2259 return HexStr(newKey.begin(), newKey.end());
2262 Value getblockhash(const Array& params, bool fHelp)
2264 if (fHelp || params.size() != 1)
2265 throw runtime_error(
2266 "getblockhash <index>\n"
2267 "Returns hash of block in best-block-chain at <index>.");
2269 int nHeight = params[0].get_int();
2270 if (nHeight < 0 || nHeight > nBestHeight)
2271 throw runtime_error("Block number out of range.");
2274 CBlockIndex* pblockindex = mapBlockIndex[hashBestChain];
2275 while (pblockindex->nHeight > nHeight)
2276 pblockindex = pblockindex->pprev;
2277 return pblockindex->phashBlock->GetHex();
2280 Value getblock(const Array& params, bool fHelp)
2282 if (fHelp || params.size() < 1 || params.size() > 2)
2283 throw runtime_error(
2284 "getblock <hash> [txinfo]\n"
2285 "txinfo optional to print more detailed tx info\n"
2286 "Returns details of a block with given block-hash.");
2288 std::string strHash = params[0].get_str();
2289 uint256 hash(strHash);
2291 if (mapBlockIndex.count(hash) == 0)
2292 throw JSONRPCError(-5, "Block not found");
2295 CBlockIndex* pblockindex = mapBlockIndex[hash];
2296 block.ReadFromDisk(pblockindex, true);
2298 return blockToJSON(block, pblockindex, params.size() > 1 ? params[1].get_bool() : false);
2301 Value getblockbynumber(const Array& params, bool fHelp)
2303 if (fHelp || params.size() < 1 || params.size() > 2)
2304 throw runtime_error(
2305 "getblock <number> [txinfo]\n"
2306 "txinfo optional to print more detailed tx info\n"
2307 "Returns details of a block with given block-number.");
2309 int nHeight = params[0].get_int();
2310 if (nHeight < 0 || nHeight > nBestHeight)
2311 throw runtime_error("Block number out of range.");
2314 CBlockIndex* pblockindex = mapBlockIndex[hashBestChain];
2315 while (pblockindex->nHeight > nHeight)
2316 pblockindex = pblockindex->pprev;
2318 uint256 hash = *pblockindex->phashBlock;
2320 pblockindex = mapBlockIndex[hash];
2321 block.ReadFromDisk(pblockindex, true);
2323 return blockToJSON(block, pblockindex, params.size() > 1 ? params[1].get_bool() : false);
2326 // ppcoin: get information of sync-checkpoint
2327 Value getcheckpoint(const Array& params, bool fHelp)
2329 if (fHelp || params.size() != 0)
2330 throw runtime_error(
2332 "Show info of synchronized checkpoint.\n");
2335 CBlockIndex* pindexCheckpoint;
2337 result.push_back(Pair("synccheckpoint", Checkpoints::hashSyncCheckpoint.ToString().c_str()));
2338 pindexCheckpoint = mapBlockIndex[Checkpoints::hashSyncCheckpoint];
2339 result.push_back(Pair("height", pindexCheckpoint->nHeight));
2340 result.push_back(Pair("timestamp", DateTimeStrFormat(pindexCheckpoint->GetBlockTime()).c_str()));
2341 if (mapArgs.count("-checkpointkey"))
2342 result.push_back(Pair("checkpointmaster", true));
2348 // ppcoin: reserve balance from being staked for network protection
2349 Value reservebalance(const Array& params, bool fHelp)
2351 if (fHelp || params.size() > 2)
2352 throw runtime_error(
2353 "reservebalance [<reserve> [amount]]\n"
2354 "<reserve> is true or false to turn balance reserve on or off.\n"
2355 "<amount> is a real and rounded to cent.\n"
2356 "Set reserve amount not participating in network protection.\n"
2357 "If no parameters provided current setting is printed.\n");
2359 if (params.size() > 0)
2361 bool fReserve = params[0].get_bool();
2364 if (params.size() == 1)
2365 throw runtime_error("must provide amount to reserve balance.\n");
2366 int64 nAmount = AmountFromValue(params[1]);
2367 nAmount = (nAmount / CENT) * CENT; // round to cent
2369 throw runtime_error("amount cannot be negative.\n");
2370 mapArgs["-reservebalance"] = FormatMoney(nAmount).c_str();
2374 if (params.size() > 1)
2375 throw runtime_error("cannot specify amount to turn off reserve.\n");
2376 mapArgs["-reservebalance"] = "0";
2381 int64 nReserveBalance = 0;
2382 if (mapArgs.count("-reservebalance") && !ParseMoney(mapArgs["-reservebalance"], nReserveBalance))
2383 throw runtime_error("invalid reserve balance amount\n");
2384 result.push_back(Pair("reserve", (nReserveBalance > 0)));
2385 result.push_back(Pair("amount", ValueFromAmount(nReserveBalance)));
2390 // ppcoin: check wallet integrity
2391 Value checkwallet(const Array& params, bool fHelp)
2393 if (fHelp || params.size() > 0)
2394 throw runtime_error(
2396 "Check wallet for integrity.\n");
2399 int64 nBalanceInQuestion;
2400 pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion, true);
2402 if (nMismatchSpent == 0)
2403 result.push_back(Pair("wallet check passed", true));
2406 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
2407 result.push_back(Pair("amount in question", ValueFromAmount(nBalanceInQuestion)));
2413 // ppcoin: repair wallet
2414 Value repairwallet(const Array& params, bool fHelp)
2416 if (fHelp || params.size() > 0)
2417 throw runtime_error(
2419 "Repair wallet if checkwallet reports any problem.\n");
2422 int64 nBalanceInQuestion;
2423 pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion);
2425 if (nMismatchSpent == 0)
2426 result.push_back(Pair("wallet check passed", true));
2429 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
2430 result.push_back(Pair("amount affected by repair", ValueFromAmount(nBalanceInQuestion)));
2435 // NovaCoin: resend unconfirmed wallet transactions
2436 Value resendtx(const Array& params, bool fHelp)
2438 if (fHelp || params.size() > 1)
2439 throw runtime_error(
2441 "Re-send unconfirmed transactions.\n"
2444 ResendWalletTransactions();
2450 // ppcoin: make a public-private key pair
2451 Value makekeypair(const Array& params, bool fHelp)
2453 if (fHelp || params.size() > 1)
2454 throw runtime_error(
2455 "makekeypair [prefix]\n"
2456 "Make a public/private key pair.\n"
2457 "[prefix] is optional preferred prefix for the public key.\n");
2459 string strPrefix = "";
2460 if (params.size() > 0)
2461 strPrefix = params[0].get_str();
2467 key.MakeNewKey(false);
2469 } while (nCount < 10000 && strPrefix != HexStr(key.GetPubKey()).substr(0, strPrefix.size()));
2471 if (strPrefix != HexStr(key.GetPubKey()).substr(0, strPrefix.size()))
2474 CPrivKey vchPrivKey = key.GetPrivKey();
2476 result.push_back(Pair("PrivateKey", HexStr<CPrivKey::iterator>(vchPrivKey.begin(), vchPrivKey.end())));
2477 result.push_back(Pair("PublicKey", HexStr(key.GetPubKey())));
2481 extern CCriticalSection cs_mapAlerts;
2482 extern map<uint256, CAlert> mapAlerts;
2484 // ppcoin: send alert.
2485 // There is a known deadlock situation with ThreadMessageHandler
2486 // ThreadMessageHandler: holds cs_vSend and acquiring cs_main in SendMessages()
2487 // ThreadRPCServer: holds cs_main and acquiring cs_vSend in alert.RelayTo()/PushMessage()/BeginMessage()
2488 Value sendalert(const Array& params, bool fHelp)
2490 if (fHelp || params.size() < 6)
2491 throw runtime_error(
2492 "sendalert <message> <privatekey> <minver> <maxver> <priority> <id> [cancelupto]\n"
2493 "<message> is the alert text message\n"
2494 "<privatekey> is hex string of alert master private key\n"
2495 "<minver> is the minimum applicable internal client version\n"
2496 "<maxver> is the maximum applicable internal client version\n"
2497 "<priority> is integer priority number\n"
2498 "<id> is the alert id\n"
2499 "[cancelupto] cancels all alert id's up to this number\n"
2500 "Returns true or false.");
2505 alert.strStatusBar = params[0].get_str();
2506 alert.nMinVer = params[2].get_int();
2507 alert.nMaxVer = params[3].get_int();
2508 alert.nPriority = params[4].get_int();
2509 alert.nID = params[5].get_int();
2510 if (params.size() > 6)
2511 alert.nCancel = params[6].get_int();
2512 alert.nVersion = PROTOCOL_VERSION;
2513 alert.nRelayUntil = GetAdjustedTime() + 365*24*60*60;
2514 alert.nExpiration = GetAdjustedTime() + 365*24*60*60;
2516 CDataStream sMsg(SER_NETWORK, PROTOCOL_VERSION);
2517 sMsg << (CUnsignedAlert)alert;
2518 alert.vchMsg = vector<unsigned char>(sMsg.begin(), sMsg.end());
2520 vector<unsigned char> vchPrivKey = ParseHex(params[1].get_str());
2521 key.SetPrivKey(CPrivKey(vchPrivKey.begin(), vchPrivKey.end())); // if key is not correct openssl may crash
2522 if (!key.Sign(Hash(alert.vchMsg.begin(), alert.vchMsg.end()), alert.vchSig))
2523 throw runtime_error(
2524 "Unable to sign alert, check private key?\n");
2525 if(!alert.ProcessAlert())
2526 throw runtime_error(
2527 "Failed to process alert.\n");
2531 BOOST_FOREACH(CNode* pnode, vNodes)
2532 alert.RelayTo(pnode);
2536 result.push_back(Pair("strStatusBar", alert.strStatusBar));
2537 result.push_back(Pair("nVersion", alert.nVersion));
2538 result.push_back(Pair("nMinVer", alert.nMinVer));
2539 result.push_back(Pair("nMaxVer", alert.nMaxVer));
2540 result.push_back(Pair("nPriority", alert.nPriority));
2541 result.push_back(Pair("nID", alert.nID));
2542 if (alert.nCancel > 0)
2543 result.push_back(Pair("nCancel", alert.nCancel));
2554 static const CRPCCommand vRPCCommands[] =
2555 { // name function safe mode?
2556 // ------------------------ ----------------------- ----------
2557 { "help", &help, true },
2558 { "stop", &stop, true },
2559 { "getblockcount", &getblockcount, true },
2560 { "getblocknumber", &getblocknumber, true },
2561 { "getconnectioncount", &getconnectioncount, true },
2562 { "getdifficulty", &getdifficulty, true },
2563 { "getgenerate", &getgenerate, true },
2564 { "setgenerate", &setgenerate, true },
2565 { "gethashespersec", &gethashespersec, true },
2566 { "getinfo", &getinfo, true },
2567 { "getmininginfo", &getmininginfo, true },
2568 { "getnewaddress", &getnewaddress, true },
2569 { "getnewpubkey", &getnewpubkey, true },
2570 { "getaccountaddress", &getaccountaddress, true },
2571 { "setaccount", &setaccount, true },
2572 { "getaccount", &getaccount, false },
2573 { "getaddressesbyaccount", &getaddressesbyaccount, true },
2574 { "sendtoaddress", &sendtoaddress, false },
2575 { "getreceivedbyaddress", &getreceivedbyaddress, false },
2576 { "getreceivedbyaccount", &getreceivedbyaccount, false },
2577 { "listreceivedbyaddress", &listreceivedbyaddress, false },
2578 { "listreceivedbyaccount", &listreceivedbyaccount, false },
2579 { "backupwallet", &backupwallet, true },
2580 { "keypoolrefill", &keypoolrefill, true },
2581 { "walletpassphrase", &walletpassphrase, true },
2582 { "walletpassphrasechange", &walletpassphrasechange, false },
2583 { "walletlock", &walletlock, true },
2584 { "encryptwallet", &encryptwallet, false },
2585 { "validateaddress", &validateaddress, true },
2586 { "validatepubkey", &validatepubkey, true },
2587 { "getbalance", &getbalance, false },
2588 { "move", &movecmd, false },
2589 { "sendfrom", &sendfrom, false },
2590 { "sendmany", &sendmany, false },
2591 { "addmultisigaddress", &addmultisigaddress, false },
2592 { "getblock", &getblock, false },
2593 { "getblockhash", &getblockhash, false },
2594 { "getblockbynumber", &getblockbynumber, false },
2595 { "gettransaction", &gettransaction, false },
2596 { "listtransactions", &listtransactions, false },
2597 { "signmessage", &signmessage, false },
2598 { "verifymessage", &verifymessage, false },
2599 { "getwork", &getwork, true },
2600 { "listaccounts", &listaccounts, false },
2601 { "settxfee", &settxfee, false },
2602 { "getmemorypool", &getmemorypool, true },
2603 { "getblocktemplate", &getblocktemplate, true },
2604 { "submitblock", &submitblock, false },
2605 { "listsinceblock", &listsinceblock, false },
2606 { "dumpprivkey", &dumpprivkey, false },
2607 { "importprivkey", &importprivkey, false },
2608 { "getcheckpoint", &getcheckpoint, true },
2609 { "reservebalance", &reservebalance, false},
2610 { "checkwallet", &checkwallet, false},
2611 { "repairwallet", &repairwallet, false},
2612 { "resendtx", &resendtx, false},
2613 { "makekeypair", &makekeypair, false},
2614 { "sendalert", &sendalert, false},
2617 CRPCTable::CRPCTable()
2620 for (vcidx = 0; vcidx < (sizeof(vRPCCommands) / sizeof(vRPCCommands[0])); vcidx++)
2622 const CRPCCommand *pcmd;
2624 pcmd = &vRPCCommands[vcidx];
2625 mapCommands[pcmd->name] = pcmd;
2629 const CRPCCommand *CRPCTable::operator[](string name) const
2631 map<string, const CRPCCommand*>::const_iterator it = mapCommands.find(name);
2632 if (it == mapCommands.end())
2634 return (*it).second;
2640 // This ain't Apache. We're just using HTTP header for the length field
2641 // and to be compatible with other JSON-RPC implementations.
2644 string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
2647 s << "POST / HTTP/1.1\r\n"
2648 << "User-Agent: novacoin-json-rpc/" << FormatFullVersion() << "\r\n"
2649 << "Host: 127.0.0.1\r\n"
2650 << "Content-Type: application/json\r\n"
2651 << "Content-Length: " << strMsg.size() << "\r\n"
2652 << "Connection: close\r\n"
2653 << "Accept: application/json\r\n";
2654 BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
2655 s << item.first << ": " << item.second << "\r\n";
2656 s << "\r\n" << strMsg;
2661 string rfc1123Time()
2666 struct tm* now_gmt = gmtime(&now);
2667 string locale(setlocale(LC_TIME, NULL));
2668 setlocale(LC_TIME, "C"); // we want posix (aka "C") weekday/month strings
2669 strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt);
2670 setlocale(LC_TIME, locale.c_str());
2671 return string(buffer);
2674 static string HTTPReply(int nStatus, const string& strMsg)
2677 return strprintf("HTTP/1.0 401 Authorization Required\r\n"
2679 "Server: novacoin-json-rpc/%s\r\n"
2680 "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
2681 "Content-Type: text/html\r\n"
2682 "Content-Length: 296\r\n"
2684 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
2685 "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
2688 "<TITLE>Error</TITLE>\r\n"
2689 "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
2691 "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
2692 "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
2693 const char *cStatus;
2694 if (nStatus == 200) cStatus = "OK";
2695 else if (nStatus == 400) cStatus = "Bad Request";
2696 else if (nStatus == 403) cStatus = "Forbidden";
2697 else if (nStatus == 404) cStatus = "Not Found";
2698 else if (nStatus == 500) cStatus = "Internal Server Error";
2701 "HTTP/1.1 %d %s\r\n"
2703 "Connection: close\r\n"
2704 "Content-Length: %d\r\n"
2705 "Content-Type: application/json\r\n"
2706 "Server: novacoin-json-rpc/%s\r\n"
2711 rfc1123Time().c_str(),
2713 FormatFullVersion().c_str(),
2717 int ReadHTTPStatus(std::basic_istream<char>& stream)
2720 getline(stream, str);
2721 vector<string> vWords;
2722 boost::split(vWords, str, boost::is_any_of(" "));
2723 if (vWords.size() < 2)
2725 return atoi(vWords[1].c_str());
2728 int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
2734 std::getline(stream, str);
2735 if (str.empty() || str == "\r")
2737 string::size_type nColon = str.find(":");
2738 if (nColon != string::npos)
2740 string strHeader = str.substr(0, nColon);
2741 boost::trim(strHeader);
2742 boost::to_lower(strHeader);
2743 string strValue = str.substr(nColon+1);
2744 boost::trim(strValue);
2745 mapHeadersRet[strHeader] = strValue;
2746 if (strHeader == "content-length")
2747 nLen = atoi(strValue.c_str());
2753 int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
2755 mapHeadersRet.clear();
2759 int nStatus = ReadHTTPStatus(stream);
2762 int nLen = ReadHTTPHeader(stream, mapHeadersRet);
2763 if (nLen < 0 || nLen > (int)MAX_SIZE)
2769 vector<char> vch(nLen);
2770 stream.read(&vch[0], nLen);
2771 strMessageRet = string(vch.begin(), vch.end());
2777 bool HTTPAuthorized(map<string, string>& mapHeaders)
2779 string strAuth = mapHeaders["authorization"];
2780 if (strAuth.substr(0,6) != "Basic ")
2782 string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
2783 string strUserPass = DecodeBase64(strUserPass64);
2784 return strUserPass == strRPCUserColonPass;
2788 // JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
2789 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
2790 // unspecified (HTTP errors and contents of 'error').
2792 // 1.0 spec: http://json-rpc.org/wiki/specification
2793 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
2794 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
2797 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
2800 request.push_back(Pair("method", strMethod));
2801 request.push_back(Pair("params", params));
2802 request.push_back(Pair("id", id));
2803 return write_string(Value(request), false) + "\n";
2806 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
2809 if (error.type() != null_type)
2810 reply.push_back(Pair("result", Value::null));
2812 reply.push_back(Pair("result", result));
2813 reply.push_back(Pair("error", error));
2814 reply.push_back(Pair("id", id));
2815 return write_string(Value(reply), false) + "\n";
2818 void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
2820 // Send error reply from json-rpc error object
2822 int code = find_value(objError, "code").get_int();
2823 if (code == -32600) nStatus = 400;
2824 else if (code == -32601) nStatus = 404;
2825 string strReply = JSONRPCReply(Value::null, objError, id);
2826 stream << HTTPReply(nStatus, strReply) << std::flush;
2829 bool ClientAllowed(const string& strAddress)
2831 if (strAddress == asio::ip::address_v4::loopback().to_string())
2833 const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
2834 BOOST_FOREACH(string strAllow, vAllow)
2835 if (WildcardMatch(strAddress, strAllow))
2841 // IOStream device that speaks SSL but can also speak non-SSL
2843 class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
2845 SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
2847 fUseSSL = fUseSSLIn;
2848 fNeedHandshake = fUseSSLIn;
2851 void handshake(ssl::stream_base::handshake_type role)
2853 if (!fNeedHandshake) return;
2854 fNeedHandshake = false;
2855 stream.handshake(role);
2857 std::streamsize read(char* s, std::streamsize n)
2859 handshake(ssl::stream_base::server); // HTTPS servers read first
2860 if (fUseSSL) return stream.read_some(asio::buffer(s, n));
2861 return stream.next_layer().read_some(asio::buffer(s, n));
2863 std::streamsize write(const char* s, std::streamsize n)
2865 handshake(ssl::stream_base::client); // HTTPS clients write first
2866 if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
2867 return asio::write(stream.next_layer(), asio::buffer(s, n));
2869 bool connect(const std::string& server, const std::string& port)
2871 ip::tcp::resolver resolver(stream.get_io_service());
2872 ip::tcp::resolver::query query(server.c_str(), port.c_str());
2873 ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
2874 ip::tcp::resolver::iterator end;
2875 boost::system::error_code error = asio::error::host_not_found;
2876 while (error && endpoint_iterator != end)
2878 stream.lowest_layer().close();
2879 stream.lowest_layer().connect(*endpoint_iterator++, error);
2887 bool fNeedHandshake;
2892 void ThreadRPCServer(void* parg)
2894 IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
2897 vnThreadsRunning[THREAD_RPCSERVER]++;
2898 ThreadRPCServer2(parg);
2899 vnThreadsRunning[THREAD_RPCSERVER]--;
2901 catch (std::exception& e) {
2902 vnThreadsRunning[THREAD_RPCSERVER]--;
2903 PrintException(&e, "ThreadRPCServer()");
2905 vnThreadsRunning[THREAD_RPCSERVER]--;
2906 PrintException(NULL, "ThreadRPCServer()");
2908 printf("ThreadRPCServer exiting\n");
2911 void ThreadRPCServer2(void* parg)
2913 printf("ThreadRPCServer started\n");
2915 strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
2916 if (mapArgs["-rpcpassword"] == "")
2918 unsigned char rand_pwd[32];
2919 RAND_bytes(rand_pwd, 32);
2920 string strWhatAmI = "To use novacoind";
2921 if (mapArgs.count("-server"))
2922 strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
2923 else if (mapArgs.count("-daemon"))
2924 strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
2925 ThreadSafeMessageBox(strprintf(
2926 _("%s, you must set a rpcpassword in the configuration file:\n %s\n"
2927 "It is recommended you use the following random password:\n"
2930 "(you do not need to remember this password)\n"
2931 "If the file does not exist, create it with owner-readable-only file permissions.\n"),
2933 GetConfigFile().string().c_str(),
2934 EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str()),
2935 _("Error"), wxOK | wxMODAL);
2940 bool fUseSSL = GetBoolArg("-rpcssl");
2941 asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
2943 asio::io_service io_service;
2944 ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", RPC_PORT));
2945 ip::tcp::acceptor acceptor(io_service);
2948 acceptor.open(endpoint.protocol());
2949 acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
2950 acceptor.bind(endpoint);
2951 acceptor.listen(socket_base::max_connections);
2953 catch(boost::system::system_error &e)
2955 ThreadSafeMessageBox(strprintf(_("An error occured while setting up the RPC port %i for listening: %s"), endpoint.port(), e.what()),
2956 _("Error"), wxOK | wxMODAL);
2961 ssl::context context(io_service, ssl::context::sslv23);
2964 context.set_options(ssl::context::no_sslv2);
2966 filesystem::path pathCertFile(GetArg("-rpcsslcertificatechainfile", "server.cert"));
2967 if (!pathCertFile.is_complete()) pathCertFile = filesystem::path(GetDataDir()) / pathCertFile;
2968 if (filesystem::exists(pathCertFile)) context.use_certificate_chain_file(pathCertFile.string());
2969 else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", pathCertFile.string().c_str());
2971 filesystem::path pathPKFile(GetArg("-rpcsslprivatekeyfile", "server.pem"));
2972 if (!pathPKFile.is_complete()) pathPKFile = filesystem::path(GetDataDir()) / pathPKFile;
2973 if (filesystem::exists(pathPKFile)) context.use_private_key_file(pathPKFile.string(), ssl::context::pem);
2974 else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pathPKFile.string().c_str());
2976 string strCiphers = GetArg("-rpcsslciphers", "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
2977 SSL_CTX_set_cipher_list(context.impl(), strCiphers.c_str());
2982 // Accept connection
2983 SSLStream sslStream(io_service, context);
2984 SSLIOStreamDevice d(sslStream, fUseSSL);
2985 iostreams::stream<SSLIOStreamDevice> stream(d);
2987 ip::tcp::endpoint peer;
2988 vnThreadsRunning[THREAD_RPCSERVER]--;
2989 acceptor.accept(sslStream.lowest_layer(), peer);
2990 vnThreadsRunning[4]++;
2994 // Restrict callers by IP
2995 if (!ClientAllowed(peer.address().to_string()))
2997 // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
2999 stream << HTTPReply(403, "") << std::flush;
3003 map<string, string> mapHeaders;
3006 boost::thread api_caller(ReadHTTP, boost::ref(stream), boost::ref(mapHeaders), boost::ref(strRequest));
3007 if (!api_caller.timed_join(boost::posix_time::seconds(GetArg("-rpctimeout", 30))))
3010 printf("ThreadRPCServer ReadHTTP timeout\n");
3014 // Check authorization
3015 if (mapHeaders.count("authorization") == 0)
3017 stream << HTTPReply(401, "") << std::flush;
3020 if (!HTTPAuthorized(mapHeaders))
3022 printf("ThreadRPCServer incorrect password attempt from %s\n",peer.address().to_string().c_str());
3023 /* Deter brute-forcing short passwords.
3024 If this results in a DOS the user really
3025 shouldn't have their RPC port exposed.*/
3026 if (mapArgs["-rpcpassword"].size() < 20)
3029 stream << HTTPReply(401, "") << std::flush;
3033 Value id = Value::null;
3038 if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
3039 throw JSONRPCError(-32700, "Parse error");
3040 const Object& request = valRequest.get_obj();
3042 // Parse id now so errors from here on will have the id
3043 id = find_value(request, "id");
3046 Value valMethod = find_value(request, "method");
3047 if (valMethod.type() == null_type)
3048 throw JSONRPCError(-32600, "Missing method");
3049 if (valMethod.type() != str_type)
3050 throw JSONRPCError(-32600, "Method must be a string");
3051 string strMethod = valMethod.get_str();
3052 if (strMethod != "getwork" && strMethod != "getmemorypool")
3053 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
3056 Value valParams = find_value(request, "params");
3058 if (valParams.type() == array_type)
3059 params = valParams.get_array();
3060 else if (valParams.type() == null_type)
3063 throw JSONRPCError(-32600, "Params must be an array");
3066 const CRPCCommand *pcmd = tableRPC[strMethod];
3068 throw JSONRPCError(-32601, "Method not found");
3070 // Observe safe mode
3071 string strWarning = GetWarnings("rpc");
3072 if (strWarning != "" && !GetBoolArg("-disablesafemode") &&
3074 throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
3081 LOCK2(cs_main, pwalletMain->cs_wallet);
3082 result = pcmd->actor(params, false);
3086 string strReply = JSONRPCReply(result, Value::null, id);
3087 stream << HTTPReply(200, strReply) << std::flush;
3089 catch (std::exception& e)
3091 ErrorReply(stream, JSONRPCError(-1, e.what()), id);
3094 catch (Object& objError)
3096 ErrorReply(stream, objError, id);
3098 catch (std::exception& e)
3100 ErrorReply(stream, JSONRPCError(-32700, e.what()), id);
3108 Object CallRPC(const string& strMethod, const Array& params)
3110 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
3111 throw runtime_error(strprintf(
3112 _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
3113 "If the file does not exist, create it with owner-readable-only file permissions."),
3114 GetConfigFile().string().c_str()));
3116 // Connect to localhost
3117 bool fUseSSL = GetBoolArg("-rpcssl");
3118 asio::io_service io_service;
3119 ssl::context context(io_service, ssl::context::sslv23);
3120 context.set_options(ssl::context::no_sslv2);
3121 SSLStream sslStream(io_service, context);
3122 SSLIOStreamDevice d(sslStream, fUseSSL);
3123 iostreams::stream<SSLIOStreamDevice> stream(d);
3124 if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", CBigNum(RPC_PORT).ToString().c_str())))
3125 throw runtime_error("couldn't connect to server");
3127 // HTTP basic authentication
3128 string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
3129 map<string, string> mapRequestHeaders;
3130 mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
3133 string strRequest = JSONRPCRequest(strMethod, params, 1);
3134 string strPost = HTTPPost(strRequest, mapRequestHeaders);
3135 stream << strPost << std::flush;
3138 map<string, string> mapHeaders;
3140 int nStatus = ReadHTTP(stream, mapHeaders, strReply);
3142 throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
3143 else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
3144 throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
3145 else if (strReply.empty())
3146 throw runtime_error("no response from server");
3150 if (!read_string(strReply, valReply))
3151 throw runtime_error("couldn't parse reply from server");
3152 const Object& reply = valReply.get_obj();
3154 throw runtime_error("expected reply to have result, error and id properties");
3162 template<typename T>
3163 void ConvertTo(Value& value)
3165 if (value.type() == str_type)
3167 // reinterpret string as unquoted json value
3169 if (!read_string(value.get_str(), value2))
3170 throw runtime_error("type mismatch");
3171 value = value2.get_value<T>();
3175 value = value.get_value<T>();
3179 int CommandLineRPC(int argc, char *argv[])
3186 while (argc > 1 && IsSwitchChar(argv[1][0]))
3194 throw runtime_error("too few parameters");
3195 string strMethod = argv[1];
3197 // Parameters default to strings
3199 for (int i = 2; i < argc; i++)
3200 params.push_back(argv[i]);
3201 int n = params.size();
3204 // Special case non-string parameter types
3206 if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
3207 if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
3208 if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
3209 if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]);
3210 if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
3211 if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]);
3212 if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
3213 if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
3214 if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]);
3215 if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
3216 if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]);
3217 if (strMethod == "getblockhash" && n > 0) ConvertTo<boost::int64_t>(params[0]);
3218 if (strMethod == "getblockbynumber" && n > 0) ConvertTo<boost::int64_t>(params[0]);
3219 if (strMethod == "getblockbynumber" && n > 1) ConvertTo<bool>(params[1]);
3220 if (strMethod == "getblock" && n > 1) ConvertTo<bool>(params[1]);
3221 if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]);
3222 if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]);
3223 if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]);
3224 if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]);
3225 if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
3226 if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]);
3227 if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]);
3228 if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]);
3229 if (strMethod == "walletpassphrase" && n > 2) ConvertTo<bool>(params[2]);
3230 if (strMethod == "listsinceblock" && n > 1) ConvertTo<boost::int64_t>(params[1]);
3231 if (strMethod == "sendalert" && n > 2) ConvertTo<boost::int64_t>(params[2]);
3232 if (strMethod == "sendalert" && n > 3) ConvertTo<boost::int64_t>(params[3]);
3233 if (strMethod == "sendalert" && n > 4) ConvertTo<boost::int64_t>(params[4]);
3234 if (strMethod == "sendalert" && n > 5) ConvertTo<boost::int64_t>(params[5]);
3235 if (strMethod == "sendalert" && n > 6) ConvertTo<boost::int64_t>(params[6]);
3236 if (strMethod == "sendmany" && n > 1)
3238 string s = params[1].get_str();
3240 if (!read_string(s, v) || v.type() != obj_type)
3241 throw runtime_error("type mismatch");
3242 params[1] = v.get_obj();
3244 if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]);
3245 if (strMethod == "reservebalance" && n > 0) ConvertTo<bool>(params[0]);
3246 if (strMethod == "reservebalance" && n > 1) ConvertTo<double>(params[1]);
3247 if (strMethod == "addmultisigaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
3248 if (strMethod == "addmultisigaddress" && n > 1)
3250 string s = params[1].get_str();
3252 if (!read_string(s, v) || v.type() != array_type)
3253 throw runtime_error("type mismatch "+s);
3254 params[1] = v.get_array();
3258 Object reply = CallRPC(strMethod, params);
3261 const Value& result = find_value(reply, "result");
3262 const Value& error = find_value(reply, "error");
3264 if (error.type() != null_type)
3267 strPrint = "error: " + write_string(error, false);
3268 int code = find_value(error.get_obj(), "code").get_int();
3274 if (result.type() == null_type)
3276 else if (result.type() == str_type)
3277 strPrint = result.get_str();
3279 strPrint = write_string(result, true);
3282 catch (std::exception& e)
3284 strPrint = string("error: ") + e.what();
3289 PrintException(NULL, "CommandLineRPC()");
3294 fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
3303 int main(int argc, char *argv[])
3306 // Turn off microsoft heap dump noise
3307 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
3308 _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
3310 setbuf(stdin, NULL);
3311 setbuf(stdout, NULL);
3312 setbuf(stderr, NULL);
3316 if (argc >= 2 && string(argv[1]) == "-server")
3318 printf("server ready\n");
3319 ThreadRPCServer(NULL);
3323 return CommandLineRPC(argc, argv);
3326 catch (std::exception& e) {
3327 PrintException(&e, "main()");
3329 PrintException(NULL, "main()");
3335 const CRPCTable tableRPC;