1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2012 The Bitcoin developers
3 // Copyright (c) 2011-2013 The PPCoin developers
4 // Copyright (c) 2013 NovaCoin Developers
5 // Distributed under the MIT/X11 software license, see the accompanying
6 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
14 #include "checkpoints.h"
15 #include "ui_interface.h"
16 #include "bitcoinrpc.h"
19 #include <boost/asio.hpp>
20 #include <boost/filesystem.hpp>
21 #include <boost/iostreams/concepts.hpp>
22 #include <boost/iostreams/stream.hpp>
23 #include <boost/algorithm/string.hpp>
24 #include <boost/lexical_cast.hpp>
25 #include <boost/asio/ssl.hpp>
26 #include <boost/filesystem/fstream.hpp>
27 typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> SSLStream;
29 #define printf OutputDebugStringF
30 // MinGW 3.4.5 gets "fatal error: had to relocate PCH" if the json headers are
31 // precompiled in headers.h. The problem might be when the pch file goes over
32 // a certain size around 145MB. If we need access to json_spirit outside this
33 // file, we could use the compiled json_spirit option.
36 using namespace boost;
37 using namespace boost::asio;
38 using namespace json_spirit;
40 void ThreadRPCServer2(void* parg);
42 static std::string strRPCUserColonPass;
44 static int64 nWalletUnlockTime;
45 static CCriticalSection cs_nWalletUnlockTime;
47 extern Value dumpprivkey(const Array& params, bool fHelp);
48 extern Value importprivkey(const Array& params, bool fHelp);
50 Object JSONRPCError(int code, const string& message)
53 error.push_back(Pair("code", code));
54 error.push_back(Pair("message", message));
58 double GetDifficulty(const CBlockIndex* blockindex = NULL)
60 // Floating point number that is a multiple of the minimum difficulty,
61 // minimum difficulty = 1.0.
62 if (blockindex == NULL)
64 if (pindexBest == NULL)
67 blockindex = GetLastBlockIndex(pindexBest, false);
70 int nShift = (blockindex->nBits >> 24) & 0xff;
73 (double)0x0000ffff / (double)(blockindex->nBits & 0x00ffffff);
90 int64 AmountFromValue(const Value& value)
92 double dAmount = value.get_real();
93 if (dAmount <= 0.0 || dAmount > MAX_MONEY)
94 throw JSONRPCError(-3, "Invalid amount");
95 int64 nAmount = roundint64(dAmount * COIN);
96 if (!MoneyRange(nAmount))
97 throw JSONRPCError(-3, "Invalid amount");
101 Value ValueFromAmount(int64 amount)
103 return (double)amount / (double)COIN;
107 HexBits(unsigned int nBits)
113 uBits.nBits = htonl((int32_t)nBits);
114 return HexStr(BEGIN(uBits.cBits), END(uBits.cBits));
117 unsigned int BitsHex(std::string HexBits)
124 vector<unsigned char> vchBits = ParseHex(HexBits);
125 copy(vchBits.begin(), vchBits.begin() + 4, uBits.cBits);
126 uBits.nBits = htonl((int32_t)uBits.nBits);
130 void TxToJSON(const CTransaction &tx, Object& entry)
132 entry.push_back(Pair("version", tx.nVersion));
133 entry.push_back(Pair("locktime", (boost::int64_t)tx.nLockTime));
134 entry.push_back(Pair("size", (boost::int64_t)::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION)));
136 BOOST_FOREACH(const CTxIn& txin, tx.vin)
140 in.push_back(Pair("coinbase", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
144 prevout.push_back(Pair("hash", txin.prevout.hash.GetHex()));
145 prevout.push_back(Pair("n", (boost::int64_t)txin.prevout.n));
146 in.push_back(Pair("prevout", prevout));
147 in.push_back(Pair("scriptSig", txin.scriptSig.ToString()));
149 in.push_back(Pair("sequence", (boost::int64_t)txin.nSequence));
152 entry.push_back(Pair("vin", vin));
154 BOOST_FOREACH(const CTxOut& txout, tx.vout)
157 out.push_back(Pair("value", ValueFromAmount(txout.nValue)));
158 out.push_back(Pair("scriptPubKey", txout.scriptPubKey.ToString()));
161 entry.push_back(Pair("vout", vout));
164 void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
166 int confirms = wtx.GetDepthInMainChain();
167 entry.push_back(Pair("confirmations", confirms));
170 entry.push_back(Pair("blockhash", wtx.hashBlock.GetHex()));
171 entry.push_back(Pair("blockindex", wtx.nIndex));
173 entry.push_back(Pair("txid", wtx.GetHash().GetHex()));
174 entry.push_back(Pair("time", (boost::int64_t)wtx.GetTxTime()));
175 BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
176 entry.push_back(Pair(item.first, item.second));
179 string AccountFromValue(const Value& value)
181 string strAccount = value.get_str();
182 if (strAccount == "*")
183 throw JSONRPCError(-11, "Invalid account name");
187 Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool fPrintTransactionDetail)
190 result.push_back(Pair("hash", block.GetHash().GetHex()));
191 result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION)));
192 result.push_back(Pair("height", blockindex->nHeight));
193 result.push_back(Pair("version", block.nVersion));
194 result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex()));
195 result.push_back(Pair("time", DateTimeStrFormat(block.GetBlockTime())));
196 result.push_back(Pair("nonce", (boost::uint64_t)block.nNonce));
197 result.push_back(Pair("bits", HexBits(block.nBits)));
198 result.push_back(Pair("difficulty", GetDifficulty(blockindex)));
199 result.push_back(Pair("mint", ValueFromAmount(blockindex->nMint)));
200 if (blockindex->pprev)
201 result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex()));
202 if (blockindex->pnext)
203 result.push_back(Pair("nextblockhash", blockindex->pnext->GetBlockHash().GetHex()));
204 result.push_back(Pair("flags", strprintf("%s%s", blockindex->IsProofOfStake()? "proof-of-stake" : "proof-of-work", blockindex->GeneratedStakeModifier()? " stake-modifier": "")));
205 result.push_back(Pair("proofhash", blockindex->IsProofOfStake()? blockindex->hashProofOfStake.GetHex() : blockindex->GetBlockHash().GetHex()));
206 result.push_back(Pair("entropybit", (int)blockindex->GetStakeEntropyBit()));
207 result.push_back(Pair("modifier", strprintf("%016"PRI64x, blockindex->nStakeModifier)));
208 result.push_back(Pair("modifierchecksum", strprintf("%08x", blockindex->nStakeModifierChecksum)));
210 BOOST_FOREACH (const CTransaction& tx, block.vtx)
212 if (fPrintTransactionDetail)
214 txinfo.push_back(tx.ToStringShort());
215 txinfo.push_back(DateTimeStrFormat(tx.nTime));
216 BOOST_FOREACH(const CTxIn& txin, tx.vin)
217 txinfo.push_back(txin.ToStringShort());
218 BOOST_FOREACH(const CTxOut& txout, tx.vout)
219 txinfo.push_back(txout.ToStringShort());
222 txinfo.push_back(tx.GetHash().GetHex());
224 result.push_back(Pair("tx", txinfo));
231 /// Note: This interface may still be subject to change.
234 string CRPCTable::help(string strCommand) const
237 set<rpcfn_type> setDone;
238 for (map<string, const CRPCCommand*>::const_iterator mi = mapCommands.begin(); mi != mapCommands.end(); ++mi)
240 const CRPCCommand *pcmd = mi->second;
241 string strMethod = mi->first;
242 // We already filter duplicates, but these deprecated screw up the sort order
243 if (strMethod == "getamountreceived" ||
244 strMethod == "getallreceived" ||
245 strMethod == "getblocknumber" || // deprecated
246 (strMethod.find("label") != string::npos))
248 if (strCommand != "" && strMethod != strCommand)
253 rpcfn_type pfn = pcmd->actor;
254 if (setDone.insert(pfn).second)
255 (*pfn)(params, true);
257 catch (std::exception& e)
259 // Help text is returned in an exception
260 string strHelp = string(e.what());
261 if (strCommand == "")
262 if (strHelp.find('\n') != string::npos)
263 strHelp = strHelp.substr(0, strHelp.find('\n'));
264 strRet += strHelp + "\n";
268 strRet = strprintf("help: unknown command: %s\n", strCommand.c_str());
269 strRet = strRet.substr(0,strRet.size()-1);
273 Value help(const Array& params, bool fHelp)
275 if (fHelp || params.size() > 1)
278 "List commands, or get help for a command.");
281 if (params.size() > 0)
282 strCommand = params[0].get_str();
284 return tableRPC.help(strCommand);
288 Value stop(const Array& params, bool fHelp)
290 if (fHelp || params.size() != 0)
293 "Stop novacoin server.");
294 // Shutdown will take long enough that the response should get back
296 return "novacoin server stopping";
300 Value getblockcount(const Array& params, bool fHelp)
302 if (fHelp || params.size() != 0)
305 "Returns the number of blocks in the longest block chain.");
312 Value getblocknumber(const Array& params, bool fHelp)
314 if (fHelp || params.size() != 0)
317 "Deprecated. Use getblockcount.");
323 Value getconnectioncount(const Array& params, bool fHelp)
325 if (fHelp || params.size() != 0)
327 "getconnectioncount\n"
328 "Returns the number of connections to other nodes.");
330 return (int)vNodes.size();
334 Value getdifficulty(const Array& params, bool fHelp)
336 if (fHelp || params.size() != 0)
339 "Returns difficulty as a multiple of the minimum difficulty.");
342 obj.push_back(Pair("proof-of-work", GetDifficulty()));
343 obj.push_back(Pair("proof-of-stake", GetDifficulty(GetLastBlockIndex(pindexBest, true))));
344 obj.push_back(Pair("search-interval", (int)nLastCoinStakeSearchInterval));
349 Value getgenerate(const Array& params, bool fHelp)
351 if (fHelp || params.size() != 0)
354 "Returns true or false.");
356 return GetBoolArg("-gen");
360 Value setgenerate(const Array& params, bool fHelp)
362 if (fHelp || params.size() < 1 || params.size() > 2)
364 "setgenerate <generate> [genproclimit]\n"
365 "<generate> is true or false to turn generation on or off.\n"
366 "Generation is limited to [genproclimit] processors, -1 is unlimited.");
368 bool fGenerate = true;
369 if (params.size() > 0)
370 fGenerate = params[0].get_bool();
372 if (params.size() > 1)
374 int nGenProcLimit = params[1].get_int();
375 mapArgs["-genproclimit"] = itostr(nGenProcLimit);
376 if (nGenProcLimit == 0)
379 mapArgs["-gen"] = (fGenerate ? "1" : "0");
381 GenerateBitcoins(fGenerate, pwalletMain);
386 Value gethashespersec(const Array& params, bool fHelp)
388 if (fHelp || params.size() != 0)
391 "Returns a recent hashes per second performance measurement while generating.");
393 if (GetTimeMillis() - nHPSTimerStart > 8000)
394 return (boost::int64_t)0;
395 return (boost::int64_t)dHashesPerSec;
399 Value getinfo(const Array& params, bool fHelp)
401 if (fHelp || params.size() != 0)
404 "Returns an object containing various state info.");
407 obj.push_back(Pair("version", FormatFullVersion()));
408 obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION));
409 obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
410 obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
411 obj.push_back(Pair("newmint", ValueFromAmount(pwalletMain->GetNewMint())));
412 obj.push_back(Pair("stake", ValueFromAmount(pwalletMain->GetStake())));
413 obj.push_back(Pair("blocks", (int)nBestHeight));
414 obj.push_back(Pair("moneysupply", ValueFromAmount(pindexBest->nMoneySupply)));
415 obj.push_back(Pair("connections", (int)vNodes.size()));
416 obj.push_back(Pair("proxy", (fUseProxy ? addrProxy.ToStringIPPort() : string())));
417 obj.push_back(Pair("ip", addrSeenByPeer.ToStringIP()));
418 obj.push_back(Pair("difficulty", (double)GetDifficulty()));
419 obj.push_back(Pair("testnet", fTestNet));
420 obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));
421 obj.push_back(Pair("keypoolsize", pwalletMain->GetKeyPoolSize()));
422 obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee)));
423 if (pwalletMain->IsCrypted())
424 obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime / 1000));
425 obj.push_back(Pair("errors", GetWarnings("statusbar")));
430 Value getmininginfo(const Array& params, bool fHelp)
432 if (fHelp || params.size() != 0)
435 "Returns an object containing mining-related information.");
438 obj.push_back(Pair("blocks", (int)nBestHeight));
439 obj.push_back(Pair("currentblocksize",(uint64_t)nLastBlockSize));
440 obj.push_back(Pair("currentblocktx",(uint64_t)nLastBlockTx));
441 obj.push_back(Pair("difficulty", (double)GetDifficulty()));
442 obj.push_back(Pair("errors", GetWarnings("statusbar")));
443 obj.push_back(Pair("generate", GetBoolArg("-gen")));
444 obj.push_back(Pair("genproclimit", (int)GetArg("-genproclimit", -1)));
445 obj.push_back(Pair("hashespersec", gethashespersec(params, false)));
446 obj.push_back(Pair("pooledtx", (uint64_t)mempool.size()));
447 obj.push_back(Pair("testnet", fTestNet));
452 Value getnewaddress(const Array& params, bool fHelp)
454 if (fHelp || params.size() > 1)
456 "getnewaddress [account]\n"
457 "Returns a new novacoin address for receiving payments. "
458 "If [account] is specified (recommended), it is added to the address book "
459 "so payments received with the address will be credited to [account].");
461 // Parse the account first so we don't generate a key if there's an error
463 if (params.size() > 0)
464 strAccount = AccountFromValue(params[0]);
466 if (!pwalletMain->IsLocked())
467 pwalletMain->TopUpKeyPool();
469 // Generate a new key that is added to wallet
470 std::vector<unsigned char> newKey;
471 if (!pwalletMain->GetKeyFromPool(newKey, false))
472 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
473 CBitcoinAddress address(newKey);
475 pwalletMain->SetAddressBookName(address, strAccount);
477 return address.ToString();
481 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
483 CWalletDB walletdb(pwalletMain->strWalletFile);
486 walletdb.ReadAccount(strAccount, account);
488 bool bKeyUsed = false;
490 // Check if the current key has been used
491 if (!account.vchPubKey.empty())
493 CScript scriptPubKey;
494 scriptPubKey.SetBitcoinAddress(account.vchPubKey);
495 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
496 it != pwalletMain->mapWallet.end() && !account.vchPubKey.empty();
499 const CWalletTx& wtx = (*it).second;
500 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
501 if (txout.scriptPubKey == scriptPubKey)
506 // Generate a new key
507 if (account.vchPubKey.empty() || bForceNew || bKeyUsed)
509 if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false))
510 throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
512 pwalletMain->SetAddressBookName(CBitcoinAddress(account.vchPubKey), strAccount);
513 walletdb.WriteAccount(strAccount, account);
516 return CBitcoinAddress(account.vchPubKey);
519 Value getaccountaddress(const Array& params, bool fHelp)
521 if (fHelp || params.size() != 1)
523 "getaccountaddress <account>\n"
524 "Returns the current novacoin address for receiving payments to this account.");
526 // Parse the account first so we don't generate a key if there's an error
527 string strAccount = AccountFromValue(params[0]);
531 ret = GetAccountAddress(strAccount).ToString();
538 Value setaccount(const Array& params, bool fHelp)
540 if (fHelp || params.size() < 1 || params.size() > 2)
542 "setaccount <novacoinaddress> <account>\n"
543 "Sets the account associated with the given address.");
545 CBitcoinAddress address(params[0].get_str());
546 if (!address.IsValid())
547 throw JSONRPCError(-5, "Invalid novacoin address");
551 if (params.size() > 1)
552 strAccount = AccountFromValue(params[1]);
554 // Detect when changing the account of an address that is the 'unused current key' of another account:
555 if (pwalletMain->mapAddressBook.count(address))
557 string strOldAccount = pwalletMain->mapAddressBook[address];
558 if (address == GetAccountAddress(strOldAccount))
559 GetAccountAddress(strOldAccount, true);
562 pwalletMain->SetAddressBookName(address, strAccount);
568 Value getaccount(const Array& params, bool fHelp)
570 if (fHelp || params.size() != 1)
572 "getaccount <novacoinaddress>\n"
573 "Returns the account associated with the given address.");
575 CBitcoinAddress address(params[0].get_str());
576 if (!address.IsValid())
577 throw JSONRPCError(-5, "Invalid novacoin address");
580 map<CBitcoinAddress, string>::iterator mi = pwalletMain->mapAddressBook.find(address);
581 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
582 strAccount = (*mi).second;
587 Value getaddressesbyaccount(const Array& params, bool fHelp)
589 if (fHelp || params.size() != 1)
591 "getaddressesbyaccount <account>\n"
592 "Returns the list of addresses for the given account.");
594 string strAccount = AccountFromValue(params[0]);
596 // Find all addresses that have the given account
598 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
600 const CBitcoinAddress& address = item.first;
601 const string& strName = item.second;
602 if (strName == strAccount)
603 ret.push_back(address.ToString());
608 Value settxfee(const Array& params, bool fHelp)
610 if (fHelp || params.size() < 1 || params.size() > 1 || AmountFromValue(params[0]) < MIN_TX_FEE)
612 "settxfee <amount>\n"
613 "<amount> is a real and is rounded to 0.01 (cent)\n"
614 "Minimum and default transaction fee per KB is 1 cent");
616 nTransactionFee = AmountFromValue(params[0]);
617 nTransactionFee = (nTransactionFee / CENT) * CENT; // round to cent
621 Value sendtoaddress(const Array& params, bool fHelp)
623 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
625 "sendtoaddress <novacoinaddress> <amount> [comment] [comment-to]\n"
626 "<amount> is a real and is rounded to the nearest 0.000001\n"
627 "requires wallet passphrase to be set with walletpassphrase first");
628 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
630 "sendtoaddress <novacoinaddress> <amount> [comment] [comment-to]\n"
631 "<amount> is a real and is rounded to the nearest 0.000001");
633 CBitcoinAddress address(params[0].get_str());
634 if (!address.IsValid())
635 throw JSONRPCError(-5, "Invalid novacoin address");
638 int64 nAmount = AmountFromValue(params[1]);
639 if (nAmount < MIN_TXOUT_AMOUNT)
640 throw JSONRPCError(-101, "Send amount too small");
644 if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
645 wtx.mapValue["comment"] = params[2].get_str();
646 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
647 wtx.mapValue["to"] = params[3].get_str();
649 if (pwalletMain->IsLocked())
650 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
652 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
654 throw JSONRPCError(-4, strError);
656 return wtx.GetHash().GetHex();
659 Value signmessage(const Array& params, bool fHelp)
661 if (fHelp || params.size() != 2)
663 "signmessage <novacoinaddress> <message>\n"
664 "Sign a message with the private key of an address");
666 if (pwalletMain->IsLocked())
667 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
669 string strAddress = params[0].get_str();
670 string strMessage = params[1].get_str();
672 CBitcoinAddress addr(strAddress);
674 throw JSONRPCError(-3, "Invalid address");
677 if (!pwalletMain->GetKey(addr, key))
678 throw JSONRPCError(-4, "Private key not available");
680 CDataStream ss(SER_GETHASH, 0);
681 ss << strMessageMagic;
684 vector<unsigned char> vchSig;
685 if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig))
686 throw JSONRPCError(-5, "Sign failed");
688 return EncodeBase64(&vchSig[0], vchSig.size());
691 Value verifymessage(const Array& params, bool fHelp)
693 if (fHelp || params.size() != 3)
695 "verifymessage <novacoinaddress> <signature> <message>\n"
696 "Verify a signed message");
698 string strAddress = params[0].get_str();
699 string strSign = params[1].get_str();
700 string strMessage = params[2].get_str();
702 CBitcoinAddress addr(strAddress);
704 throw JSONRPCError(-3, "Invalid address");
706 bool fInvalid = false;
707 vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
710 throw JSONRPCError(-5, "Malformed base64 encoding");
712 CDataStream ss(SER_GETHASH, 0);
713 ss << strMessageMagic;
717 if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
720 return (CBitcoinAddress(key.GetPubKey()) == addr);
724 Value getreceivedbyaddress(const Array& params, bool fHelp)
726 if (fHelp || params.size() < 1 || params.size() > 2)
728 "getreceivedbyaddress <novacoinaddress> [minconf=1]\n"
729 "Returns the total amount received by <novacoinaddress> in transactions with at least [minconf] confirmations.");
732 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
733 CScript scriptPubKey;
734 if (!address.IsValid())
735 throw JSONRPCError(-5, "Invalid novacoin address");
736 scriptPubKey.SetBitcoinAddress(address);
737 if (!IsMine(*pwalletMain,scriptPubKey))
740 // Minimum confirmations
742 if (params.size() > 1)
743 nMinDepth = params[1].get_int();
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)
754 if (txout.scriptPubKey == scriptPubKey)
755 if (wtx.GetDepthInMainChain() >= nMinDepth)
756 nAmount += txout.nValue;
759 return ValueFromAmount(nAmount);
763 void GetAccountAddresses(string strAccount, set<CBitcoinAddress>& setAddress)
765 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
767 const CBitcoinAddress& address = item.first;
768 const string& strName = item.second;
769 if (strName == strAccount)
770 setAddress.insert(address);
775 Value getreceivedbyaccount(const Array& params, bool fHelp)
777 if (fHelp || params.size() < 1 || params.size() > 2)
779 "getreceivedbyaccount <account> [minconf=1]\n"
780 "Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.");
782 // Minimum confirmations
784 if (params.size() > 1)
785 nMinDepth = params[1].get_int();
787 // Get the set of pub keys assigned to account
788 string strAccount = AccountFromValue(params[0]);
789 set<CBitcoinAddress> setAddress;
790 GetAccountAddresses(strAccount, setAddress);
794 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
796 const CWalletTx& wtx = (*it).second;
797 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
800 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
802 CBitcoinAddress address;
803 if (ExtractAddress(txout.scriptPubKey, address) && pwalletMain->HaveKey(address) && setAddress.count(address))
804 if (wtx.GetDepthInMainChain() >= nMinDepth)
805 nAmount += txout.nValue;
809 return (double)nAmount / (double)COIN;
813 int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth)
817 // Tally wallet transactions
818 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
820 const CWalletTx& wtx = (*it).second;
824 int64 nGenerated, nReceived, nSent, nFee;
825 wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee);
827 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
828 nBalance += nReceived;
829 nBalance += nGenerated - nSent - nFee;
832 // Tally internal accounting entries
833 nBalance += walletdb.GetAccountCreditDebit(strAccount);
838 int64 GetAccountBalance(const string& strAccount, int nMinDepth)
840 CWalletDB walletdb(pwalletMain->strWalletFile);
841 return GetAccountBalance(walletdb, strAccount, nMinDepth);
845 Value getbalance(const Array& params, bool fHelp)
847 if (fHelp || params.size() > 2)
849 "getbalance [account] [minconf=1]\n"
850 "If [account] is not specified, returns the server's total available balance.\n"
851 "If [account] is specified, returns the balance in the account.");
853 if (params.size() == 0)
854 return ValueFromAmount(pwalletMain->GetBalance());
857 if (params.size() > 1)
858 nMinDepth = params[1].get_int();
860 if (params[0].get_str() == "*") {
861 // Calculate total balance a different way from GetBalance()
862 // (GetBalance() sums up all unspent TxOuts)
863 // getbalance and getbalance '*' should always return the same number.
865 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
867 const CWalletTx& wtx = (*it).second;
871 int64 allGeneratedImmature, allGeneratedMature, allFee;
872 allGeneratedImmature = allGeneratedMature = allFee = 0;
873 string strSentAccount;
874 list<pair<CBitcoinAddress, int64> > listReceived;
875 list<pair<CBitcoinAddress, int64> > listSent;
876 wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
877 if (wtx.GetDepthInMainChain() >= nMinDepth)
879 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listReceived)
880 nBalance += r.second;
882 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listSent)
883 nBalance -= r.second;
885 nBalance += allGeneratedMature;
887 return ValueFromAmount(nBalance);
890 string strAccount = AccountFromValue(params[0]);
892 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
894 return ValueFromAmount(nBalance);
898 Value getpowreward(const Array& params, bool fHelp)
900 if (fHelp || params.size() > 1)
902 "getpowreward [nBits]\n"
903 "Returns PoW reward for block with provided difficulty.");
905 if (params.size() == 0)
906 throw JSONRPCError(-200, "no bits provided");
908 std::string sBits = params[0].get_str();
910 if (sBits.length() != 8)
911 throw JSONRPCError(-201, "incorrect bits provided");
913 unsigned int nBits = BitsHex(sBits);
915 return (int)GetProofOfWorkReward(nBits);
920 Value movecmd(const Array& params, bool fHelp)
922 if (fHelp || params.size() < 3 || params.size() > 5)
924 "move <fromaccount> <toaccount> <amount> [minconf=1] [comment]\n"
925 "Move from one account in your wallet to another.");
927 string strFrom = AccountFromValue(params[0]);
928 string strTo = AccountFromValue(params[1]);
929 int64 nAmount = AmountFromValue(params[2]);
930 if (params.size() > 3)
931 // unused parameter, used to be nMinDepth, keep type-checking it though
932 (void)params[3].get_int();
934 if (params.size() > 4)
935 strComment = params[4].get_str();
937 CWalletDB walletdb(pwalletMain->strWalletFile);
938 if (!walletdb.TxnBegin())
939 throw JSONRPCError(-20, "database error");
941 int64 nNow = GetAdjustedTime();
944 CAccountingEntry debit;
945 debit.strAccount = strFrom;
946 debit.nCreditDebit = -nAmount;
948 debit.strOtherAccount = strTo;
949 debit.strComment = strComment;
950 walletdb.WriteAccountingEntry(debit);
953 CAccountingEntry credit;
954 credit.strAccount = strTo;
955 credit.nCreditDebit = nAmount;
957 credit.strOtherAccount = strFrom;
958 credit.strComment = strComment;
959 walletdb.WriteAccountingEntry(credit);
961 if (!walletdb.TxnCommit())
962 throw JSONRPCError(-20, "database error");
968 Value sendfrom(const Array& params, bool fHelp)
970 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
972 "sendfrom <fromaccount> <tonovacoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
973 "<amount> is a real and is rounded to the nearest 0.000001\n"
974 "requires wallet passphrase to be set with walletpassphrase first");
975 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
977 "sendfrom <fromaccount> <tonovacoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
978 "<amount> is a real and is rounded to the nearest 0.000001");
980 string strAccount = AccountFromValue(params[0]);
981 CBitcoinAddress address(params[1].get_str());
982 if (!address.IsValid())
983 throw JSONRPCError(-5, "Invalid novacoin address");
984 int64 nAmount = AmountFromValue(params[2]);
985 if (nAmount < MIN_TXOUT_AMOUNT)
986 throw JSONRPCError(-101, "Send amount too small");
988 if (params.size() > 3)
989 nMinDepth = params[3].get_int();
992 wtx.strFromAccount = strAccount;
993 if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
994 wtx.mapValue["comment"] = params[4].get_str();
995 if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
996 wtx.mapValue["to"] = params[5].get_str();
998 if (pwalletMain->IsLocked())
999 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
1002 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
1003 if (nAmount > nBalance)
1004 throw JSONRPCError(-6, "Account has insufficient funds");
1007 string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
1009 throw JSONRPCError(-4, strError);
1011 return wtx.GetHash().GetHex();
1015 Value sendmany(const Array& params, bool fHelp)
1017 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
1018 throw runtime_error(
1019 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
1020 "amounts are double-precision floating point numbers\n"
1021 "requires wallet passphrase to be set with walletpassphrase first");
1022 if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
1023 throw runtime_error(
1024 "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
1025 "amounts are double-precision floating point numbers");
1027 string strAccount = AccountFromValue(params[0]);
1028 Object sendTo = params[1].get_obj();
1030 if (params.size() > 2)
1031 nMinDepth = params[2].get_int();
1034 wtx.strFromAccount = strAccount;
1035 if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
1036 wtx.mapValue["comment"] = params[3].get_str();
1038 set<CBitcoinAddress> setAddress;
1039 vector<pair<CScript, int64> > vecSend;
1041 int64 totalAmount = 0;
1042 BOOST_FOREACH(const Pair& s, sendTo)
1044 CBitcoinAddress address(s.name_);
1045 if (!address.IsValid())
1046 throw JSONRPCError(-5, string("Invalid novacoin address:")+s.name_);
1048 if (setAddress.count(address))
1049 throw JSONRPCError(-8, string("Invalid parameter, duplicated address: ")+s.name_);
1050 setAddress.insert(address);
1052 CScript scriptPubKey;
1053 scriptPubKey.SetBitcoinAddress(address);
1054 int64 nAmount = AmountFromValue(s.value_);
1055 if (nAmount < MIN_TXOUT_AMOUNT)
1056 throw JSONRPCError(-101, "Send amount too small");
1057 totalAmount += nAmount;
1059 vecSend.push_back(make_pair(scriptPubKey, nAmount));
1062 if (pwalletMain->IsLocked())
1063 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
1064 if (fWalletUnlockMintOnly)
1065 throw JSONRPCError(-13, "Error: Wallet unlocked for block minting only.");
1068 int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
1069 if (totalAmount > nBalance)
1070 throw JSONRPCError(-6, "Account has insufficient funds");
1073 CReserveKey keyChange(pwalletMain);
1074 int64 nFeeRequired = 0;
1075 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
1078 if (totalAmount + nFeeRequired > pwalletMain->GetBalance())
1079 throw JSONRPCError(-6, "Insufficient funds");
1080 throw JSONRPCError(-4, "Transaction creation failed");
1082 if (!pwalletMain->CommitTransaction(wtx, keyChange))
1083 throw JSONRPCError(-4, "Transaction commit failed");
1085 return wtx.GetHash().GetHex();
1088 Value addmultisigaddress(const Array& params, bool fHelp)
1090 if (fHelp || params.size() < 2 || params.size() > 3)
1092 string msg = "addmultisigaddress <nrequired> <'[\"key\",\"key\"]'> [account]\n"
1093 "Add a nrequired-to-sign multisignature address to the wallet\"\n"
1094 "each key is a bitcoin address or hex-encoded public key\n"
1095 "If [account] is specified, assign address to [account].";
1096 throw runtime_error(msg);
1099 int nRequired = params[0].get_int();
1100 const Array& keys = params[1].get_array();
1102 if (params.size() > 2)
1103 strAccount = AccountFromValue(params[2]);
1105 // Gather public keys
1107 throw runtime_error("a multisignature address must require at least one key to redeem");
1108 if ((int)keys.size() < nRequired)
1109 throw runtime_error(
1110 strprintf("not enough keys supplied "
1111 "(got %d keys, but need at least %d to redeem)", keys.size(), nRequired));
1112 std::vector<CKey> pubkeys;
1113 pubkeys.resize(keys.size());
1114 for (unsigned int i = 0; i < keys.size(); i++)
1116 const std::string& ks = keys[i].get_str();
1118 // Case 1: bitcoin address and we have full public key:
1119 CBitcoinAddress address(ks);
1120 if (address.IsValid())
1122 if (address.IsScript())
1123 throw runtime_error(
1124 strprintf("%s is a pay-to-script address",ks.c_str()));
1125 std::vector<unsigned char> vchPubKey;
1126 if (!pwalletMain->GetPubKey(address, vchPubKey))
1127 throw runtime_error(
1128 strprintf("no full public key for address %s",ks.c_str()));
1129 if (vchPubKey.empty() || !pubkeys[i].SetPubKey(vchPubKey))
1130 throw runtime_error(" Invalid public key: "+ks);
1133 // Case 2: hex public key
1136 vector<unsigned char> vchPubKey = ParseHex(ks);
1137 if (vchPubKey.empty() || !pubkeys[i].SetPubKey(vchPubKey))
1138 throw runtime_error(" Invalid public key: "+ks);
1142 throw runtime_error(" Invalid public key: "+ks);
1146 // Construct using pay-to-script-hash:
1148 inner.SetMultisig(nRequired, pubkeys);
1150 uint160 scriptHash = Hash160(inner);
1151 CScript scriptPubKey;
1152 scriptPubKey.SetPayToScriptHash(inner);
1153 pwalletMain->AddCScript(inner);
1154 CBitcoinAddress address;
1155 address.SetScriptHash160(scriptHash);
1157 pwalletMain->SetAddressBookName(address, strAccount);
1158 return address.ToString();
1169 nConf = std::numeric_limits<int>::max();
1173 Value ListReceived(const Array& params, bool fByAccounts)
1175 // Minimum confirmations
1177 if (params.size() > 0)
1178 nMinDepth = params[0].get_int();
1180 // Whether to include empty accounts
1181 bool fIncludeEmpty = false;
1182 if (params.size() > 1)
1183 fIncludeEmpty = params[1].get_bool();
1186 map<CBitcoinAddress, tallyitem> mapTally;
1187 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1189 const CWalletTx& wtx = (*it).second;
1191 if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
1194 int nDepth = wtx.GetDepthInMainChain();
1195 if (nDepth < nMinDepth)
1198 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
1200 CBitcoinAddress address;
1201 if (!ExtractAddress(txout.scriptPubKey, address) || !pwalletMain->HaveKey(address) || !address.IsValid())
1204 tallyitem& item = mapTally[address];
1205 item.nAmount += txout.nValue;
1206 item.nConf = min(item.nConf, nDepth);
1212 map<string, tallyitem> mapAccountTally;
1213 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
1215 const CBitcoinAddress& address = item.first;
1216 const string& strAccount = item.second;
1217 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
1218 if (it == mapTally.end() && !fIncludeEmpty)
1222 int nConf = std::numeric_limits<int>::max();
1223 if (it != mapTally.end())
1225 nAmount = (*it).second.nAmount;
1226 nConf = (*it).second.nConf;
1231 tallyitem& item = mapAccountTally[strAccount];
1232 item.nAmount += nAmount;
1233 item.nConf = min(item.nConf, nConf);
1238 obj.push_back(Pair("address", address.ToString()));
1239 obj.push_back(Pair("account", strAccount));
1240 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1241 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1248 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
1250 int64 nAmount = (*it).second.nAmount;
1251 int nConf = (*it).second.nConf;
1253 obj.push_back(Pair("account", (*it).first));
1254 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1255 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1263 Value listreceivedbyaddress(const Array& params, bool fHelp)
1265 if (fHelp || params.size() > 2)
1266 throw runtime_error(
1267 "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
1268 "[minconf] is the minimum number of confirmations before payments are included.\n"
1269 "[includeempty] whether to include addresses that haven't received any payments.\n"
1270 "Returns an array of objects containing:\n"
1271 " \"address\" : receiving address\n"
1272 " \"account\" : the account of the receiving address\n"
1273 " \"amount\" : total amount received by the address\n"
1274 " \"confirmations\" : number of confirmations of the most recent transaction included");
1276 return ListReceived(params, false);
1279 Value listreceivedbyaccount(const Array& params, bool fHelp)
1281 if (fHelp || params.size() > 2)
1282 throw runtime_error(
1283 "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
1284 "[minconf] is the minimum number of confirmations before payments are included.\n"
1285 "[includeempty] whether to include accounts that haven't received any payments.\n"
1286 "Returns an array of objects containing:\n"
1287 " \"account\" : the account of the receiving addresses\n"
1288 " \"amount\" : total amount received by addresses with this account\n"
1289 " \"confirmations\" : number of confirmations of the most recent transaction included");
1291 return ListReceived(params, true);
1294 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret)
1296 int64 nGeneratedImmature, nGeneratedMature, nFee;
1297 string strSentAccount;
1298 list<pair<CBitcoinAddress, int64> > listReceived;
1299 list<pair<CBitcoinAddress, int64> > listSent;
1301 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1303 bool fAllAccounts = (strAccount == string("*"));
1305 // Generated blocks assigned to account ""
1306 if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == ""))
1309 entry.push_back(Pair("account", string("")));
1310 if (nGeneratedImmature)
1312 entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
1313 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
1317 entry.push_back(Pair("category", "generate"));
1318 entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
1321 WalletTxToJSON(wtx, entry);
1322 ret.push_back(entry);
1326 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1328 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1331 entry.push_back(Pair("account", strSentAccount));
1332 entry.push_back(Pair("address", s.first.ToString()));
1333 entry.push_back(Pair("category", "send"));
1334 entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
1335 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1337 WalletTxToJSON(wtx, entry);
1338 ret.push_back(entry);
1343 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1345 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1348 if (pwalletMain->mapAddressBook.count(r.first))
1349 account = pwalletMain->mapAddressBook[r.first];
1350 if (fAllAccounts || (account == strAccount))
1353 entry.push_back(Pair("account", account));
1354 entry.push_back(Pair("address", r.first.ToString()));
1355 entry.push_back(Pair("category", "receive"));
1356 entry.push_back(Pair("amount", ValueFromAmount(r.second)));
1358 WalletTxToJSON(wtx, entry);
1359 ret.push_back(entry);
1365 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
1367 bool fAllAccounts = (strAccount == string("*"));
1369 if (fAllAccounts || acentry.strAccount == strAccount)
1372 entry.push_back(Pair("account", acentry.strAccount));
1373 entry.push_back(Pair("category", "move"));
1374 entry.push_back(Pair("time", (boost::int64_t)acentry.nTime));
1375 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1376 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1377 entry.push_back(Pair("comment", acentry.strComment));
1378 ret.push_back(entry);
1382 Value listtransactions(const Array& params, bool fHelp)
1384 if (fHelp || params.size() > 3)
1385 throw runtime_error(
1386 "listtransactions [account] [count=10] [from=0]\n"
1387 "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
1389 string strAccount = "*";
1390 if (params.size() > 0)
1391 strAccount = params[0].get_str();
1393 if (params.size() > 1)
1394 nCount = params[1].get_int();
1396 if (params.size() > 2)
1397 nFrom = params[2].get_int();
1400 throw JSONRPCError(-8, "Negative count");
1402 throw JSONRPCError(-8, "Negative from");
1405 CWalletDB walletdb(pwalletMain->strWalletFile);
1407 // First: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap.
1408 typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
1409 typedef multimap<int64, TxPair > TxItems;
1412 // Note: maintaining indices in the database of (account,time) --> txid and (account, time) --> acentry
1413 // would make this much faster for applications that do this a lot.
1414 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1416 CWalletTx* wtx = &((*it).second);
1417 txByTime.insert(make_pair(wtx->GetTxTime(), TxPair(wtx, (CAccountingEntry*)0)));
1419 list<CAccountingEntry> acentries;
1420 walletdb.ListAccountCreditDebit(strAccount, acentries);
1421 BOOST_FOREACH(CAccountingEntry& entry, acentries)
1423 txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
1426 // iterate backwards until we have nCount items to return:
1427 for (TxItems::reverse_iterator it = txByTime.rbegin(); it != txByTime.rend(); ++it)
1429 CWalletTx *const pwtx = (*it).second.first;
1431 ListTransactions(*pwtx, strAccount, 0, true, ret);
1432 CAccountingEntry *const pacentry = (*it).second.second;
1434 AcentryToJSON(*pacentry, strAccount, ret);
1436 if (ret.size() >= (nCount+nFrom)) break;
1438 // ret is newest to oldest
1440 if (nFrom > (int)ret.size())
1442 if ((nFrom + nCount) > (int)ret.size())
1443 nCount = ret.size() - nFrom;
1444 Array::iterator first = ret.begin();
1445 std::advance(first, nFrom);
1446 Array::iterator last = ret.begin();
1447 std::advance(last, nFrom+nCount);
1449 if (last != ret.end()) ret.erase(last, ret.end());
1450 if (first != ret.begin()) ret.erase(ret.begin(), first);
1452 std::reverse(ret.begin(), ret.end()); // Return oldest to newest
1457 Value listaccounts(const Array& params, bool fHelp)
1459 if (fHelp || params.size() > 1)
1460 throw runtime_error(
1461 "listaccounts [minconf=1]\n"
1462 "Returns Object that has account names as keys, account balances as values.");
1465 if (params.size() > 0)
1466 nMinDepth = params[0].get_int();
1468 map<string, int64> mapAccountBalances;
1469 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& entry, pwalletMain->mapAddressBook) {
1470 if (pwalletMain->HaveKey(entry.first)) // This address belongs to me
1471 mapAccountBalances[entry.second] = 0;
1474 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1476 const CWalletTx& wtx = (*it).second;
1477 int64 nGeneratedImmature, nGeneratedMature, nFee;
1478 string strSentAccount;
1479 list<pair<CBitcoinAddress, int64> > listReceived;
1480 list<pair<CBitcoinAddress, int64> > listSent;
1481 wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
1482 mapAccountBalances[strSentAccount] -= nFee;
1483 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
1484 mapAccountBalances[strSentAccount] -= s.second;
1485 if (wtx.GetDepthInMainChain() >= nMinDepth)
1487 mapAccountBalances[""] += nGeneratedMature;
1488 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
1489 if (pwalletMain->mapAddressBook.count(r.first))
1490 mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
1492 mapAccountBalances[""] += r.second;
1496 list<CAccountingEntry> acentries;
1497 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1498 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1499 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1502 BOOST_FOREACH(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) {
1503 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1508 Value listsinceblock(const Array& params, bool fHelp)
1511 throw runtime_error(
1512 "listsinceblock [blockhash] [target-confirmations]\n"
1513 "Get all transactions in blocks since block [blockhash], or all transactions if omitted");
1515 CBlockIndex *pindex = NULL;
1516 int target_confirms = 1;
1518 if (params.size() > 0)
1520 uint256 blockId = 0;
1522 blockId.SetHex(params[0].get_str());
1523 pindex = CBlockLocator(blockId).GetBlockIndex();
1526 if (params.size() > 1)
1528 target_confirms = params[1].get_int();
1530 if (target_confirms < 1)
1531 throw JSONRPCError(-8, "Invalid parameter");
1534 int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1;
1538 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1540 CWalletTx tx = (*it).second;
1542 if (depth == -1 || tx.GetDepthInMainChain() < depth)
1543 ListTransactions(tx, "*", 0, true, transactions);
1548 if (target_confirms == 1)
1550 lastblock = hashBestChain;
1554 int target_height = pindexBest->nHeight + 1 - target_confirms;
1557 for (block = pindexBest;
1558 block && block->nHeight > target_height;
1559 block = block->pprev) { }
1561 lastblock = block ? block->GetBlockHash() : 0;
1565 ret.push_back(Pair("transactions", transactions));
1566 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1572 Value gettransaction(const Array& params, bool fHelp)
1574 if (fHelp || params.size() != 1)
1575 throw runtime_error(
1576 "gettransaction <txid>\n"
1577 "Get detailed information about <txid>");
1580 hash.SetHex(params[0].get_str());
1584 if (!pwalletMain->mapWallet.count(hash))
1585 throw JSONRPCError(-5, "Invalid or non-wallet transaction id");
1586 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1588 int64 nCredit = wtx.GetCredit();
1589 int64 nDebit = wtx.GetDebit();
1590 int64 nNet = nCredit - nDebit;
1591 int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
1593 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1595 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1597 WalletTxToJSON(pwalletMain->mapWallet[hash], entry);
1600 ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
1601 entry.push_back(Pair("details", details));
1608 Value gettransaction(const Array& params, bool fHelp)
1610 if (fHelp || params.size() != 1)
1611 throw runtime_error(
1612 "gettransaction <txid>\n"
1613 "Get detailed information about <txid>");
1616 hash.SetHex(params[0].get_str());
1620 if (pwalletMain->mapWallet.count(hash))
1622 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1624 TxToJSON(wtx, entry);
1626 int64 nCredit = wtx.GetCredit();
1627 int64 nDebit = wtx.GetDebit();
1628 int64 nNet = nCredit - nDebit;
1629 int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
1631 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1633 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1635 WalletTxToJSON(wtx, entry);
1638 ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
1639 entry.push_back(Pair("details", details));
1644 uint256 hashBlock = 0;
1645 if (GetTransaction(hash, tx, hashBlock))
1647 entry.push_back(Pair("txid", hash.GetHex()));
1648 TxToJSON(tx, entry);
1650 entry.push_back(Pair("confirmations", 0));
1653 entry.push_back(Pair("blockhash", hashBlock.GetHex()));
1654 map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
1655 if (mi != mapBlockIndex.end() && (*mi).second)
1657 CBlockIndex* pindex = (*mi).second;
1658 if (pindex->IsInMainChain())
1660 entry.push_back(Pair("confirmations", 1 + nBestHeight - pindex->nHeight));
1661 entry.push_back(Pair("time", (boost::int64_t)pindex->nTime));
1664 entry.push_back(Pair("confirmations", 0));
1669 throw JSONRPCError(-5, "No information available about transaction");
1676 Value backupwallet(const Array& params, bool fHelp)
1678 if (fHelp || params.size() != 1)
1679 throw runtime_error(
1680 "backupwallet <destination>\n"
1681 "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
1683 string strDest = params[0].get_str();
1684 BackupWallet(*pwalletMain, strDest);
1690 Value keypoolrefill(const Array& params, bool fHelp)
1692 if (pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1693 throw runtime_error(
1695 "Fills the keypool, requires wallet passphrase to be set.");
1696 if (!pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
1697 throw runtime_error(
1699 "Fills the keypool.");
1701 if (pwalletMain->IsLocked())
1702 throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
1704 pwalletMain->TopUpKeyPool();
1706 if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100))
1707 throw JSONRPCError(-4, "Error refreshing keypool.");
1713 void ThreadTopUpKeyPool(void* parg)
1715 pwalletMain->TopUpKeyPool();
1718 void ThreadCleanWalletPassphrase(void* parg)
1720 int64 nMyWakeTime = GetTimeMillis() + *((int64*)parg) * 1000;
1722 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1724 if (nWalletUnlockTime == 0)
1726 nWalletUnlockTime = nMyWakeTime;
1730 if (nWalletUnlockTime==0)
1732 int64 nToSleep = nWalletUnlockTime - GetTimeMillis();
1736 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1738 ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
1742 if (nWalletUnlockTime)
1744 nWalletUnlockTime = 0;
1745 pwalletMain->Lock();
1750 if (nWalletUnlockTime < nMyWakeTime)
1751 nWalletUnlockTime = nMyWakeTime;
1754 LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
1756 delete (int64*)parg;
1759 Value walletpassphrase(const Array& params, bool fHelp)
1761 if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 3))
1762 throw runtime_error(
1763 "walletpassphrase <passphrase> <timeout> [mintonly]\n"
1764 "Stores the wallet decryption key in memory for <timeout> seconds.\n"
1765 "mintonly is optional true/false allowing only block minting.");
1768 if (!pwalletMain->IsCrypted())
1769 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1771 if (!pwalletMain->IsLocked())
1772 throw JSONRPCError(-17, "Error: Wallet is already unlocked, use walletlock first if need to change unlock settings.");
1774 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1775 SecureString strWalletPass;
1776 strWalletPass.reserve(100);
1777 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1778 // Alternately, find a way to make params[0] mlock()'d to begin with.
1779 strWalletPass = params[0].get_str().c_str();
1781 if (strWalletPass.length() > 0)
1783 if (!pwalletMain->Unlock(strWalletPass))
1784 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1787 throw runtime_error(
1788 "walletpassphrase <passphrase> <timeout>\n"
1789 "Stores the wallet decryption key in memory for <timeout> seconds.");
1791 CreateThread(ThreadTopUpKeyPool, NULL);
1792 int64* pnSleepTime = new int64(params[1].get_int64());
1793 CreateThread(ThreadCleanWalletPassphrase, pnSleepTime);
1795 // ppcoin: if user OS account compromised prevent trivial sendmoney commands
1796 if (params.size() > 2)
1797 fWalletUnlockMintOnly = params[2].get_bool();
1799 fWalletUnlockMintOnly = false;
1805 Value walletpassphrasechange(const Array& params, bool fHelp)
1807 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1808 throw runtime_error(
1809 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1810 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1813 if (!pwalletMain->IsCrypted())
1814 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1816 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1817 // Alternately, find a way to make params[0] mlock()'d to begin with.
1818 SecureString strOldWalletPass;
1819 strOldWalletPass.reserve(100);
1820 strOldWalletPass = params[0].get_str().c_str();
1822 SecureString strNewWalletPass;
1823 strNewWalletPass.reserve(100);
1824 strNewWalletPass = params[1].get_str().c_str();
1826 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1827 throw runtime_error(
1828 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1829 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1831 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1832 throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
1838 Value walletlock(const Array& params, bool fHelp)
1840 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1841 throw runtime_error(
1843 "Removes the wallet encryption key from memory, locking the wallet.\n"
1844 "After calling this method, you will need to call walletpassphrase again\n"
1845 "before being able to call any methods which require the wallet to be unlocked.");
1848 if (!pwalletMain->IsCrypted())
1849 throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called.");
1852 LOCK(cs_nWalletUnlockTime);
1853 pwalletMain->Lock();
1854 nWalletUnlockTime = 0;
1861 Value encryptwallet(const Array& params, bool fHelp)
1863 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
1864 throw runtime_error(
1865 "encryptwallet <passphrase>\n"
1866 "Encrypts the wallet with <passphrase>.");
1869 if (pwalletMain->IsCrypted())
1870 throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
1872 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1873 // Alternately, find a way to make params[0] mlock()'d to begin with.
1874 SecureString strWalletPass;
1875 strWalletPass.reserve(100);
1876 strWalletPass = params[0].get_str().c_str();
1878 if (strWalletPass.length() < 1)
1879 throw runtime_error(
1880 "encryptwallet <passphrase>\n"
1881 "Encrypts the wallet with <passphrase>.");
1883 if (!pwalletMain->EncryptWallet(strWalletPass))
1884 throw JSONRPCError(-16, "Error: Failed to encrypt the wallet.");
1886 // BDB seems to have a bad habit of writing old data into
1887 // slack space in .dat files; that is bad if the old data is
1888 // unencrypted private keys. So:
1890 return "wallet encrypted; novacoin server stopping, restart to run with encrypted wallet";
1894 Value validateaddress(const Array& params, bool fHelp)
1896 if (fHelp || params.size() != 1)
1897 throw runtime_error(
1898 "validateaddress <novacoinaddress>\n"
1899 "Return information about <novacoinaddress>.");
1901 CBitcoinAddress address(params[0].get_str());
1902 bool isValid = address.IsValid();
1905 ret.push_back(Pair("isvalid", isValid));
1908 // Call Hash160ToAddress() so we always return current ADDRESSVERSION
1909 // version of the address:
1910 string currentAddress = address.ToString();
1911 ret.push_back(Pair("address", currentAddress));
1912 if (pwalletMain->HaveKey(address))
1914 ret.push_back(Pair("ismine", true));
1915 std::vector<unsigned char> vchPubKey;
1916 pwalletMain->GetPubKey(address, vchPubKey);
1917 ret.push_back(Pair("pubkey", HexStr(vchPubKey)));
1919 key.SetPubKey(vchPubKey);
1920 ret.push_back(Pair("iscompressed", key.IsCompressed()));
1922 else if (pwalletMain->HaveCScript(address.GetHash160()))
1924 ret.push_back(Pair("isscript", true));
1926 pwalletMain->GetCScript(address.GetHash160(), subscript);
1927 ret.push_back(Pair("ismine", ::IsMine(*pwalletMain, subscript)));
1928 std::vector<CBitcoinAddress> addresses;
1929 txnouttype whichType;
1931 ExtractAddresses(subscript, whichType, addresses, nRequired);
1932 ret.push_back(Pair("script", GetTxnOutputType(whichType)));
1934 BOOST_FOREACH(const CBitcoinAddress& addr, addresses)
1935 a.push_back(addr.ToString());
1936 ret.push_back(Pair("addresses", a));
1937 if (whichType == TX_MULTISIG)
1938 ret.push_back(Pair("sigsrequired", nRequired));
1941 ret.push_back(Pair("ismine", false));
1942 if (pwalletMain->mapAddressBook.count(address))
1943 ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
1948 Value validatepubkey(const Array& params, bool fHelp)
1950 if (fHelp || !params.size() || params.size() > 2)
1951 throw runtime_error(
1952 "validatepubkey <novacoinpubkey>\n"
1953 "Return information about <novacoinpubkey>.");
1955 std::vector<unsigned char> vchPubKey = ParseHex(params[0].get_str());
1958 if(vchPubKey.size() == 33) // Compressed key
1959 isValid = (vchPubKey[0] == 0x02 || vchPubKey[0] == 0x03);
1960 else if(vchPubKey.size() == 65) // Uncompressed key
1961 isValid = vchPubKey[0] == 0x04;
1965 CBitcoinAddress address(vchPubKey);
1966 isValid = isValid ? address.IsValid() : false;
1969 ret.push_back(Pair("isvalid", isValid));
1972 // Call Hash160ToAddress() so we always return current ADDRESSVERSION
1973 // version of the address:
1974 string currentAddress = address.ToString();
1975 ret.push_back(Pair("address", currentAddress));
1976 if (pwalletMain->HaveKey(address))
1978 ret.push_back(Pair("ismine", true));
1980 key.SetPubKey(vchPubKey);
1981 ret.push_back(Pair("iscompressed", key.IsCompressed()));
1984 ret.push_back(Pair("ismine", false));
1985 if (pwalletMain->mapAddressBook.count(address))
1986 ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
1991 Value getworkex(const Array& params, bool fHelp)
1993 if (fHelp || params.size() > 2)
1994 throw runtime_error(
1995 "getworkex [data, coinbase]\n"
1996 "If [data, coinbase] is not specified, returns extended work data.\n"
2000 throw JSONRPCError(-9, "NovaCoin is not connected!");
2002 if (IsInitialBlockDownload())
2003 throw JSONRPCError(-10, "NovaCoin is downloading blocks...");
2005 typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
2006 static mapNewBlock_t mapNewBlock;
2007 static vector<CBlock*> vNewBlock;
2008 static CReserveKey reservekey(pwalletMain);
2010 if (params.size() == 0)
2013 static unsigned int nTransactionsUpdatedLast;
2014 static CBlockIndex* pindexPrev;
2015 static int64 nStart;
2016 static CBlock* pblock;
2017 if (pindexPrev != pindexBest ||
2018 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
2020 if (pindexPrev != pindexBest)
2022 // Deallocate old blocks since they're obsolete now
2023 mapNewBlock.clear();
2024 BOOST_FOREACH(CBlock* pblock, vNewBlock)
2028 nTransactionsUpdatedLast = nTransactionsUpdated;
2029 pindexPrev = pindexBest;
2033 pblock = CreateNewBlock(pwalletMain);
2035 throw JSONRPCError(-7, "Out of memory");
2036 vNewBlock.push_back(pblock);
2040 pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
2043 // Update nExtraNonce
2044 static unsigned int nExtraNonce = 0;
2045 IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
2048 mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
2050 // Prebuild hash buffers
2054 FormatHashBuffers(pblock, pmidstate, pdata, phash1);
2056 uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
2058 CTransaction coinbaseTx = pblock->vtx[0];
2059 std::vector<uint256> merkle = pblock->GetMerkleBranch(0);
2062 result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata))));
2063 result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
2065 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
2067 result.push_back(Pair("coinbase", HexStr(ssTx.begin(), ssTx.end())));
2070 printf("DEBUG: merkle size %i\n", merkle.size());
2072 BOOST_FOREACH(uint256 merkleh, merkle) {
2073 printf("%s\n", merkleh.ToString().c_str());
2074 merkle_arr.push_back(HexStr(BEGIN(merkleh), END(merkleh)));
2077 result.push_back(Pair("merkle", merkle_arr));
2085 vector<unsigned char> vchData = ParseHex(params[0].get_str());
2086 vector<unsigned char> coinbase;
2088 if(params.size() == 2)
2089 coinbase = ParseHex(params[1].get_str());
2091 if (vchData.size() != 128)
2092 throw JSONRPCError(-8, "Invalid parameter");
2094 CBlock* pdata = (CBlock*)&vchData[0];
2097 for (int i = 0; i < 128/4; i++)
2098 ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]);
2101 if (!mapNewBlock.count(pdata->hashMerkleRoot))
2103 CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
2105 pblock->nTime = pdata->nTime;
2106 pblock->nNonce = pdata->nNonce;
2108 if(coinbase.size() == 0)
2109 pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
2111 CDataStream(coinbase, SER_NETWORK, PROTOCOL_VERSION) >> pblock->vtx[0]; // FIXME - HACK!
2113 pblock->hashMerkleRoot = pblock->BuildMerkleTree();
2115 if (!pblock->SignBlock(*pwalletMain))
2116 throw JSONRPCError(-100, "Unable to sign block, wallet locked?");
2118 return CheckWork(pblock, *pwalletMain, reservekey);
2123 Value getwork(const Array& params, bool fHelp)
2125 if (fHelp || params.size() > 1)
2126 throw runtime_error(
2128 "If [data] is not specified, returns formatted hash data to work on:\n"
2129 " \"midstate\" : precomputed hash state after hashing the first half of the data (DEPRECATED)\n" // deprecated
2130 " \"data\" : block data\n"
2131 " \"hash1\" : formatted hash buffer for second hash (DEPRECATED)\n" // deprecated
2132 " \"target\" : little endian hash target\n"
2133 "If [data] is specified, tries to solve the block and returns true if it was successful.");
2136 throw JSONRPCError(-9, "NovaCoin is not connected!");
2138 if (IsInitialBlockDownload())
2139 throw JSONRPCError(-10, "NovaCoin is downloading blocks...");
2141 typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
2142 static mapNewBlock_t mapNewBlock;
2143 static vector<CBlock*> vNewBlock;
2144 static CReserveKey reservekey(pwalletMain);
2146 if (params.size() == 0)
2149 static unsigned int nTransactionsUpdatedLast;
2150 static CBlockIndex* pindexPrev;
2151 static int64 nStart;
2152 static CBlock* pblock;
2153 if (pindexPrev != pindexBest ||
2154 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
2156 if (pindexPrev != pindexBest)
2158 // Deallocate old blocks since they're obsolete now
2159 mapNewBlock.clear();
2160 BOOST_FOREACH(CBlock* pblock, vNewBlock)
2164 nTransactionsUpdatedLast = nTransactionsUpdated;
2165 pindexPrev = pindexBest;
2169 pblock = CreateNewBlock(pwalletMain);
2171 throw JSONRPCError(-7, "Out of memory");
2172 vNewBlock.push_back(pblock);
2176 pblock->UpdateTime(pindexPrev);
2179 // Update nExtraNonce
2180 static unsigned int nExtraNonce = 0;
2181 IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
2184 mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
2186 // Prebuild hash buffers
2190 FormatHashBuffers(pblock, pmidstate, pdata, phash1);
2192 uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
2195 result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate)))); // deprecated
2196 result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata))));
2197 result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1)))); // deprecated
2198 result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
2204 vector<unsigned char> vchData = ParseHex(params[0].get_str());
2205 if (vchData.size() != 128)
2206 throw JSONRPCError(-8, "Invalid parameter");
2207 CBlock* pdata = (CBlock*)&vchData[0];
2210 for (int i = 0; i < 128/4; i++)
2211 ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]);
2214 if (!mapNewBlock.count(pdata->hashMerkleRoot))
2216 CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
2218 pblock->nTime = pdata->nTime;
2219 pblock->nNonce = pdata->nNonce;
2220 pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
2221 pblock->hashMerkleRoot = pblock->BuildMerkleTree();
2222 if (!pblock->SignBlock(*pwalletMain))
2223 throw JSONRPCError(-100, "Unable to sign block, wallet locked?");
2225 return CheckWork(pblock, *pwalletMain, reservekey);
2229 Value getblocktemplate(const Array& params, bool fHelp)
2231 if (fHelp || params.size() > 1)
2232 throw runtime_error(
2233 "getblocktemplate [params]\n"
2234 "Returns data needed to construct a block to work on:\n"
2235 " \"version\" : block version\n"
2236 " \"previousblockhash\" : hash of current highest block\n"
2237 " \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
2238 " \"coinbaseaux\" : data that should be included in coinbase\n"
2239 " \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
2240 " \"target\" : hash target\n"
2241 " \"mintime\" : minimum timestamp appropriate for next block\n"
2242 " \"curtime\" : current timestamp\n"
2243 " \"mutable\" : list of ways the block template may be changed\n"
2244 " \"noncerange\" : range of valid nonces\n"
2245 " \"sigoplimit\" : limit of sigops in blocks\n"
2246 " \"sizelimit\" : limit of block size\n"
2247 " \"bits\" : compressed target of next block\n"
2248 " \"height\" : height of the next block\n"
2249 "See https://en.bitcoin.it/wiki/BIP_0022 for full specification.");
2251 std::string strMode = "template";
2252 if (params.size() > 0)
2254 const Object& oparam = params[0].get_obj();
2255 const Value& modeval = find_value(oparam, "mode");
2256 if (modeval.type() == str_type)
2257 strMode = modeval.get_str();
2259 throw JSONRPCError(-8, "Invalid mode");
2262 if (strMode != "template")
2263 throw JSONRPCError(-8, "Invalid mode");
2266 throw JSONRPCError(-9, "NovaCoin is not connected!");
2268 if (IsInitialBlockDownload())
2269 throw JSONRPCError(-10, "NovaCoin is downloading blocks...");
2271 static CReserveKey reservekey(pwalletMain);
2274 static unsigned int nTransactionsUpdatedLast;
2275 static CBlockIndex* pindexPrev;
2276 static int64 nStart;
2277 static CBlock* pblock;
2278 if (pindexPrev != pindexBest ||
2279 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5))
2281 // Clear pindexPrev so future calls make a new block, despite any failures from here on
2284 // Store the pindexBest used before CreateNewBlock, to avoid races
2285 nTransactionsUpdatedLast = nTransactionsUpdated;
2286 CBlockIndex* pindexPrevNew = pindexBest;
2295 pblock = CreateNewBlock(pwalletMain);
2297 throw JSONRPCError(-7, "Out of memory");
2299 // Need to update only after we know CreateNewBlock succeeded
2300 pindexPrev = pindexPrevNew;
2304 pblock->UpdateTime(pindexPrev);
2308 map<uint256, int64_t> setTxIndex;
2311 BOOST_FOREACH (CTransaction& tx, pblock->vtx)
2313 uint256 txHash = tx.GetHash();
2314 setTxIndex[txHash] = i++;
2316 if (tx.IsCoinBase() || tx.IsCoinStake())
2321 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
2323 entry.push_back(Pair("data", HexStr(ssTx.begin(), ssTx.end())));
2325 entry.push_back(Pair("hash", txHash.GetHex()));
2327 MapPrevTx mapInputs;
2328 map<uint256, CTxIndex> mapUnused;
2329 bool fInvalid = false;
2330 if (tx.FetchInputs(txdb, mapUnused, false, false, mapInputs, fInvalid))
2332 entry.push_back(Pair("fee", (int64_t)(tx.GetValueIn(mapInputs) - tx.GetValueOut())));
2335 BOOST_FOREACH (MapPrevTx::value_type& inp, mapInputs)
2337 if (setTxIndex.count(inp.first))
2338 deps.push_back(setTxIndex[inp.first]);
2340 entry.push_back(Pair("depends", deps));
2342 int64_t nSigOps = tx.GetLegacySigOpCount();
2343 nSigOps += tx.GetP2SHSigOpCount(mapInputs);
2344 entry.push_back(Pair("sigops", nSigOps));
2347 transactions.push_back(entry);
2351 aux.push_back(Pair("flags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end())));
2353 uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
2355 static Array aMutable;
2356 if (aMutable.empty())
2358 aMutable.push_back("time");
2359 aMutable.push_back("transactions");
2360 aMutable.push_back("prevblock");
2364 result.push_back(Pair("version", pblock->nVersion));
2365 result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
2366 result.push_back(Pair("transactions", transactions));
2367 result.push_back(Pair("coinbaseaux", aux));
2368 result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
2369 result.push_back(Pair("target", hashTarget.GetHex()));
2370 result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1));
2371 result.push_back(Pair("mutable", aMutable));
2372 result.push_back(Pair("noncerange", "00000000ffffffff"));
2373 result.push_back(Pair("sigoplimit", (int64_t)MAX_BLOCK_SIGOPS));
2374 result.push_back(Pair("sizelimit", (int64_t)MAX_BLOCK_SIZE));
2375 result.push_back(Pair("curtime", (int64_t)pblock->nTime));
2376 result.push_back(Pair("bits", HexBits(pblock->nBits)));
2377 result.push_back(Pair("height", (int64_t)(pindexPrev->nHeight+1)));
2382 Value submitblock(const Array& params, bool fHelp)
2384 if (fHelp || params.size() < 1 || params.size() > 2)
2385 throw runtime_error(
2386 "submitblock <hex data> [optional-params-obj]\n"
2387 "[optional-params-obj] parameter is currently ignored.\n"
2388 "Attempts to submit new block to network.\n"
2389 "See https://en.bitcoin.it/wiki/BIP_0022 for full specification.");
2391 vector<unsigned char> blockData(ParseHex(params[0].get_str()));
2392 CDataStream ssBlock(blockData, SER_NETWORK, PROTOCOL_VERSION);
2397 catch (std::exception &e) {
2398 throw JSONRPCError(-22, "Block decode failed");
2401 static CReserveKey reservekey(pwalletMain);
2403 if(!block.SignBlock(*pwalletMain))
2404 throw JSONRPCError(-100, "Unable to sign block, wallet locked?");
2406 bool fAccepted = CheckWork(&block, *pwalletMain, reservekey);
2414 Value getmemorypool(const Array& params, bool fHelp)
2416 if (fHelp || params.size() > 1)
2417 throw runtime_error(
2418 "getmemorypool [data]\n"
2419 "If [data] is not specified, returns data needed to construct a block to work on:\n"
2420 " \"version\" : block version\n"
2421 " \"previousblockhash\" : hash of current highest block\n"
2422 " \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
2423 " \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
2424 " \"coinbaseflags\" : data that should be included in coinbase so support for new features can be judged\n"
2425 " \"time\" : timestamp appropriate for next block\n"
2426 " \"mintime\" : minimum timestamp appropriate for next block\n"
2427 " \"curtime\" : current timestamp\n"
2428 " \"bits\" : compressed target of next block\n"
2429 "If [data] is specified, tries to solve the block and returns true if it was successful.");
2431 if (params.size() == 0)
2434 throw JSONRPCError(-9, "NovaCoin is not connected!");
2436 if (IsInitialBlockDownload())
2437 throw JSONRPCError(-10, "NovaCoin is downloading blocks...");
2439 static CReserveKey reservekey(pwalletMain);
2442 static unsigned int nTransactionsUpdatedLast;
2443 static CBlockIndex* pindexPrev;
2444 static int64 nStart;
2445 static CBlock* pblock;
2446 if (pindexPrev != pindexBest ||
2447 (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5))
2449 nTransactionsUpdatedLast = nTransactionsUpdated;
2450 pindexPrev = pindexBest;
2456 pblock = CreateNewBlock(pwalletMain);
2458 throw JSONRPCError(-7, "Out of memory");
2462 pblock->UpdateTime(pindexPrev);
2466 BOOST_FOREACH(CTransaction tx, pblock->vtx) {
2467 if(tx.IsCoinBase() || tx.IsCoinStake())
2470 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
2473 transactions.push_back(HexStr(ssTx.begin(), ssTx.end()));
2477 result.push_back(Pair("version", pblock->nVersion));
2478 result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
2479 result.push_back(Pair("transactions", transactions));
2480 result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
2481 result.push_back(Pair("coinbaseflags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end())));
2482 result.push_back(Pair("time", (int64_t)pblock->nTime));
2483 result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1));
2484 result.push_back(Pair("curtime", (int64_t)GetAdjustedTime()));
2485 result.push_back(Pair("bits", HexBits(pblock->nBits)));
2492 CDataStream ssBlock(ParseHex(params[0].get_str()), SER_NETWORK, PROTOCOL_VERSION);
2496 static CReserveKey reservekey(pwalletMain);
2498 if(!pblock.SignBlock(*pwalletMain))
2499 throw JSONRPCError(-100, "Unable to sign block, wallet locked?");
2501 return CheckWork(&pblock, *pwalletMain, reservekey);
2505 Value getnewpubkey(const Array& params, bool fHelp)
2507 if (fHelp || params.size() > 1)
2508 throw runtime_error(
2509 "getnewpubkey [account]\n"
2510 "Returns new public key for coinbase generation.");
2512 // Parse the account first so we don't generate a key if there's an error
2514 if (params.size() > 0)
2515 strAccount = AccountFromValue(params[0]);
2517 if (!pwalletMain->IsLocked())
2518 pwalletMain->TopUpKeyPool();
2520 // Generate a new key that is added to wallet
2521 std::vector<unsigned char> newKey = pwalletMain->GenerateNewKey(false);
2524 throw JSONRPCError(-12, "Error: Unable to create key");
2526 CBitcoinAddress address(newKey);
2527 pwalletMain->SetAddressBookName(address, strAccount);
2529 return HexStr(newKey.begin(), newKey.end());
2532 Value getblockhash(const Array& params, bool fHelp)
2534 if (fHelp || params.size() != 1)
2535 throw runtime_error(
2536 "getblockhash <index>\n"
2537 "Returns hash of block in best-block-chain at <index>.");
2539 int nHeight = params[0].get_int();
2540 if (nHeight < 0 || nHeight > nBestHeight)
2541 throw runtime_error("Block number out of range.");
2544 CBlockIndex* pblockindex = mapBlockIndex[hashBestChain];
2545 while (pblockindex->nHeight > nHeight)
2546 pblockindex = pblockindex->pprev;
2547 return pblockindex->phashBlock->GetHex();
2550 Value getblock(const Array& params, bool fHelp)
2552 if (fHelp || params.size() < 1 || params.size() > 2)
2553 throw runtime_error(
2554 "getblock <hash> [txinfo]\n"
2555 "txinfo optional to print more detailed tx info\n"
2556 "Returns details of a block with given block-hash.");
2558 std::string strHash = params[0].get_str();
2559 uint256 hash(strHash);
2561 if (mapBlockIndex.count(hash) == 0)
2562 throw JSONRPCError(-5, "Block not found");
2565 CBlockIndex* pblockindex = mapBlockIndex[hash];
2566 block.ReadFromDisk(pblockindex, true);
2568 return blockToJSON(block, pblockindex, params.size() > 1 ? params[1].get_bool() : false);
2571 Value getblockbynumber(const Array& params, bool fHelp)
2573 if (fHelp || params.size() < 1 || params.size() > 2)
2574 throw runtime_error(
2575 "getblock <number> [txinfo]\n"
2576 "txinfo optional to print more detailed tx info\n"
2577 "Returns details of a block with given block-number.");
2579 int nHeight = params[0].get_int();
2580 if (nHeight < 0 || nHeight > nBestHeight)
2581 throw runtime_error("Block number out of range.");
2584 CBlockIndex* pblockindex = mapBlockIndex[hashBestChain];
2585 while (pblockindex->nHeight > nHeight)
2586 pblockindex = pblockindex->pprev;
2588 uint256 hash = *pblockindex->phashBlock;
2590 pblockindex = mapBlockIndex[hash];
2591 block.ReadFromDisk(pblockindex, true);
2593 return blockToJSON(block, pblockindex, params.size() > 1 ? params[1].get_bool() : false);
2596 // ppcoin: get information of sync-checkpoint
2597 Value getcheckpoint(const Array& params, bool fHelp)
2599 if (fHelp || params.size() != 0)
2600 throw runtime_error(
2602 "Show info of synchronized checkpoint.\n");
2605 CBlockIndex* pindexCheckpoint;
2607 result.push_back(Pair("synccheckpoint", Checkpoints::hashSyncCheckpoint.ToString().c_str()));
2608 pindexCheckpoint = mapBlockIndex[Checkpoints::hashSyncCheckpoint];
2609 result.push_back(Pair("height", pindexCheckpoint->nHeight));
2610 result.push_back(Pair("timestamp", DateTimeStrFormat(pindexCheckpoint->GetBlockTime()).c_str()));
2611 if (mapArgs.count("-checkpointkey"))
2612 result.push_back(Pair("checkpointmaster", true));
2618 // ppcoin: reserve balance from being staked for network protection
2619 Value reservebalance(const Array& params, bool fHelp)
2621 if (fHelp || params.size() > 2)
2622 throw runtime_error(
2623 "reservebalance [<reserve> [amount]]\n"
2624 "<reserve> is true or false to turn balance reserve on or off.\n"
2625 "<amount> is a real and rounded to cent.\n"
2626 "Set reserve amount not participating in network protection.\n"
2627 "If no parameters provided current setting is printed.\n");
2629 if (params.size() > 0)
2631 bool fReserve = params[0].get_bool();
2634 if (params.size() == 1)
2635 throw runtime_error("must provide amount to reserve balance.\n");
2636 int64 nAmount = AmountFromValue(params[1]);
2637 nAmount = (nAmount / CENT) * CENT; // round to cent
2639 throw runtime_error("amount cannot be negative.\n");
2640 mapArgs["-reservebalance"] = FormatMoney(nAmount).c_str();
2644 if (params.size() > 1)
2645 throw runtime_error("cannot specify amount to turn off reserve.\n");
2646 mapArgs["-reservebalance"] = "0";
2651 int64 nReserveBalance = 0;
2652 if (mapArgs.count("-reservebalance") && !ParseMoney(mapArgs["-reservebalance"], nReserveBalance))
2653 throw runtime_error("invalid reserve balance amount\n");
2654 result.push_back(Pair("reserve", (nReserveBalance > 0)));
2655 result.push_back(Pair("amount", ValueFromAmount(nReserveBalance)));
2660 // ppcoin: check wallet integrity
2661 Value checkwallet(const Array& params, bool fHelp)
2663 if (fHelp || params.size() > 0)
2664 throw runtime_error(
2666 "Check wallet for integrity.\n");
2669 int64 nBalanceInQuestion;
2670 pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion, true);
2672 if (nMismatchSpent == 0)
2673 result.push_back(Pair("wallet check passed", true));
2676 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
2677 result.push_back(Pair("amount in question", ValueFromAmount(nBalanceInQuestion)));
2683 // ppcoin: repair wallet
2684 Value repairwallet(const Array& params, bool fHelp)
2686 if (fHelp || params.size() > 0)
2687 throw runtime_error(
2689 "Repair wallet if checkwallet reports any problem.\n");
2692 int64 nBalanceInQuestion;
2693 pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion);
2695 if (nMismatchSpent == 0)
2696 result.push_back(Pair("wallet check passed", true));
2699 result.push_back(Pair("mismatched spent coins", nMismatchSpent));
2700 result.push_back(Pair("amount affected by repair", ValueFromAmount(nBalanceInQuestion)));
2705 // NovaCoin: resend unconfirmed wallet transactions
2706 Value resendtx(const Array& params, bool fHelp)
2708 if (fHelp || params.size() > 1)
2709 throw runtime_error(
2711 "Re-send unconfirmed transactions.\n"
2714 ResendWalletTransactions();
2720 // ppcoin: make a public-private key pair
2721 Value makekeypair(const Array& params, bool fHelp)
2723 if (fHelp || params.size() > 1)
2724 throw runtime_error(
2725 "makekeypair [prefix]\n"
2726 "Make a public/private key pair.\n"
2727 "[prefix] is optional preferred prefix for the public key.\n");
2729 string strPrefix = "";
2730 if (params.size() > 0)
2731 strPrefix = params[0].get_str();
2737 key.MakeNewKey(false);
2739 } while (nCount < 10000 && strPrefix != HexStr(key.GetPubKey()).substr(0, strPrefix.size()));
2741 if (strPrefix != HexStr(key.GetPubKey()).substr(0, strPrefix.size()))
2744 CPrivKey vchPrivKey = key.GetPrivKey();
2746 result.push_back(Pair("PrivateKey", HexStr<CPrivKey::iterator>(vchPrivKey.begin(), vchPrivKey.end())));
2747 result.push_back(Pair("PublicKey", HexStr(key.GetPubKey())));
2751 extern CCriticalSection cs_mapAlerts;
2752 extern map<uint256, CAlert> mapAlerts;
2754 // ppcoin: send alert.
2755 // There is a known deadlock situation with ThreadMessageHandler
2756 // ThreadMessageHandler: holds cs_vSend and acquiring cs_main in SendMessages()
2757 // ThreadRPCServer: holds cs_main and acquiring cs_vSend in alert.RelayTo()/PushMessage()/BeginMessage()
2758 Value sendalert(const Array& params, bool fHelp)
2760 if (fHelp || params.size() < 6)
2761 throw runtime_error(
2762 "sendalert <message> <privatekey> <minver> <maxver> <priority> <id> [cancelupto]\n"
2763 "<message> is the alert text message\n"
2764 "<privatekey> is hex string of alert master private key\n"
2765 "<minver> is the minimum applicable internal client version\n"
2766 "<maxver> is the maximum applicable internal client version\n"
2767 "<priority> is integer priority number\n"
2768 "<id> is the alert id\n"
2769 "[cancelupto] cancels all alert id's up to this number\n"
2770 "Returns true or false.");
2775 alert.strStatusBar = params[0].get_str();
2776 alert.nMinVer = params[2].get_int();
2777 alert.nMaxVer = params[3].get_int();
2778 alert.nPriority = params[4].get_int();
2779 alert.nID = params[5].get_int();
2780 if (params.size() > 6)
2781 alert.nCancel = params[6].get_int();
2782 alert.nVersion = PROTOCOL_VERSION;
2783 alert.nRelayUntil = GetAdjustedTime() + 365*24*60*60;
2784 alert.nExpiration = GetAdjustedTime() + 365*24*60*60;
2786 CDataStream sMsg(SER_NETWORK, PROTOCOL_VERSION);
2787 sMsg << (CUnsignedAlert)alert;
2788 alert.vchMsg = vector<unsigned char>(sMsg.begin(), sMsg.end());
2790 vector<unsigned char> vchPrivKey = ParseHex(params[1].get_str());
2791 key.SetPrivKey(CPrivKey(vchPrivKey.begin(), vchPrivKey.end())); // if key is not correct openssl may crash
2792 if (!key.Sign(Hash(alert.vchMsg.begin(), alert.vchMsg.end()), alert.vchSig))
2793 throw runtime_error(
2794 "Unable to sign alert, check private key?\n");
2795 if(!alert.ProcessAlert())
2796 throw runtime_error(
2797 "Failed to process alert.\n");
2801 BOOST_FOREACH(CNode* pnode, vNodes)
2802 alert.RelayTo(pnode);
2806 result.push_back(Pair("strStatusBar", alert.strStatusBar));
2807 result.push_back(Pair("nVersion", alert.nVersion));
2808 result.push_back(Pair("nMinVer", alert.nMinVer));
2809 result.push_back(Pair("nMaxVer", alert.nMaxVer));
2810 result.push_back(Pair("nPriority", alert.nPriority));
2811 result.push_back(Pair("nID", alert.nID));
2812 if (alert.nCancel > 0)
2813 result.push_back(Pair("nCancel", alert.nCancel));
2824 static const CRPCCommand vRPCCommands[] =
2825 { // name function safe mode?
2826 // ------------------------ ----------------------- ----------
2827 { "help", &help, true },
2828 { "stop", &stop, true },
2829 { "getblockcount", &getblockcount, true },
2830 { "getblocknumber", &getblocknumber, true },
2831 { "getconnectioncount", &getconnectioncount, true },
2832 { "getdifficulty", &getdifficulty, true },
2833 { "getpowreward", &getpowreward, true },
2834 { "getgenerate", &getgenerate, true },
2835 { "setgenerate", &setgenerate, true },
2836 { "gethashespersec", &gethashespersec, true },
2837 { "getinfo", &getinfo, true },
2838 { "getmininginfo", &getmininginfo, true },
2839 { "getnewaddress", &getnewaddress, true },
2840 { "getnewpubkey", &getnewpubkey, true },
2841 { "getaccountaddress", &getaccountaddress, true },
2842 { "setaccount", &setaccount, true },
2843 { "getaccount", &getaccount, false },
2844 { "getaddressesbyaccount", &getaddressesbyaccount, true },
2845 { "sendtoaddress", &sendtoaddress, false },
2846 { "getreceivedbyaddress", &getreceivedbyaddress, false },
2847 { "getreceivedbyaccount", &getreceivedbyaccount, false },
2848 { "listreceivedbyaddress", &listreceivedbyaddress, false },
2849 { "listreceivedbyaccount", &listreceivedbyaccount, false },
2850 { "backupwallet", &backupwallet, true },
2851 { "keypoolrefill", &keypoolrefill, true },
2852 { "walletpassphrase", &walletpassphrase, true },
2853 { "walletpassphrasechange", &walletpassphrasechange, false },
2854 { "walletlock", &walletlock, true },
2855 { "encryptwallet", &encryptwallet, false },
2856 { "validateaddress", &validateaddress, true },
2857 { "validatepubkey", &validatepubkey, true },
2858 { "getbalance", &getbalance, false },
2859 { "move", &movecmd, false },
2860 { "sendfrom", &sendfrom, false },
2861 { "sendmany", &sendmany, false },
2862 { "addmultisigaddress", &addmultisigaddress, false },
2863 { "getblock", &getblock, false },
2864 { "getblockhash", &getblockhash, false },
2865 { "getblockbynumber", &getblockbynumber, false },
2866 { "gettransaction", &gettransaction, false },
2867 { "listtransactions", &listtransactions, false },
2868 { "signmessage", &signmessage, false },
2869 { "verifymessage", &verifymessage, false },
2870 { "getwork", &getwork, true },
2871 { "getworkex", &getworkex, true },
2872 { "listaccounts", &listaccounts, false },
2873 { "settxfee", &settxfee, false },
2874 { "getmemorypool", &getmemorypool, true },
2875 { "getblocktemplate", &getblocktemplate, true },
2876 { "submitblock", &submitblock, false },
2877 { "listsinceblock", &listsinceblock, false },
2878 { "dumpprivkey", &dumpprivkey, false },
2879 { "importprivkey", &importprivkey, false },
2880 { "getcheckpoint", &getcheckpoint, true },
2881 { "reservebalance", &reservebalance, false},
2882 { "checkwallet", &checkwallet, false},
2883 { "repairwallet", &repairwallet, false},
2884 { "resendtx", &resendtx, false},
2885 { "makekeypair", &makekeypair, false},
2886 { "sendalert", &sendalert, false},
2889 CRPCTable::CRPCTable()
2892 for (vcidx = 0; vcidx < (sizeof(vRPCCommands) / sizeof(vRPCCommands[0])); vcidx++)
2894 const CRPCCommand *pcmd;
2896 pcmd = &vRPCCommands[vcidx];
2897 mapCommands[pcmd->name] = pcmd;
2901 const CRPCCommand *CRPCTable::operator[](string name) const
2903 map<string, const CRPCCommand*>::const_iterator it = mapCommands.find(name);
2904 if (it == mapCommands.end())
2906 return (*it).second;
2912 // This ain't Apache. We're just using HTTP header for the length field
2913 // and to be compatible with other JSON-RPC implementations.
2916 string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
2919 s << "POST / HTTP/1.1\r\n"
2920 << "User-Agent: novacoin-json-rpc/" << FormatFullVersion() << "\r\n"
2921 << "Host: 127.0.0.1\r\n"
2922 << "Content-Type: application/json\r\n"
2923 << "Content-Length: " << strMsg.size() << "\r\n"
2924 << "Connection: close\r\n"
2925 << "Accept: application/json\r\n";
2926 BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
2927 s << item.first << ": " << item.second << "\r\n";
2928 s << "\r\n" << strMsg;
2933 string rfc1123Time()
2938 struct tm* now_gmt = gmtime(&now);
2939 string locale(setlocale(LC_TIME, NULL));
2940 setlocale(LC_TIME, "C"); // we want posix (aka "C") weekday/month strings
2941 strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt);
2942 setlocale(LC_TIME, locale.c_str());
2943 return string(buffer);
2946 static string HTTPReply(int nStatus, const string& strMsg)
2949 return strprintf("HTTP/1.0 401 Authorization Required\r\n"
2951 "Server: novacoin-json-rpc/%s\r\n"
2952 "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
2953 "Content-Type: text/html\r\n"
2954 "Content-Length: 296\r\n"
2956 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
2957 "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
2960 "<TITLE>Error</TITLE>\r\n"
2961 "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
2963 "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
2964 "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
2965 const char *cStatus;
2966 if (nStatus == 200) cStatus = "OK";
2967 else if (nStatus == 400) cStatus = "Bad Request";
2968 else if (nStatus == 403) cStatus = "Forbidden";
2969 else if (nStatus == 404) cStatus = "Not Found";
2970 else if (nStatus == 500) cStatus = "Internal Server Error";
2973 "HTTP/1.1 %d %s\r\n"
2975 "Connection: close\r\n"
2976 "Content-Length: %d\r\n"
2977 "Content-Type: application/json\r\n"
2978 "Server: novacoin-json-rpc/%s\r\n"
2983 rfc1123Time().c_str(),
2985 FormatFullVersion().c_str(),
2989 int ReadHTTPStatus(std::basic_istream<char>& stream)
2992 getline(stream, str);
2993 vector<string> vWords;
2994 boost::split(vWords, str, boost::is_any_of(" "));
2995 if (vWords.size() < 2)
2997 return atoi(vWords[1].c_str());
3000 int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
3006 std::getline(stream, str);
3007 if (str.empty() || str == "\r")
3009 string::size_type nColon = str.find(":");
3010 if (nColon != string::npos)
3012 string strHeader = str.substr(0, nColon);
3013 boost::trim(strHeader);
3014 boost::to_lower(strHeader);
3015 string strValue = str.substr(nColon+1);
3016 boost::trim(strValue);
3017 mapHeadersRet[strHeader] = strValue;
3018 if (strHeader == "content-length")
3019 nLen = atoi(strValue.c_str());
3025 int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
3027 mapHeadersRet.clear();
3031 int nStatus = ReadHTTPStatus(stream);
3034 int nLen = ReadHTTPHeader(stream, mapHeadersRet);
3035 if (nLen < 0 || nLen > (int)MAX_SIZE)
3041 vector<char> vch(nLen);
3042 stream.read(&vch[0], nLen);
3043 strMessageRet = string(vch.begin(), vch.end());
3049 bool HTTPAuthorized(map<string, string>& mapHeaders)
3051 string strAuth = mapHeaders["authorization"];
3052 if (strAuth.substr(0,6) != "Basic ")
3054 string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
3055 string strUserPass = DecodeBase64(strUserPass64);
3056 return strUserPass == strRPCUserColonPass;
3060 // JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
3061 // but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
3062 // unspecified (HTTP errors and contents of 'error').
3064 // 1.0 spec: http://json-rpc.org/wiki/specification
3065 // 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
3066 // http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
3069 string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
3072 request.push_back(Pair("method", strMethod));
3073 request.push_back(Pair("params", params));
3074 request.push_back(Pair("id", id));
3075 return write_string(Value(request), false) + "\n";
3078 string JSONRPCReply(const Value& result, const Value& error, const Value& id)
3081 if (error.type() != null_type)
3082 reply.push_back(Pair("result", Value::null));
3084 reply.push_back(Pair("result", result));
3085 reply.push_back(Pair("error", error));
3086 reply.push_back(Pair("id", id));
3087 return write_string(Value(reply), false) + "\n";
3090 void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
3092 // Send error reply from json-rpc error object
3094 int code = find_value(objError, "code").get_int();
3095 if (code == -32600) nStatus = 400;
3096 else if (code == -32601) nStatus = 404;
3097 string strReply = JSONRPCReply(Value::null, objError, id);
3098 stream << HTTPReply(nStatus, strReply) << std::flush;
3101 bool ClientAllowed(const string& strAddress)
3103 if (strAddress == asio::ip::address_v4::loopback().to_string())
3105 const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
3106 BOOST_FOREACH(string strAllow, vAllow)
3107 if (WildcardMatch(strAddress, strAllow))
3113 // IOStream device that speaks SSL but can also speak non-SSL
3115 class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
3117 SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
3119 fUseSSL = fUseSSLIn;
3120 fNeedHandshake = fUseSSLIn;
3123 void handshake(ssl::stream_base::handshake_type role)
3125 if (!fNeedHandshake) return;
3126 fNeedHandshake = false;
3127 stream.handshake(role);
3129 std::streamsize read(char* s, std::streamsize n)
3131 handshake(ssl::stream_base::server); // HTTPS servers read first
3132 if (fUseSSL) return stream.read_some(asio::buffer(s, n));
3133 return stream.next_layer().read_some(asio::buffer(s, n));
3135 std::streamsize write(const char* s, std::streamsize n)
3137 handshake(ssl::stream_base::client); // HTTPS clients write first
3138 if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
3139 return asio::write(stream.next_layer(), asio::buffer(s, n));
3141 bool connect(const std::string& server, const std::string& port)
3143 ip::tcp::resolver resolver(stream.get_io_service());
3144 ip::tcp::resolver::query query(server.c_str(), port.c_str());
3145 ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
3146 ip::tcp::resolver::iterator end;
3147 boost::system::error_code error = asio::error::host_not_found;
3148 while (error && endpoint_iterator != end)
3150 stream.lowest_layer().close();
3151 stream.lowest_layer().connect(*endpoint_iterator++, error);
3159 bool fNeedHandshake;
3164 void ThreadRPCServer(void* parg)
3166 IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
3169 vnThreadsRunning[THREAD_RPCSERVER]++;
3170 ThreadRPCServer2(parg);
3171 vnThreadsRunning[THREAD_RPCSERVER]--;
3173 catch (std::exception& e) {
3174 vnThreadsRunning[THREAD_RPCSERVER]--;
3175 PrintException(&e, "ThreadRPCServer()");
3177 vnThreadsRunning[THREAD_RPCSERVER]--;
3178 PrintException(NULL, "ThreadRPCServer()");
3180 printf("ThreadRPCServer exiting\n");
3183 void ThreadRPCServer2(void* parg)
3185 printf("ThreadRPCServer started\n");
3187 strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
3188 if (mapArgs["-rpcpassword"] == "")
3190 unsigned char rand_pwd[32];
3191 RAND_bytes(rand_pwd, 32);
3192 string strWhatAmI = "To use novacoind";
3193 if (mapArgs.count("-server"))
3194 strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
3195 else if (mapArgs.count("-daemon"))
3196 strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
3197 ThreadSafeMessageBox(strprintf(
3198 _("%s, you must set a rpcpassword in the configuration file:\n %s\n"
3199 "It is recommended you use the following random password:\n"
3202 "(you do not need to remember this password)\n"
3203 "If the file does not exist, create it with owner-readable-only file permissions.\n"),
3205 GetConfigFile().string().c_str(),
3206 EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str()),
3207 _("Error"), wxOK | wxMODAL);
3212 bool fUseSSL = GetBoolArg("-rpcssl");
3213 asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
3215 asio::io_service io_service;
3216 ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", RPC_PORT));
3217 ip::tcp::acceptor acceptor(io_service);
3220 acceptor.open(endpoint.protocol());
3221 acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
3222 acceptor.bind(endpoint);
3223 acceptor.listen(socket_base::max_connections);
3225 catch(boost::system::system_error &e)
3227 ThreadSafeMessageBox(strprintf(_("An error occured while setting up the RPC port %i for listening: %s"), endpoint.port(), e.what()),
3228 _("Error"), wxOK | wxMODAL);
3233 ssl::context context(io_service, ssl::context::sslv23);
3236 context.set_options(ssl::context::no_sslv2);
3238 filesystem::path pathCertFile(GetArg("-rpcsslcertificatechainfile", "server.cert"));
3239 if (!pathCertFile.is_complete()) pathCertFile = filesystem::path(GetDataDir()) / pathCertFile;
3240 if (filesystem::exists(pathCertFile)) context.use_certificate_chain_file(pathCertFile.string());
3241 else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", pathCertFile.string().c_str());
3243 filesystem::path pathPKFile(GetArg("-rpcsslprivatekeyfile", "server.pem"));
3244 if (!pathPKFile.is_complete()) pathPKFile = filesystem::path(GetDataDir()) / pathPKFile;
3245 if (filesystem::exists(pathPKFile)) context.use_private_key_file(pathPKFile.string(), ssl::context::pem);
3246 else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pathPKFile.string().c_str());
3248 string strCiphers = GetArg("-rpcsslciphers", "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
3249 SSL_CTX_set_cipher_list(context.impl(), strCiphers.c_str());
3254 // Accept connection
3255 SSLStream sslStream(io_service, context);
3256 SSLIOStreamDevice d(sslStream, fUseSSL);
3257 iostreams::stream<SSLIOStreamDevice> stream(d);
3259 ip::tcp::endpoint peer;
3260 vnThreadsRunning[THREAD_RPCSERVER]--;
3261 acceptor.accept(sslStream.lowest_layer(), peer);
3262 vnThreadsRunning[4]++;
3266 // Restrict callers by IP
3267 if (!ClientAllowed(peer.address().to_string()))
3269 // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
3271 stream << HTTPReply(403, "") << std::flush;
3275 map<string, string> mapHeaders;
3278 boost::thread api_caller(ReadHTTP, boost::ref(stream), boost::ref(mapHeaders), boost::ref(strRequest));
3279 if (!api_caller.timed_join(boost::posix_time::seconds(GetArg("-rpctimeout", 30))))
3282 printf("ThreadRPCServer ReadHTTP timeout\n");
3286 // Check authorization
3287 if (mapHeaders.count("authorization") == 0)
3289 stream << HTTPReply(401, "") << std::flush;
3292 if (!HTTPAuthorized(mapHeaders))
3294 printf("ThreadRPCServer incorrect password attempt from %s\n",peer.address().to_string().c_str());
3295 /* Deter brute-forcing short passwords.
3296 If this results in a DOS the user really
3297 shouldn't have their RPC port exposed.*/
3298 if (mapArgs["-rpcpassword"].size() < 20)
3301 stream << HTTPReply(401, "") << std::flush;
3305 Value id = Value::null;
3310 if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
3311 throw JSONRPCError(-32700, "Parse error");
3312 const Object& request = valRequest.get_obj();
3314 // Parse id now so errors from here on will have the id
3315 id = find_value(request, "id");
3318 Value valMethod = find_value(request, "method");
3319 if (valMethod.type() == null_type)
3320 throw JSONRPCError(-32600, "Missing method");
3321 if (valMethod.type() != str_type)
3322 throw JSONRPCError(-32600, "Method must be a string");
3323 string strMethod = valMethod.get_str();
3324 if (strMethod != "getwork" && strMethod != "getmemorypool")
3325 printf("ThreadRPCServer method=%s\n", strMethod.c_str());
3328 Value valParams = find_value(request, "params");
3330 if (valParams.type() == array_type)
3331 params = valParams.get_array();
3332 else if (valParams.type() == null_type)
3335 throw JSONRPCError(-32600, "Params must be an array");
3338 const CRPCCommand *pcmd = tableRPC[strMethod];
3340 throw JSONRPCError(-32601, "Method not found");
3342 // Observe safe mode
3343 string strWarning = GetWarnings("rpc");
3344 if (strWarning != "" && !GetBoolArg("-disablesafemode") &&
3346 throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
3353 LOCK2(cs_main, pwalletMain->cs_wallet);
3354 result = pcmd->actor(params, false);
3358 string strReply = JSONRPCReply(result, Value::null, id);
3359 stream << HTTPReply(200, strReply) << std::flush;
3361 catch (std::exception& e)
3363 ErrorReply(stream, JSONRPCError(-1, e.what()), id);
3366 catch (Object& objError)
3368 ErrorReply(stream, objError, id);
3370 catch (std::exception& e)
3372 ErrorReply(stream, JSONRPCError(-32700, e.what()), id);
3380 Object CallRPC(const string& strMethod, const Array& params)
3382 if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
3383 throw runtime_error(strprintf(
3384 _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
3385 "If the file does not exist, create it with owner-readable-only file permissions."),
3386 GetConfigFile().string().c_str()));
3388 // Connect to localhost
3389 bool fUseSSL = GetBoolArg("-rpcssl");
3390 asio::io_service io_service;
3391 ssl::context context(io_service, ssl::context::sslv23);
3392 context.set_options(ssl::context::no_sslv2);
3393 SSLStream sslStream(io_service, context);
3394 SSLIOStreamDevice d(sslStream, fUseSSL);
3395 iostreams::stream<SSLIOStreamDevice> stream(d);
3396 if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", CBigNum(RPC_PORT).ToString().c_str())))
3397 throw runtime_error("couldn't connect to server");
3399 // HTTP basic authentication
3400 string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
3401 map<string, string> mapRequestHeaders;
3402 mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
3405 string strRequest = JSONRPCRequest(strMethod, params, 1);
3406 string strPost = HTTPPost(strRequest, mapRequestHeaders);
3407 stream << strPost << std::flush;
3410 map<string, string> mapHeaders;
3412 int nStatus = ReadHTTP(stream, mapHeaders, strReply);
3414 throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
3415 else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
3416 throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
3417 else if (strReply.empty())
3418 throw runtime_error("no response from server");
3422 if (!read_string(strReply, valReply))
3423 throw runtime_error("couldn't parse reply from server");
3424 const Object& reply = valReply.get_obj();
3426 throw runtime_error("expected reply to have result, error and id properties");
3434 template<typename T>
3435 void ConvertTo(Value& value)
3437 if (value.type() == str_type)
3439 // reinterpret string as unquoted json value
3441 if (!read_string(value.get_str(), value2))
3442 throw runtime_error("type mismatch");
3443 value = value2.get_value<T>();
3447 value = value.get_value<T>();
3451 int CommandLineRPC(int argc, char *argv[])
3458 while (argc > 1 && IsSwitchChar(argv[1][0]))
3466 throw runtime_error("too few parameters");
3467 string strMethod = argv[1];
3469 // Parameters default to strings
3471 for (int i = 2; i < argc; i++)
3472 params.push_back(argv[i]);
3473 int n = params.size();
3476 // Special case non-string parameter types
3478 if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
3479 if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
3480 if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
3481 if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]);
3482 if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
3483 if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]);
3484 if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
3485 if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
3486 if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]);
3487 if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
3488 if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]);
3489 if (strMethod == "getblockhash" && n > 0) ConvertTo<boost::int64_t>(params[0]);
3490 if (strMethod == "getblockbynumber" && n > 0) ConvertTo<boost::int64_t>(params[0]);
3491 if (strMethod == "getblockbynumber" && n > 1) ConvertTo<bool>(params[1]);
3492 if (strMethod == "getblock" && n > 1) ConvertTo<bool>(params[1]);
3493 if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]);
3494 if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]);
3495 if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]);
3496 if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]);
3497 if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
3498 if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]);
3499 if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]);
3500 if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]);
3501 if (strMethod == "walletpassphrase" && n > 2) ConvertTo<bool>(params[2]);
3502 if (strMethod == "listsinceblock" && n > 1) ConvertTo<boost::int64_t>(params[1]);
3503 if (strMethod == "sendalert" && n > 2) ConvertTo<boost::int64_t>(params[2]);
3504 if (strMethod == "sendalert" && n > 3) ConvertTo<boost::int64_t>(params[3]);
3505 if (strMethod == "sendalert" && n > 4) ConvertTo<boost::int64_t>(params[4]);
3506 if (strMethod == "sendalert" && n > 5) ConvertTo<boost::int64_t>(params[5]);
3507 if (strMethod == "sendalert" && n > 6) ConvertTo<boost::int64_t>(params[6]);
3508 if (strMethod == "sendmany" && n > 1)
3510 string s = params[1].get_str();
3512 if (!read_string(s, v) || v.type() != obj_type)
3513 throw runtime_error("type mismatch");
3514 params[1] = v.get_obj();
3516 if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]);
3517 if (strMethod == "reservebalance" && n > 0) ConvertTo<bool>(params[0]);
3518 if (strMethod == "reservebalance" && n > 1) ConvertTo<double>(params[1]);
3519 if (strMethod == "addmultisigaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
3520 if (strMethod == "addmultisigaddress" && n > 1)
3522 string s = params[1].get_str();
3524 if (!read_string(s, v) || v.type() != array_type)
3525 throw runtime_error("type mismatch "+s);
3526 params[1] = v.get_array();
3530 Object reply = CallRPC(strMethod, params);
3533 const Value& result = find_value(reply, "result");
3534 const Value& error = find_value(reply, "error");
3536 if (error.type() != null_type)
3539 strPrint = "error: " + write_string(error, false);
3540 int code = find_value(error.get_obj(), "code").get_int();
3546 if (result.type() == null_type)
3548 else if (result.type() == str_type)
3549 strPrint = result.get_str();
3551 strPrint = write_string(result, true);
3554 catch (std::exception& e)
3556 strPrint = string("error: ") + e.what();
3561 PrintException(NULL, "CommandLineRPC()");
3566 fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
3575 int main(int argc, char *argv[])
3578 // Turn off microsoft heap dump noise
3579 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
3580 _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
3582 setbuf(stdin, NULL);
3583 setbuf(stdout, NULL);
3584 setbuf(stderr, NULL);
3588 if (argc >= 2 && string(argv[1]) == "-server")
3590 printf("server ready\n");
3591 ThreadRPCServer(NULL);
3595 return CommandLineRPC(argc, argv);
3598 catch (std::exception& e) {
3599 PrintException(&e, "main()");
3601 PrintException(NULL, "main()");
3607 const CRPCTable tableRPC;