diff options
Diffstat (limited to 'src/rpcmining.cpp')
| -rw-r--r-- | src/rpcmining.cpp | 488 |
1 files changed, 331 insertions, 157 deletions
diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index e4a5bc416..c8649ec27 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -1,36 +1,40 @@ // Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2009-2013 The Bitcoin developers -// Distributed under the MIT/X11 software license, see the accompanying +// Copyright (c) 2009-2014 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "rpcserver.h" +#include "amount.h" +#include "chain.h" #include "chainparams.h" +#include "consensus/consensus.h" +#include "consensus/validation.h" +#include "core_io.h" #include "init.h" -#include "net.h" #include "main.h" #include "miner.h" +#include "net.h" #include "pow.h" -#include "core_io.h" +#include "rpcserver.h" +#include "txmempool.h" #include "util.h" -#ifdef ENABLE_WALLET -#include "db.h" -#include "wallet.h" -#endif +#include "utilstrencodings.h" +#include "validationinterface.h" #include <stdint.h> #include <boost/assign/list_of.hpp> +#include <boost/shared_ptr.hpp> -#include "json/json_spirit_utils.h" -#include "json/json_spirit_value.h" +#include <univalue.h> -using namespace json_spirit; using namespace std; -// Return average network hashes per second based on the last 'lookup' blocks, -// or from the last difficulty change if 'lookup' is nonpositive. -// If 'height' is nonnegative, compute the estimate at the time when a given block was found. -Value GetNetworkHashPS(int lookup, int height) { +/** + * Return average network hashes per second based on the last 'lookup' blocks, + * or from the last difficulty change if 'lookup' is nonpositive. + * If 'height' is nonnegative, compute the estimate at the time when a given block was found. + */ +UniValue GetNetworkHashPS(int lookup, int height) { CBlockIndex *pb = chainActive.Tip(); if (height >= 0 && height < chainActive.Height()) @@ -41,7 +45,7 @@ Value GetNetworkHashPS(int lookup, int height) { // If lookup is -1, then use blocks since last difficulty change. if (lookup <= 0) - lookup = pb->nHeight % 2016 + 1; + lookup = pb->nHeight % Params().GetConsensus().DifficultyAdjustmentInterval() + 1; // If lookup is larger than chain, then set it to chain length. if (lookup > pb->nHeight) @@ -61,13 +65,13 @@ Value GetNetworkHashPS(int lookup, int height) { if (minTime == maxTime) return 0; - uint256 workDiff = pb->nChainWork - pb0->nChainWork; + arith_uint256 workDiff = pb->nChainWork - pb0->nChainWork; int64_t timeDiff = maxTime - minTime; return (int64_t)(workDiff.getdouble() / timeDiff); } -Value getnetworkhashps(const Array& params, bool fHelp) +UniValue getnetworkhashps(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 2) throw runtime_error( @@ -85,17 +89,17 @@ Value getnetworkhashps(const Array& params, bool fHelp) + HelpExampleRpc("getnetworkhashps", "") ); + LOCK(cs_main); return GetNetworkHashPS(params.size() > 0 ? params[0].get_int() : 120, params.size() > 1 ? params[1].get_int() : -1); } -#ifdef ENABLE_WALLET -Value getgenerate(const Array& params, bool fHelp) +UniValue getgenerate(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( "getgenerate\n" "\nReturn if the server is set to generate coins or not. The default is false.\n" - "It is set with the command line argument -gen (or bitcoin.conf setting gen)\n" + "It is set with the command line argument -gen (or " + std::string(BITCOIN_CONF_FILENAME) + " setting gen)\n" "It can also be set with the setgenerate call.\n" "\nResult\n" "true|false (boolean) If the server is set to generate coins or not\n" @@ -104,11 +108,81 @@ Value getgenerate(const Array& params, bool fHelp) + HelpExampleRpc("getgenerate", "") ); - return GetBoolArg("-gen", false); + LOCK(cs_main); + return GetBoolArg("-gen", DEFAULT_GENERATE); } +UniValue generate(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 1) + throw runtime_error( + "generate numblocks\n" + "\nMine blocks immediately (before the RPC call returns)\n" + "\nNote: this function can only be used on the regtest network\n" + "\nArguments:\n" + "1. numblocks (numeric, required) How many blocks are generated immediately.\n" + "\nResult\n" + "[ blockhashes ] (array) hashes of blocks generated\n" + "\nExamples:\n" + "\nGenerate 11 blocks\n" + + HelpExampleCli("generate", "11") + ); + + if (!Params().MineBlocksOnDemand()) + throw JSONRPCError(RPC_METHOD_NOT_FOUND, "This method can only be used on regtest"); + + int nHeightStart = 0; + int nHeightEnd = 0; + int nHeight = 0; + int nGenerate = params[0].get_int(); + + boost::shared_ptr<CReserveScript> coinbaseScript; + GetMainSignals().ScriptForMining(coinbaseScript); -Value setgenerate(const Array& params, bool fHelp) + // If the keypool is exhausted, no script is returned at all. Catch this. + if (!coinbaseScript) + throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first"); + + //throw an error if no script was provided + if (coinbaseScript->reserveScript.empty()) + throw JSONRPCError(RPC_INTERNAL_ERROR, "No coinbase script available (mining requires a wallet)"); + + { // Don't keep cs_main locked + LOCK(cs_main); + nHeightStart = chainActive.Height(); + nHeight = nHeightStart; + nHeightEnd = nHeightStart+nGenerate; + } + unsigned int nExtraNonce = 0; + UniValue blockHashes(UniValue::VARR); + while (nHeight < nHeightEnd) + { + auto_ptr<CBlockTemplate> pblocktemplate(CreateNewBlock(Params(), coinbaseScript->reserveScript)); + if (!pblocktemplate.get()) + throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block"); + CBlock *pblock = &pblocktemplate->block; + { + LOCK(cs_main); + IncrementExtraNonce(pblock, chainActive.Tip(), nExtraNonce); + } + while (!CheckProofOfWork(pblock->GetHash(), pblock->nBits, Params().GetConsensus())) { + // Yes, there is a chance every nonce could fail to satisfy the -regtest + // target -- 1 in 2^(2^32). That ain't gonna happen. + ++pblock->nNonce; + } + CValidationState state; + if (!ProcessNewBlock(state, Params(), NULL, pblock, true, NULL)) + throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted"); + ++nHeight; + blockHashes.push_back(pblock->GetHash().GetHex()); + + //mark script as important because it was used at least for one coinbase output + coinbaseScript->KeepScript(); + } + return blockHashes; +} + +UniValue setgenerate(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 2) throw runtime_error( @@ -119,7 +193,6 @@ Value setgenerate(const Array& params, bool fHelp) "\nArguments:\n" "1. generate (boolean, required) Set to true to turn on generation, off to turn off.\n" "2. genproclimit (numeric, optional) Set the processor limit for when generation is on. Can be -1 for unlimited.\n" - " Note: in -regtest mode, genproclimit controls how many blocks are generated immediately.\n" "\nExamples:\n" "\nSet the generation on with a limit of one processor\n" + HelpExampleCli("setgenerate", "true 1") + @@ -131,14 +204,14 @@ Value setgenerate(const Array& params, bool fHelp) + HelpExampleRpc("setgenerate", "true, 1") ); - if (pwalletMain == NULL) - throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found (disabled)"); + if (Params().MineBlocksOnDemand()) + throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Use the generate method instead of setgenerate on this network"); bool fGenerate = true; if (params.size() > 0) fGenerate = params[0].get_bool(); - int nGenProcLimit = -1; + int nGenProcLimit = GetArg("-genproclimit", DEFAULT_GENERATE_THREADS); if (params.size() > 1) { nGenProcLimit = params[1].get_int(); @@ -146,66 +219,14 @@ Value setgenerate(const Array& params, bool fHelp) fGenerate = false; } - // -regtest mode: don't return until nGenProcLimit blocks are generated - if (fGenerate && Params().MineBlocksOnDemand()) - { - int nHeightStart = 0; - int nHeightEnd = 0; - int nHeight = 0; - int nGenerate = (nGenProcLimit > 0 ? nGenProcLimit : 1); - { // Don't keep cs_main locked - LOCK(cs_main); - nHeightStart = chainActive.Height(); - nHeight = nHeightStart; - nHeightEnd = nHeightStart+nGenerate; - } - int nHeightLast = -1; - while (nHeight < nHeightEnd) - { - if (nHeightLast != nHeight) - { - nHeightLast = nHeight; - GenerateBitcoins(fGenerate, pwalletMain, 1); - } - MilliSleep(1); - { // Don't keep cs_main locked - LOCK(cs_main); - nHeight = chainActive.Height(); - } - } - } - else // Not -regtest: start generate thread, return immediately - { - mapArgs["-gen"] = (fGenerate ? "1" : "0"); - mapArgs ["-genproclimit"] = itostr(nGenProcLimit); - GenerateBitcoins(fGenerate, pwalletMain, nGenProcLimit); - } - - return Value::null; -} + mapArgs["-gen"] = (fGenerate ? "1" : "0"); + mapArgs ["-genproclimit"] = itostr(nGenProcLimit); + GenerateBitcoins(fGenerate, nGenProcLimit, Params()); -Value gethashespersec(const Array& params, bool fHelp) -{ - if (fHelp || params.size() != 0) - throw runtime_error( - "gethashespersec\n" - "\nReturns a recent hashes per second performance measurement while generating.\n" - "See the getgenerate and setgenerate calls to turn generation on and off.\n" - "\nResult:\n" - "n (numeric) The recent hashes per second when generation is on (will return 0 if generation is off)\n" - "\nExamples:\n" - + HelpExampleCli("gethashespersec", "") - + HelpExampleRpc("gethashespersec", "") - ); - - if (GetTimeMillis() - nHPSTimerStart > 8000) - return (int64_t)0; - return (int64_t)dHashesPerSec; + return NullUniValue; } -#endif - -Value getmininginfo(const Array& params, bool fHelp) +UniValue getmininginfo(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( @@ -220,7 +241,6 @@ Value getmininginfo(const Array& params, bool fHelp) " \"errors\": \"...\" (string) Current errors\n" " \"generate\": true|false (boolean) If the generation is on or off (see getgenerate or setgenerate calls)\n" " \"genproclimit\": n (numeric) The processor limit for generation. -1 if no generation. (see getgenerate or setgenerate calls)\n" - " \"hashespersec\": n (numeric) The hashes per second of the generation, or 0 if no generation.\n" " \"pooledtx\": n (numeric) The size of the mem pool\n" " \"testnet\": true|false (boolean) If using testnet or not\n" " \"chain\": \"xxxx\", (string) current network name as defined in BIP70 (main, test, regtest)\n" @@ -230,26 +250,27 @@ Value getmininginfo(const Array& params, bool fHelp) + HelpExampleRpc("getmininginfo", "") ); - Object obj; + + LOCK(cs_main); + + UniValue obj(UniValue::VOBJ); obj.push_back(Pair("blocks", (int)chainActive.Height())); obj.push_back(Pair("currentblocksize", (uint64_t)nLastBlockSize)); obj.push_back(Pair("currentblocktx", (uint64_t)nLastBlockTx)); obj.push_back(Pair("difficulty", (double)GetDifficulty())); obj.push_back(Pair("errors", GetWarnings("statusbar"))); - obj.push_back(Pair("genproclimit", (int)GetArg("-genproclimit", -1))); + obj.push_back(Pair("genproclimit", (int)GetArg("-genproclimit", DEFAULT_GENERATE_THREADS))); obj.push_back(Pair("networkhashps", getnetworkhashps(params, false))); obj.push_back(Pair("pooledtx", (uint64_t)mempool.size())); - obj.push_back(Pair("testnet", Params().NetworkID() == CBaseChainParams::TESTNET)); + obj.push_back(Pair("testnet", Params().TestnetToBeDeprecatedFieldRPC())); obj.push_back(Pair("chain", Params().NetworkIDString())); -#ifdef ENABLE_WALLET obj.push_back(Pair("generate", getgenerate(params, false))); - obj.push_back(Pair("hashespersec", gethashespersec(params, false))); -#endif return obj; } -Value prioritisetransaction(const Array& params, bool fHelp) +// NOTE: Unlike wallet RPC (which use BTC values), mining RPCs follow GBT (BIP 22) in using satoshi amounts +UniValue prioritisetransaction(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 3) throw runtime_error( @@ -260,29 +281,46 @@ Value prioritisetransaction(const Array& params, bool fHelp) "2. priority delta (numeric, required) The priority to add or subtract.\n" " The transaction selection algorithm considers the tx as it would have a higher priority.\n" " (priority of a transaction is calculated: coinage * value_in_satoshis / txsize) \n" - "3. fee delta (numeric, required) The absolute fee value to add or subtract in bitcoin.\n" + "3. fee delta (numeric, required) The fee value (in satoshis) to add (or subtract, if negative).\n" " The fee is not actually paid, only the algorithm for selecting transactions into a block\n" " considers the transaction as it would have paid a higher (or lower) fee.\n" "\nResult\n" "true (boolean) Returns true\n" "\nExamples:\n" - + HelpExampleCli("prioritisetransaction", "\"txid\" 0.0 0.00010000") - + HelpExampleRpc("prioritisetransaction", "\"txid\", 0.0, 0.00010000") + + HelpExampleCli("prioritisetransaction", "\"txid\" 0.0 10000") + + HelpExampleRpc("prioritisetransaction", "\"txid\", 0.0, 10000") ); - uint256 hash; - hash.SetHex(params[0].get_str()); + LOCK(cs_main); - int64_t nAmount = 0; - if (params[2].get_real() != 0.0) - nAmount = AmountFromValue(params[2]); + uint256 hash = ParseHashStr(params[0].get_str(), "txid"); + CAmount nAmount = params[2].get_int64(); mempool.PrioritiseTransaction(hash, params[0].get_str(), params[1].get_real(), nAmount); return true; } -Value getblocktemplate(const Array& params, bool fHelp) +// NOTE: Assumes a conclusive result; if result is inconclusive, it must be handled by caller +static UniValue BIP22ValidationResult(const CValidationState& state) +{ + if (state.IsValid()) + return NullUniValue; + + std::string strRejectReason = state.GetRejectReason(); + if (state.IsError()) + throw JSONRPCError(RPC_VERIFY_ERROR, strRejectReason); + if (state.IsInvalid()) + { + if (strRejectReason.empty()) + return "rejected"; + return strRejectReason; + } + // Should be impossible + return "valid?"; +} + +UniValue getblocktemplate(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 1) throw runtime_error( @@ -344,21 +382,53 @@ Value getblocktemplate(const Array& params, bool fHelp) + HelpExampleRpc("getblocktemplate", "") ); + LOCK(cs_main); + std::string strMode = "template"; - Value lpval = Value::null; + UniValue lpval = NullUniValue; if (params.size() > 0) { - const Object& oparam = params[0].get_obj(); - const Value& modeval = find_value(oparam, "mode"); - if (modeval.type() == str_type) + const UniValue& oparam = params[0].get_obj(); + const UniValue& modeval = find_value(oparam, "mode"); + if (modeval.isStr()) strMode = modeval.get_str(); - else if (modeval.type() == null_type) + else if (modeval.isNull()) { /* Do nothing */ } else throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid mode"); lpval = find_value(oparam, "longpollid"); + + if (strMode == "proposal") + { + const UniValue& dataval = find_value(oparam, "data"); + if (!dataval.isStr()) + throw JSONRPCError(RPC_TYPE_ERROR, "Missing data String key for proposal"); + + CBlock block; + if (!DecodeHexBlk(block, dataval.get_str())) + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block decode failed"); + + uint256 hash = block.GetHash(); + BlockMap::iterator mi = mapBlockIndex.find(hash); + if (mi != mapBlockIndex.end()) { + CBlockIndex *pindex = mi->second; + if (pindex->IsValid(BLOCK_VALID_SCRIPTS)) + return "duplicate"; + if (pindex->nStatus & BLOCK_FAILED_MASK) + return "duplicate-invalid"; + return "duplicate-inconclusive"; + } + + CBlockIndex* const pindexPrev = chainActive.Tip(); + // TestBlockValidity only supports blocks built on the current Tip + if (block.hashPrevBlock != pindexPrev->GetBlockHash()) + return "inconclusive-not-best-prevblk"; + CValidationState state; + TestBlockValidity(state, Params(), block, pindexPrev, false, true); + return BIP22ValidationResult(state); + } } if (strMode != "template") @@ -372,14 +442,14 @@ Value getblocktemplate(const Array& params, bool fHelp) static unsigned int nTransactionsUpdatedLast; - if (lpval.type() != null_type) + if (!lpval.isNull()) { // Wait to respond until either the best block changes, OR a minute has passed and there are more transactions uint256 hashWatchedChain; boost::system_time checktxtime; unsigned int nTransactionsUpdatedLastLP; - if (lpval.type() == str_type) + if (lpval.isStr()) { // Format: <hashBestChain><nTransactionsUpdatedLast> std::string lpstr = lpval.get_str(); @@ -395,10 +465,6 @@ Value getblocktemplate(const Array& params, bool fHelp) } // Release the wallet and main lock while waiting -#ifdef ENABLE_WALLET - if(pwalletMain) - LEAVE_CRITICAL_SECTION(pwalletMain->cs_wallet); -#endif LEAVE_CRITICAL_SECTION(cs_main); { checktxtime = boost::get_system_time() + boost::posix_time::minutes(1); @@ -416,10 +482,6 @@ Value getblocktemplate(const Array& params, bool fHelp) } } ENTER_CRITICAL_SECTION(cs_main); -#ifdef ENABLE_WALLET - if(pwalletMain) - ENTER_CRITICAL_SECTION(pwalletMain->cs_wallet); -#endif if (!IsRPCRunning()) throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "Shutting down"); @@ -448,7 +510,7 @@ Value getblocktemplate(const Array& params, bool fHelp) pblocktemplate = NULL; } CScript scriptDummy = CScript() << OP_TRUE; - pblocktemplate = CreateNewBlock(scriptDummy); + pblocktemplate = CreateNewBlock(Params(), scriptDummy); if (!pblocktemplate) throw JSONRPCError(RPC_OUT_OF_MEMORY, "Out of memory"); @@ -458,27 +520,28 @@ Value getblocktemplate(const Array& params, bool fHelp) CBlock* pblock = &pblocktemplate->block; // pointer for convenience // Update nTime - UpdateTime(pblock, pindexPrev); + UpdateTime(pblock, Params().GetConsensus(), pindexPrev); pblock->nNonce = 0; - Array transactions; + UniValue aCaps(UniValue::VARR); aCaps.push_back("proposal"); + + UniValue transactions(UniValue::VARR); map<uint256, int64_t> setTxIndex; int i = 0; - BOOST_FOREACH (CTransaction& tx, pblock->vtx) - { + BOOST_FOREACH (const CTransaction& tx, pblock->vtx) { uint256 txHash = tx.GetHash(); setTxIndex[txHash] = i++; if (tx.IsCoinBase()) continue; - Object entry; + UniValue entry(UniValue::VOBJ); entry.push_back(Pair("data", EncodeHexTx(tx))); entry.push_back(Pair("hash", txHash.GetHex())); - Array deps; + UniValue deps(UniValue::VARR); BOOST_FOREACH (const CTxIn &in, tx.vin) { if (setTxIndex.count(in.prevout.hash)) @@ -493,12 +556,12 @@ Value getblocktemplate(const Array& params, bool fHelp) transactions.push_back(entry); } - Object aux; + UniValue aux(UniValue::VOBJ); aux.push_back(Pair("flags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end()))); - uint256 hashTarget = uint256().SetCompact(pblock->nBits); + arith_uint256 hashTarget = arith_uint256().SetCompact(pblock->nBits); - static Array aMutable; + static UniValue aMutable(UniValue::VARR); if (aMutable.empty()) { aMutable.push_back("time"); @@ -506,7 +569,8 @@ Value getblocktemplate(const Array& params, bool fHelp) aMutable.push_back("prevblock"); } - Object result; + UniValue result(UniValue::VOBJ); + result.push_back(Pair("capabilities", aCaps)); result.push_back(Pair("version", pblock->nVersion)); result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex())); result.push_back(Pair("transactions", transactions)); @@ -526,7 +590,25 @@ Value getblocktemplate(const Array& params, bool fHelp) return result; } -Value submitblock(const Array& params, bool fHelp) +class submitblock_StateCatcher : public CValidationInterface +{ +public: + uint256 hash; + bool found; + CValidationState state; + + submitblock_StateCatcher(const uint256 &hashIn) : hash(hashIn), found(false), state() {}; + +protected: + virtual void BlockChecked(const CBlock& block, const CValidationState& stateIn) { + if (block.GetHash() != hash) + return; + found = true; + state = stateIn; + }; +}; + +UniValue submitblock(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 2) throw runtime_error( @@ -547,44 +629,65 @@ Value submitblock(const Array& params, bool fHelp) + HelpExampleRpc("submitblock", "\"mydata\"") ); - vector<unsigned char> blockData(ParseHex(params[0].get_str())); - CDataStream ssBlock(blockData, SER_NETWORK, PROTOCOL_VERSION); - CBlock pblock; - try { - ssBlock >> pblock; - } - catch (std::exception &e) { + CBlock block; + if (!DecodeHexBlk(block, params[0].get_str())) throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block decode failed"); + + uint256 hash = block.GetHash(); + bool fBlockPresent = false; + { + LOCK(cs_main); + BlockMap::iterator mi = mapBlockIndex.find(hash); + if (mi != mapBlockIndex.end()) { + CBlockIndex *pindex = mi->second; + if (pindex->IsValid(BLOCK_VALID_SCRIPTS)) + return "duplicate"; + if (pindex->nStatus & BLOCK_FAILED_MASK) + return "duplicate-invalid"; + // Otherwise, we might only have the header - process the block before returning + fBlockPresent = true; + } } CValidationState state; - bool fAccepted = ProcessBlock(state, NULL, &pblock); - if (!fAccepted) - return "rejected"; // TODO: report validation state - - return Value::null; + submitblock_StateCatcher sc(block.GetHash()); + RegisterValidationInterface(&sc); + bool fAccepted = ProcessNewBlock(state, Params(), NULL, &block, true, NULL); + UnregisterValidationInterface(&sc); + if (fBlockPresent) + { + if (fAccepted && !sc.found) + return "duplicate-inconclusive"; + return "duplicate"; + } + if (fAccepted) + { + if (!sc.found) + return "inconclusive"; + state = sc.state; + } + return BIP22ValidationResult(state); } -Value estimatefee(const Array& params, bool fHelp) +UniValue estimatefee(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) throw runtime_error( "estimatefee nblocks\n" - "\nEstimates the approximate fee per kilobyte\n" - "needed for a transaction to get confirmed\n" - "within nblocks blocks.\n" + "\nEstimates the approximate fee per kilobyte needed for a transaction to begin\n" + "confirmation within nblocks blocks.\n" "\nArguments:\n" "1. nblocks (numeric)\n" "\nResult:\n" - "n : (numeric) estimated fee-per-kilobyte\n" + "n (numeric) estimated fee-per-kilobyte\n" "\n" - "-1.0 is returned if not enough transactions and\n" - "blocks have been observed to make an estimate.\n" + "A negative value is returned if not enough transactions and blocks\n" + "have been observed to make an estimate.\n" "\nExample:\n" + HelpExampleCli("estimatefee", "6") ); - RPCTypeCheck(params, boost::assign::list_of(int_type)); + RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM)); int nBlocks = params[0].get_int(); if (nBlocks < 1) @@ -597,26 +700,25 @@ Value estimatefee(const Array& params, bool fHelp) return ValueFromAmount(feeRate.GetFeePerK()); } -Value estimatepriority(const Array& params, bool fHelp) +UniValue estimatepriority(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) throw runtime_error( "estimatepriority nblocks\n" - "\nEstimates the approximate priority\n" - "a zero-fee transaction needs to get confirmed\n" - "within nblocks blocks.\n" + "\nEstimates the approximate priority a zero-fee transaction needs to begin\n" + "confirmation within nblocks blocks.\n" "\nArguments:\n" "1. nblocks (numeric)\n" "\nResult:\n" - "n : (numeric) estimated priority\n" + "n (numeric) estimated priority\n" "\n" - "-1.0 is returned if not enough transactions and\n" - "blocks have been observed to make an estimate.\n" + "A negative value is returned if not enough transactions and blocks\n" + "have been observed to make an estimate.\n" "\nExample:\n" + HelpExampleCli("estimatepriority", "6") ); - RPCTypeCheck(params, boost::assign::list_of(int_type)); + RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM)); int nBlocks = params[0].get_int(); if (nBlocks < 1) @@ -624,3 +726,75 @@ Value estimatepriority(const Array& params, bool fHelp) return mempool.estimatePriority(nBlocks); } + +UniValue estimatesmartfee(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "estimatesmartfee nblocks\n" + "\nWARNING: This interface is unstable and may disappear or change!\n" + "\nEstimates the approximate fee per kilobyte needed for a transaction to begin\n" + "confirmation within nblocks blocks if possible and return the number of blocks\n" + "for which the estimate is valid.\n" + "\nArguments:\n" + "1. nblocks (numeric)\n" + "\nResult:\n" + "{\n" + " \"feerate\" : x.x, (numeric) estimate fee-per-kilobyte (in BTC)\n" + " \"blocks\" : n (numeric) block number where estimate was found\n" + "}\n" + "\n" + "A negative value is returned if not enough transactions and blocks\n" + "have been observed to make an estimate for any number of blocks.\n" + "However it will not return a value below the mempool reject fee.\n" + "\nExample:\n" + + HelpExampleCli("estimatesmartfee", "6") + ); + + RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM)); + + int nBlocks = params[0].get_int(); + + UniValue result(UniValue::VOBJ); + int answerFound; + CFeeRate feeRate = mempool.estimateSmartFee(nBlocks, &answerFound); + result.push_back(Pair("feerate", feeRate == CFeeRate(0) ? -1.0 : ValueFromAmount(feeRate.GetFeePerK()))); + result.push_back(Pair("blocks", answerFound)); + return result; +} + +UniValue estimatesmartpriority(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "estimatesmartpriority nblocks\n" + "\nWARNING: This interface is unstable and may disappear or change!\n" + "\nEstimates the approximate priority a zero-fee transaction needs to begin\n" + "confirmation within nblocks blocks if possible and return the number of blocks\n" + "for which the estimate is valid.\n" + "\nArguments:\n" + "1. nblocks (numeric)\n" + "\nResult:\n" + "{\n" + " \"priority\" : x.x, (numeric) estimated priority\n" + " \"blocks\" : n (numeric) block number where estimate was found\n" + "}\n" + "\n" + "A negative value is returned if not enough transactions and blocks\n" + "have been observed to make an estimate for any number of blocks.\n" + "However if the mempool reject fee is set it will return 1e9 * MAX_MONEY.\n" + "\nExample:\n" + + HelpExampleCli("estimatesmartpriority", "6") + ); + + RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM)); + + int nBlocks = params[0].get_int(); + + UniValue result(UniValue::VOBJ); + int answerFound; + double priority = mempool.estimateSmartPriority(nBlocks, &answerFound); + result.push_back(Pair("priority", priority)); + result.push_back(Pair("blocks", answerFound)); + return result; +} |