diff --git a/src/pow.cpp b/src/pow.cpp --- a/src/pow.cpp +++ b/src/pow.cpp @@ -59,6 +59,24 @@ nBits = pindexPrev->nBits; } + arith_uint256 nTarget; + nTarget.SetCompact(nBits); + + // Long-term block production time stabiliser that should rarely + // trigger. Should miners produce blocks considerably faster than + // target spacing but collude to fudge timestamps to stay above the 30 + // minute window, ensure difficulty will rise to compensate anyway. + if (nHeight > 2016) { + const CBlockIndex *p2016 = pindexPrev->GetAncestor(nHeight - 2017); + int64_t t = pindexPrev->GetBlockTime() - p2016->GetBlockTime(); + + // If too fast, increase the target by 1/256. Std deviation over + // 2016 blocks is 2.2%. + if (t < params.nPowTargetSpacing * 2016 * 95 / 100) { + nTarget -= (nTarget >> 8); + } + } + // Determine the MTP difference - the difference between the MTP // of the previous block, and the block 6 blocks earlier const CBlockIndex *pindex6 = pindexPrev->GetAncestor(nHeight - 7); @@ -68,25 +86,17 @@ // If too fast (< 30 mins), increase the target by 1/256. if (mtp6blocks < params.nPowTargetSpacing * 30 / 10) { - arith_uint256 nTarget; - nTarget.SetCompact(nBits); nTarget -= (nTarget >> 8); - return nTarget.GetCompact(); } - // If too slow (> 128 mins), decrease the target by 1/64. - if (mtp6blocks > params.nPowTargetSpacing * 128 / 10) { - arith_uint256 nTarget; - nTarget.SetCompact(nBits); + else if (mtp6blocks > params.nPowTargetSpacing * 128 / 10) { nTarget += (nTarget >> 6); - nBits = nTarget.GetCompact(); - // We can't go below the minimum target - if (nBits > nProofOfWorkLimit) nBits = nProofOfWorkLimit; - return nBits; } - // Otherwise difficulty is unchanged - return nBits; + nBits = nTarget.GetCompact(); + + // We can't go below the minimum target + return std::min(nBits, nProofOfWorkLimit); } /** diff --git a/src/test/pow_tests.cpp b/src/test/pow_tests.cpp --- a/src/test/pow_tests.cpp +++ b/src/test/pow_tests.cpp @@ -2,9 +2,9 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "pow.h" #include "chain.h" #include "chainparams.h" +#include "pow.h" #include "random.h" #include "test/test_bitcoin.h" #include "util.h" @@ -338,6 +338,39 @@ nBits = nextBits; } + + // Check the long-term block production time stabiliser - that attempts + // to game with timestamps 5 mins apart still causes difficulty to rise + // even though the standard window isn't hit. + + // Reset to just after the initial regular blocks + i = 2050; + nBits = initialBits; + + for (size_t j = 0; j < 300; i++, j++) { + blocks[i] = GetBlockIndex(&blocks[i - 1], 300, nBits); + uint32_t nextBits = + GetNextCashWorkRequired(&blocks[i], &blkHeaderDummy, params); + + // Check that a) the normal windowing isn't adjusting difficulty, + // and that b) the difficulty responds once the fast blocks start to + // materially affect the 2016-block timestamp difference. + if (j <= 200) { + BOOST_CHECK_EQUAL(nextBits, nBits); + } else { + arith_uint256 currentTarget; + currentTarget.SetCompact(nBits); + arith_uint256 nextTarget; + nextTarget.SetCompact(nextBits); + + // Make sure that difficulty increases slowly. + BOOST_CHECK(nextTarget < currentTarget); + BOOST_CHECK((currentTarget - nextTarget) < (currentTarget / 250)); + BOOST_CHECK((currentTarget - nextTarget) > (currentTarget / 260)); + } + + nBits = nextBits; + } } BOOST_AUTO_TEST_SUITE_END()