From 695a7a88263198e6df23161305cb506d7c29ad4f Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Fri, 26 Aug 2016 18:42:18 +1200 Subject: [PATCH] Separate concepts of block difficulty and network difficulty in RPC "Block difficulty" is the difficulty listed in a block's header, which in the testnet can sometimes be min-difficulty (if time-since-last-block is too large). "Network difficulty" is the difficulty that the network was trying to satisfy at a particular block height. In mainnet this is always equal to the difficulty of the solved block for that height, but in testnet the network difficulty is derived from the last non-min-difficulty block difficulty. This commit fixes the RPC APIs that are intended to show network difficulty, so that on testnet they don't sometimes drop to 1.0, confusing users. Closes #1181 --- src/rpcblockchain.cpp | 33 +++++++++++++++++++++++++++++---- src/rpcmining.cpp | 2 +- src/rpcserver.h | 1 + 3 files changed, 31 insertions(+), 5 deletions(-) diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 20c669d5c..44e30c623 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -21,7 +21,7 @@ using namespace std; extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry); void ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out, bool fIncludeHex); -double GetDifficulty(const CBlockIndex* blockindex) +double GetDifficultyINTERNAL(const CBlockIndex* blockindex, bool networkDifficulty) { // Floating point number that is a multiple of the minimum difficulty, // minimum difficulty = 1.0. @@ -33,9 +33,24 @@ double GetDifficulty(const CBlockIndex* blockindex) blockindex = chainActive.Tip(); } - int nShift = (blockindex->nBits >> 24) & 0xff; uint32_t powLimit = UintToArith256(Params().GetConsensus().powLimit).GetCompact();; + { + if (networkDifficulty && Params().GetConsensus().fPowAllowMinDifficultyBlocks) + { + // Special difficulty rule for testnet: + // If a block's timestamp is more than 2*nPowTargetSpacing minutes after + // the previous block, then it is permitted to be min-difficulty. So + // get the last non-min-difficulty (or at worst the genesis difficulty). + auto window = Params().GetConsensus().nPowTargetSpacing*2; + while (blockindex->pprev && blockindex->nBits == powLimit && + blockindex->GetBlockTime() > blockindex->pprev->GetBlockTime() + window) { + blockindex = blockindex->pprev; + } + } + } + + int nShift = (blockindex->nBits >> 24) & 0xff; int nShiftAmount = (powLimit >> 24) & 0xff; double dDiff = @@ -56,6 +71,16 @@ double GetDifficulty(const CBlockIndex* blockindex) return dDiff; } +double GetDifficulty(const CBlockIndex* blockindex) +{ + return GetDifficultyINTERNAL(blockindex, false); +} + +double GetNetworkDifficulty(const CBlockIndex* blockindex) +{ + return GetDifficultyINTERNAL(blockindex, true); +} + Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false) { @@ -147,7 +172,7 @@ Value getdifficulty(const Array& params, bool fHelp) ); LOCK(cs_main); - return GetDifficulty(); + return GetNetworkDifficulty(); } @@ -542,7 +567,7 @@ Value getblockchaininfo(const Array& params, bool fHelp) obj.push_back(Pair("blocks", (int)chainActive.Height())); obj.push_back(Pair("headers", pindexBestHeader ? pindexBestHeader->nHeight : -1)); obj.push_back(Pair("bestblockhash", chainActive.Tip()->GetBlockHash().GetHex())); - obj.push_back(Pair("difficulty", (double)GetDifficulty())); + obj.push_back(Pair("difficulty", (double)GetNetworkDifficulty())); obj.push_back(Pair("verificationprogress", Checkpoints::GuessVerificationProgress(Params().Checkpoints(), chainActive.Tip()))); obj.push_back(Pair("chainwork", chainActive.Tip()->nChainWork.GetHex())); obj.push_back(Pair("pruned", fPruneMode)); diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index 6e865cc56..70e3787bd 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -286,7 +286,7 @@ Value getmininginfo(const Array& params, bool fHelp) 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("difficulty", (double)GetNetworkDifficulty())); obj.push_back(Pair("errors", GetWarnings("statusbar"))); obj.push_back(Pair("genproclimit", (int)GetArg("-genproclimit", -1))); obj.push_back(Pair("networkhashps", getnetworkhashps(params, false))); diff --git a/src/rpcserver.h b/src/rpcserver.h index 0e8b60b7b..5828dd489 100644 --- a/src/rpcserver.h +++ b/src/rpcserver.h @@ -140,6 +140,7 @@ extern int64_t nWalletUnlockTime; extern CAmount AmountFromValue(const json_spirit::Value& value); extern json_spirit::Value ValueFromAmount(const CAmount& amount); extern double GetDifficulty(const CBlockIndex* blockindex = NULL); +extern double GetNetworkDifficulty(const CBlockIndex* blockindex = NULL); extern std::string HelpRequiringPassphrase(); extern std::string HelpExampleCli(std::string methodname, std::string args); extern std::string HelpExampleRpc(std::string methodname, std::string args);