Merge pull request #1977 from rnicoll/1.21-difficulty

Introduce Dogecoin difficulty calculations
This commit is contained in:
Patrick Lodder 2021-05-29 21:15:48 +02:00 committed by GitHub
commit 4fc6d6360a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 225 additions and 7 deletions

View file

@ -134,6 +134,8 @@ BITCOIN_CORE_H = \
core_memusage.h \
cuckoocache.h \
dbwrapper.h \
dogecoin.cpp \
dogecoin.h \
flatfile.h \
fs.h \
httprpc.h \

View file

@ -232,6 +232,7 @@ BITCOIN_TESTS =\
test/cuckoocache_tests.cpp \
test/denialofservice_tests.cpp \
test/descriptor_tests.cpp \
test/dogecoin_tests.cpp \
test/flatfile_tests.cpp \
test/fs_tests.cpp \
test/getarg_tests.cpp \

78
src/dogecoin.cpp Normal file
View file

@ -0,0 +1,78 @@
// Copyright (c) 2015-2021 The Dogecoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <arith_uint256.h>
#include <dogecoin.h>
#include <logging.h>
// Dogecoin: Normally minimum difficulty blocks can only occur in between
// retarget blocks. However, once we introduce Digishield every block is
// a retarget, so we need to handle minimum difficulty on all blocks.
bool AllowDigishieldMinDifficultyForBlock(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params)
{
// check if the chain allows minimum difficulty blocks
if (!params.fPowAllowMinDifficultyBlocks)
return false;
// check if the chain allows minimum difficulty blocks on recalc blocks
if (pindexLast->nHeight < 157500)
// if (!params.fPowAllowDigishieldMinDifficultyBlocks)
return false;
// Allow for a minimum block time if the elapsed time > 2*nTargetSpacing
return (pblock->GetBlockTime() > pindexLast->GetBlockTime() + params.nPowTargetSpacing*2);
}
unsigned int CalculateDogecoinNextWorkRequired(const CBlockIndex* pindexLast, int64_t nFirstBlockTime, const Consensus::Params& params)
{
if (params.fPowNoRetargeting)
return pindexLast->nBits;
int nHeight = pindexLast->nHeight + 1;
bool fNewDifficultyProtocol = (nHeight >= 145000);
// bool fNewDifficultyProtocol = (nHeight >= params.GetDigiShieldForkBlock());
const int64_t nRetargetTimespan = fNewDifficultyProtocol
? 60 // params.DigiShieldTargetTimespan()
: params.nPowTargetTimespan;
int64_t nTimespan = pindexLast->GetBlockTime() - nFirstBlockTime;
int64_t nMaxTimespan;
int64_t nMinTimespan;
if (fNewDifficultyProtocol) //DigiShield implementation - thanks to RealSolid & WDC for this code
{
// amplitude filter - thanks to daft27 for this code
nTimespan = nRetargetTimespan + (nTimespan - nRetargetTimespan) / 8;
nMinTimespan = nRetargetTimespan - (nRetargetTimespan / 4);
nMaxTimespan = nRetargetTimespan + (nRetargetTimespan / 2);
} else if (nHeight > 10000) {
nMinTimespan = nRetargetTimespan / 4;
nMaxTimespan = nRetargetTimespan * 4;
} else if (nHeight > 5000) {
nMinTimespan = nRetargetTimespan / 8;
nMaxTimespan = nRetargetTimespan * 4;
} else {
nMinTimespan = nRetargetTimespan / 16;
nMaxTimespan = nRetargetTimespan * 4;
}
// Limit adjustment step
if (nTimespan < nMinTimespan)
nTimespan = nMinTimespan;
else if (nTimespan > nMaxTimespan)
nTimespan = nMaxTimespan;
// Retarget
const arith_uint256 bnPowLimit = UintToArith256(params.powLimit);
arith_uint256 bnNew;
bnNew.SetCompact(pindexLast->nBits);
bnNew *= nTimespan;
bnNew /= nRetargetTimespan;
if (bnNew > bnPowLimit)
bnNew = bnPowLimit;
return bnNew.GetCompact();
}

14
src/dogecoin.h Normal file
View file

@ -0,0 +1,14 @@
// Copyright (c) 2015-2017 The Dogecoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_DOGECOIN_H
#define BITCOIN_DOGECOIN_H
#include <chain.h>
#include <chainparams.h>
bool AllowDigishieldMinDifficultyForBlock(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params);
unsigned int CalculateDogecoinNextWorkRequired(const CBlockIndex* pindexLast, int64_t nLastRetargetTime, const Consensus::Params& params);
#endif // BITCOIN_DOGECOIN_H

View file

@ -7,6 +7,7 @@
#include <arith_uint256.h>
#include <chain.h>
#include <dogecoin.h>
#include <primitives/block.h>
#include <uint256.h>
@ -15,21 +16,39 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead
assert(pindexLast != nullptr);
unsigned int nProofOfWorkLimit = UintToArith256(params.powLimit).GetCompact();
// Dogecoin: Special rules for minimum difficulty blocks with Digishield
if (AllowDigishieldMinDifficultyForBlock(pindexLast, pblock, params))
{
// Special difficulty rule for testnet:
// If the new block's timestamp is more than 2* nTargetSpacing minutes
// then allow mining of a min-difficulty block.
return nProofOfWorkLimit;
}
// Only change once per difficulty adjustment interval
if ((pindexLast->nHeight+1) % params.DifficultyAdjustmentInterval() != 0)
bool fNewDifficultyProtocol = (pindexLast->nHeight+1 >= 145000);
const int64_t difficultyAdjustmentInterval = fNewDifficultyProtocol
? 1
: params.DifficultyAdjustmentInterval();
const int64_t powTargetSpacing = fNewDifficultyProtocol
? 60
: params.nPowTargetSpacing;
if ((pindexLast->nHeight+1) % difficultyAdjustmentInterval != 0)
{
if (params.fPowAllowMinDifficultyBlocks)
{
// Special difficulty rule for testnet:
// If the new block's timestamp is more than 2* 10 minutes
// then allow mining of a min-difficulty block.
if (pblock->GetBlockTime() > pindexLast->GetBlockTime() + params.nPowTargetSpacing*2)
if (pblock->GetBlockTime() > pindexLast->GetBlockTime() + powTargetSpacing*2) {
return nProofOfWorkLimit;
}
else
{
// Return the last non-special-min-difficulty-rules-block
const CBlockIndex* pindex = pindexLast;
while (pindex->pprev && pindex->nHeight % params.DifficultyAdjustmentInterval() != 0 && pindex->nBits == nProofOfWorkLimit)
while (pindex->pprev && pindex->nHeight % difficultyAdjustmentInterval != 0 && pindex->nBits == nProofOfWorkLimit)
pindex = pindex->pprev;
return pindex->nBits;
}
@ -39,9 +58,9 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead
// Litecoin: This fixes an issue where a 51% attack can change difficulty at will.
// Go back the full period unless it's the first retarget after genesis. Code courtesy of Art Forz
int blockstogoback = params.DifficultyAdjustmentInterval()-1;
if ((pindexLast->nHeight+1) != params.DifficultyAdjustmentInterval())
blockstogoback = params.DifficultyAdjustmentInterval();
int blockstogoback = difficultyAdjustmentInterval-1;
if ((pindexLast->nHeight+1) != difficultyAdjustmentInterval)
blockstogoback = difficultyAdjustmentInterval;
// Go back by what we want to be 14 days worth of blocks
int nHeightFirst = pindexLast->nHeight - blockstogoback;
@ -49,7 +68,7 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead
const CBlockIndex* pindexFirst = pindexLast->GetAncestor(nHeightFirst);
assert(pindexFirst);
return CalculateNextWorkRequired(pindexLast, pindexFirst->GetBlockTime(), params);
return CalculateDogecoinNextWorkRequired(pindexLast, pindexFirst->GetBlockTime(), params);
}
unsigned int CalculateNextWorkRequired(const CBlockIndex* pindexLast, int64_t nFirstBlockTime, const Consensus::Params& params)

104
src/test/dogecoin_tests.cpp Normal file
View file

@ -0,0 +1,104 @@
// Copyright (c) 2015-2021 The Dogecoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <arith_uint256.h>
#include <chainparams.h>
#include <dogecoin.h>
#include <test/util/setup_common.h>
#include <boost/test/unit_test.hpp>
BOOST_FIXTURE_TEST_SUITE(dogecoin_tests, TestingSetup)
BOOST_AUTO_TEST_CASE(get_next_work_difficulty_limit)
{
SelectParams(CBaseChainParams::MAIN);
const Consensus::Params& params = Params().GetConsensus();
CBlockIndex pindexLast;
int64_t nLastRetargetTime = 1386474927; // Block # 1
pindexLast.nHeight = 239;
pindexLast.nTime = 1386475638; // Block #239
pindexLast.nBits = 0x1e0ffff0;
BOOST_CHECK_EQUAL(CalculateDogecoinNextWorkRequired(&pindexLast, nLastRetargetTime, params), 0x1e00ffff);
}
BOOST_AUTO_TEST_CASE(get_next_work_pre_digishield)
{
SelectParams(CBaseChainParams::MAIN);
const Consensus::Params& params = Params().GetConsensus();
CBlockIndex pindexLast;
int64_t nLastRetargetTime = 1386942008; // Block 9359
pindexLast.nHeight = 9599;
pindexLast.nTime = 1386954113;
pindexLast.nBits = 0x1c1a1206;
BOOST_CHECK_EQUAL(CalculateDogecoinNextWorkRequired(&pindexLast, nLastRetargetTime, params), 0x1c15ea59);
}
BOOST_AUTO_TEST_CASE(get_next_work_digishield)
{
SelectParams(CBaseChainParams::MAIN);
const Consensus::Params& params = Params().GetConsensus();
CBlockIndex pindexLast;
int64_t nLastRetargetTime = 1395094427;
// First hard-fork at 145,000, which applies to block 145,001 onwards
pindexLast.nHeight = 145000;
pindexLast.nTime = 1395094679;
pindexLast.nBits = 0x1b499dfd;
BOOST_CHECK_EQUAL(CalculateDogecoinNextWorkRequired(&pindexLast, nLastRetargetTime, params), 0x1b671062);
}
BOOST_AUTO_TEST_CASE(get_next_work_digishield_modulated_upper)
{
SelectParams(CBaseChainParams::MAIN);
const Consensus::Params& params = Params().GetConsensus();
CBlockIndex pindexLast;
int64_t nLastRetargetTime = 1395100835;
// Test the upper bound on modulated time using mainnet block #145,107
pindexLast.nHeight = 145107;
pindexLast.nTime = 1395101360;
pindexLast.nBits = 0x1b3439cd;
BOOST_CHECK_EQUAL(CalculateDogecoinNextWorkRequired(&pindexLast, nLastRetargetTime, params), 0x1b4e56b3);
}
BOOST_AUTO_TEST_CASE(get_next_work_digishield_modulated_lower)
{
SelectParams(CBaseChainParams::MAIN);
const Consensus::Params& params = Params().GetConsensus();
CBlockIndex pindexLast;
int64_t nLastRetargetTime = 1395380517;
// Test the lower bound on modulated time using mainnet block #149,423
pindexLast.nHeight = 149423;
pindexLast.nTime = 1395380447;
pindexLast.nBits = 0x1b446f21;
BOOST_CHECK_EQUAL(CalculateDogecoinNextWorkRequired(&pindexLast, nLastRetargetTime, params), 0x1b335358);
}
BOOST_AUTO_TEST_CASE(get_next_work_digishield_rounding)
{
SelectParams(CBaseChainParams::MAIN);
const Consensus::Params& params = Params().GetConsensus();
CBlockIndex pindexLast;
int64_t nLastRetargetTime = 1395094679;
// Test case for correct rounding of modulated time - this depends on
// handling of integer division, and is not obvious from the code
pindexLast.nHeight = 145001;
pindexLast.nTime = 1395094727;
pindexLast.nBits = 0x1b671062;
BOOST_CHECK_EQUAL(CalculateDogecoinNextWorkRequired(&pindexLast, nLastRetargetTime, params), 0x1b6558a4);
}
BOOST_AUTO_TEST_SUITE_END()