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 \
|
core_memusage.h \
|
||||||
cuckoocache.h \
|
cuckoocache.h \
|
||||||
dbwrapper.h \
|
dbwrapper.h \
|
||||||
|
dogecoin.cpp \
|
||||||
|
dogecoin.h \
|
||||||
flatfile.h \
|
flatfile.h \
|
||||||
fs.h \
|
fs.h \
|
||||||
httprpc.h \
|
httprpc.h \
|
||||||
|
|
|
@ -232,6 +232,7 @@ BITCOIN_TESTS =\
|
||||||
test/cuckoocache_tests.cpp \
|
test/cuckoocache_tests.cpp \
|
||||||
test/denialofservice_tests.cpp \
|
test/denialofservice_tests.cpp \
|
||||||
test/descriptor_tests.cpp \
|
test/descriptor_tests.cpp \
|
||||||
|
test/dogecoin_tests.cpp \
|
||||||
test/flatfile_tests.cpp \
|
test/flatfile_tests.cpp \
|
||||||
test/fs_tests.cpp \
|
test/fs_tests.cpp \
|
||||||
test/getarg_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 <arith_uint256.h>
|
||||||
#include <chain.h>
|
#include <chain.h>
|
||||||
|
#include <dogecoin.h>
|
||||||
#include <primitives/block.h>
|
#include <primitives/block.h>
|
||||||
#include <uint256.h>
|
#include <uint256.h>
|
||||||
|
|
||||||
|
@ -15,21 +16,39 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead
|
||||||
assert(pindexLast != nullptr);
|
assert(pindexLast != nullptr);
|
||||||
unsigned int nProofOfWorkLimit = UintToArith256(params.powLimit).GetCompact();
|
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
|
// 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)
|
if (params.fPowAllowMinDifficultyBlocks)
|
||||||
{
|
{
|
||||||
// Special difficulty rule for testnet:
|
// Special difficulty rule for testnet:
|
||||||
// If the new block's timestamp is more than 2* 10 minutes
|
// If the new block's timestamp is more than 2* 10 minutes
|
||||||
// then allow mining of a min-difficulty block.
|
// 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;
|
return nProofOfWorkLimit;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Return the last non-special-min-difficulty-rules-block
|
// Return the last non-special-min-difficulty-rules-block
|
||||||
const CBlockIndex* pindex = pindexLast;
|
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;
|
pindex = pindex->pprev;
|
||||||
return pindex->nBits;
|
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.
|
// 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
|
// Go back the full period unless it's the first retarget after genesis. Code courtesy of Art Forz
|
||||||
int blockstogoback = params.DifficultyAdjustmentInterval()-1;
|
int blockstogoback = difficultyAdjustmentInterval-1;
|
||||||
if ((pindexLast->nHeight+1) != params.DifficultyAdjustmentInterval())
|
if ((pindexLast->nHeight+1) != difficultyAdjustmentInterval)
|
||||||
blockstogoback = params.DifficultyAdjustmentInterval();
|
blockstogoback = difficultyAdjustmentInterval;
|
||||||
|
|
||||||
// Go back by what we want to be 14 days worth of blocks
|
// Go back by what we want to be 14 days worth of blocks
|
||||||
int nHeightFirst = pindexLast->nHeight - blockstogoback;
|
int nHeightFirst = pindexLast->nHeight - blockstogoback;
|
||||||
|
@ -49,7 +68,7 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead
|
||||||
const CBlockIndex* pindexFirst = pindexLast->GetAncestor(nHeightFirst);
|
const CBlockIndex* pindexFirst = pindexLast->GetAncestor(nHeightFirst);
|
||||||
assert(pindexFirst);
|
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)
|
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