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