From 639e46b4d7c6d9fcaab1a76433fb174364c84413 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 3 Oct 2018 16:15:03 +0100 Subject: [PATCH] Revert "Remove testnet-only difficulty rules" This reverts commit 333ea3c4266179da5d40e496ae60bcce0259c790. --- src/gtest/test_rpc.cpp | 27 +++++++++++++++++++++++++++ src/pow.cpp | 17 +++++++++++++++++ src/rpc/blockchain.cpp | 26 +++++++++++++++++--------- 3 files changed, 61 insertions(+), 9 deletions(-) diff --git a/src/gtest/test_rpc.cpp b/src/gtest/test_rpc.cpp index 3733379a8..ad80393f5 100644 --- a/src/gtest/test_rpc.cpp +++ b/src/gtest/test_rpc.cpp @@ -9,6 +9,33 @@ #include "streams.h" #include "utilstrencodings.h" +TEST(rpc, GetDifficultyTestnetRules) { + SelectParams(CBaseChainParams::TESTNET); + + CBlockIndex prev; + prev.nTime = 1472700000; + prev.nBits = 0x201fffff; + + CBlockIndex curr; + curr.pprev = &prev; + curr.nTime = 1472700300; + curr.nBits = 0x207fffff; + + // Time interval is within 5 minutes, so the min-difficulty block should be + // interpreted as a valid network difficulty. + EXPECT_EQ(1, GetDifficulty(&curr)); + EXPECT_EQ(1, GetNetworkDifficulty(&curr)); + + curr.nTime += 1; + + // Time interval is over 5 minutes, so the min-difficulty block should be + // ignored for network difficulty determination. + EXPECT_EQ(1, GetDifficulty(&curr)); + // We have to check this directly, because of some combination of rounding + // and truncation issues that result in Google Test displaying 4 != 4 + EXPECT_EQ((double)0x7fffff/(double)0x1fffff, GetNetworkDifficulty(&curr)); +} + extern UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false); TEST(rpc, check_blockToJSON_returns_minified_solution) { diff --git a/src/pow.cpp b/src/pow.cpp index 18873d4ee..0eb81414a 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -24,6 +24,23 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead if (pindexLast == NULL) return nProofOfWorkLimit; + const CBlockIndex* pindexBits = pindexLast; + { + if (params.fPowAllowMinDifficultyBlocks) + { + // Special difficulty rule for testnet: + // If the new block's timestamp is more than 2* 2.5 minutes + // then allow mining of a min-difficulty block. + if (pblock->GetBlockTime() > pindexLast->GetBlockTime() + params.nPowTargetSpacing*2) + return nProofOfWorkLimit; + else { + // Get the last non-min-difficulty (or at worst the genesis difficulty) + while (pindexBits->pprev && pindexBits->nBits == nProofOfWorkLimit) + pindexBits = pindexBits->pprev; + } + } + } + // Find the first block in the averaging interval const CBlockIndex* pindexFirst = pindexLast; arith_uint256 bnTot {0}; diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 9a9b0fd57..c7afe7af8 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -38,21 +38,29 @@ double GetDifficultyINTERNAL(const CBlockIndex* blockindex, bool networkDifficul blockindex = chainActive.Tip(); } - uint32_t bits; - if (networkDifficulty) { - bits = GetNextWorkRequired(blockindex, nullptr, Params().GetConsensus()); - } else { - bits = blockindex->nBits; - } - uint32_t powLimit = UintToArith256(Params().GetConsensus().powLimit).GetCompact(); - int nShift = (bits >> 24) & 0xff; + { + 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 = (double)(powLimit & 0x00ffffff) / - (double)(bits & 0x00ffffff); + (double)(blockindex->nBits & 0x00ffffff); while (nShift < nShiftAmount) {