Merge pull request #1977 from rnicoll/1.21-difficulty
Introduce Dogecoin difficulty calculations
This commit is contained in:
commit
4fc6d6360a
|
@ -134,6 +134,8 @@ BITCOIN_CORE_H = \
|
|||
core_memusage.h \
|
||||
cuckoocache.h \
|
||||
dbwrapper.h \
|
||||
dogecoin.cpp \
|
||||
dogecoin.h \
|
||||
flatfile.h \
|
||||
fs.h \
|
||||
httprpc.h \
|
||||
|
|
|
@ -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
78
src/dogecoin.cpp
Normal 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
14
src/dogecoin.h
Normal 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
|
33
src/pow.cpp
33
src/pow.cpp
|
@ -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
104
src/test/dogecoin_tests.cpp
Normal 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()
|
Loading…
Reference in a new issue