aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am2
-rw-r--r--src/Makefile.test.include1
-rw-r--r--src/dogecoin.cpp78
-rw-r--r--src/dogecoin.h14
-rw-r--r--src/pow.cpp33
-rw-r--r--src/test/dogecoin_tests.cpp104
6 files changed, 225 insertions, 7 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 0331571a1..8e8ce6646 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -134,6 +134,8 @@ BITCOIN_CORE_H = \
core_memusage.h \
cuckoocache.h \
dbwrapper.h \
+ dogecoin.cpp \
+ dogecoin.h \
flatfile.h \
fs.h \
httprpc.h \
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index 2b6de6cce..31738769f 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -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 \
diff --git a/src/dogecoin.cpp b/src/dogecoin.cpp
new file mode 100644
index 000000000..7af47d5d4
--- /dev/null
+++ b/src/dogecoin.cpp
@@ -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();
+}
diff --git a/src/dogecoin.h b/src/dogecoin.h
new file mode 100644
index 000000000..134caa629
--- /dev/null
+++ b/src/dogecoin.h
@@ -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
diff --git a/src/pow.cpp b/src/pow.cpp
index 70c61e77d..de8ba9be2 100644
--- a/src/pow.cpp
+++ b/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)
diff --git a/src/test/dogecoin_tests.cpp b/src/test/dogecoin_tests.cpp
new file mode 100644
index 000000000..b446ff685
--- /dev/null
+++ b/src/test/dogecoin_tests.cpp
@@ -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()