aboutsummaryrefslogtreecommitdiff
path: root/src/rpcmining.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/rpcmining.cpp')
-rw-r--r--src/rpcmining.cpp488
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;
+}