Activate ASERT difficulty adjustment at block 6500
This commit is contained in:
parent
a69a236209
commit
a16bb53457
4 changed files with 290 additions and 1 deletions
|
|
@ -180,6 +180,8 @@ public:
|
|||
|
||||
consensus.difficultyMinActualTimespan = consensus.difficultyTargetTimespan * 92 / 100;
|
||||
consensus.difficultyMaxActualTimespan = consensus.difficultyTargetTimespan * 116 / 100;
|
||||
consensus.asertActivationHeight = 6500;
|
||||
consensus.asertHalfLife = 2 * 24 * 60 * 60;
|
||||
|
||||
|
||||
|
||||
|
|
@ -219,6 +221,8 @@ public:
|
|||
|
||||
consensus.difficultyMinActualTimespan = consensus.difficultyTargetTimespan * 92 / 100;
|
||||
consensus.difficultyMaxActualTimespan = consensus.difficultyTargetTimespan * 116 / 100;
|
||||
consensus.asertActivationHeight = 6500;
|
||||
consensus.asertHalfLife = 2 * 24 * 60 * 60;
|
||||
|
||||
|
||||
|
||||
|
|
@ -451,6 +455,8 @@ public:
|
|||
|
||||
consensus.difficultyMinActualTimespan = consensus.difficultyTargetTimespan * 92 / 100;
|
||||
consensus.difficultyMaxActualTimespan = consensus.difficultyTargetTimespan * 116 / 100;
|
||||
consensus.asertActivationHeight = 6500;
|
||||
consensus.asertHalfLife = 2 * 24 * 60 * 60;
|
||||
|
||||
|
||||
consensus.BIP65Height = 1351;
|
||||
|
|
|
|||
|
|
@ -121,6 +121,8 @@ struct Params {
|
|||
|
||||
int64_t difficultyMinActualTimespan;
|
||||
int64_t difficultyMaxActualTimespan;
|
||||
int asertActivationHeight;
|
||||
int64_t asertHalfLife;
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
73
src/pow.cpp
73
src/pow.cpp
|
|
@ -22,13 +22,84 @@ unsigned int InitialDifficulty(const Consensus::Params& params)
|
|||
return PowLimit(params);
|
||||
}
|
||||
|
||||
unsigned int CalculateASERT(const CBlockIndex* pindexLast, const Consensus::Params& params)
|
||||
{
|
||||
// Anchor ASERT to the last block before activation.
|
||||
const int anchorHeight = params.asertActivationHeight - 1;
|
||||
const CBlockIndex* pindexAnchor = pindexLast->GetAncestor(anchorHeight);
|
||||
|
||||
if (pindexAnchor == nullptr) {
|
||||
return pindexLast->nBits;
|
||||
}
|
||||
|
||||
const int64_t heightDiff = pindexLast->nHeight - pindexAnchor->nHeight;
|
||||
const int64_t timeDiff = pindexLast->GetBlockTime() - pindexAnchor->pprev->GetBlockTime();
|
||||
|
||||
// ASERT exponent in fixed-point 16.16:
|
||||
// exponent = (timeDiff - idealTime) / halfLife
|
||||
const int64_t idealTime = (heightDiff + 1) * params.nPowTargetSpacing;
|
||||
const int64_t exponent = ((timeDiff - idealTime) * 65536) / params.asertHalfLife;
|
||||
|
||||
int64_t shifts = exponent >> 16;
|
||||
const uint16_t frac = static_cast<uint16_t>(exponent);
|
||||
|
||||
// Approximation of 2^(frac/65536), scaled by 65536.
|
||||
const uint64_t factor =
|
||||
65536ULL +
|
||||
((195766423245049ULL * frac +
|
||||
971821376ULL * frac * frac +
|
||||
5127ULL * frac * frac * frac +
|
||||
(1ULL << 47)) >> 48);
|
||||
|
||||
arith_uint256 target;
|
||||
target.SetCompact(pindexAnchor->nBits);
|
||||
target *= factor;
|
||||
|
||||
// factor is scaled by 2^16.
|
||||
shifts -= 16;
|
||||
|
||||
const arith_uint256 powLimit = UintToArith256(params.powLimit);
|
||||
|
||||
if (shifts <= 0) {
|
||||
if (-shifts >= 256) {
|
||||
target = 1;
|
||||
} else {
|
||||
target >>= -shifts;
|
||||
}
|
||||
} else {
|
||||
if (shifts >= 256 || target > (powLimit >> shifts)) {
|
||||
target = powLimit;
|
||||
} else {
|
||||
target <<= shifts;
|
||||
}
|
||||
}
|
||||
|
||||
if (target == 0) {
|
||||
target = 1;
|
||||
}
|
||||
if (target > powLimit) {
|
||||
target = powLimit;
|
||||
}
|
||||
|
||||
return target.GetCompact();
|
||||
}
|
||||
|
||||
unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params)
|
||||
{
|
||||
// Vexta is SHA256D-only. Use one global averaging window.
|
||||
// Vexta is SHA256D-only.
|
||||
if (pindexLast == nullptr) {
|
||||
return InitialDifficulty(params);
|
||||
}
|
||||
|
||||
// ASERT activates for the block at asertActivationHeight.
|
||||
// pindexLast is the previous block, so activation starts when
|
||||
// the next block height reaches the configured activation height.
|
||||
if (!params.fPowNoRetargeting &&
|
||||
!params.fEasyPow &&
|
||||
pindexLast->nHeight + 1 >= params.asertActivationHeight) {
|
||||
return CalculateASERT(pindexLast, params);
|
||||
}
|
||||
|
||||
const CBlockIndex* pindexFirst = pindexLast;
|
||||
for (int i = 0; pindexFirst && i < params.difficultyAveragingWindow; i++) {
|
||||
pindexFirst = pindexFirst->pprev;
|
||||
|
|
|
|||
|
|
@ -141,4 +141,214 @@ BOOST_AUTO_TEST_CASE(ChainParams_SIGNET_sanity)
|
|||
sanity_check_chainparams(*m_node.args, CBaseChainParams::SIGNET);
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(ASERT_behavior_test)
|
||||
{
|
||||
const auto chainParams = CreateChainParams(*m_node.args, CBaseChainParams::MAIN);
|
||||
const auto consensus = chainParams->GetConsensus();
|
||||
|
||||
std::vector<CBlockIndex> blocks(6501);
|
||||
|
||||
arith_uint256 anchorTargetValue = UintToArith256(consensus.powLimit);
|
||||
anchorTargetValue >>= 8;
|
||||
const unsigned int anchorBits = anchorTargetValue.GetCompact();
|
||||
const int64_t startTime = 1800000000;
|
||||
|
||||
for (int i = 0; i <= 6500; ++i) {
|
||||
blocks[i].pprev = i ? &blocks[i - 1] : nullptr;
|
||||
blocks[i].nHeight = i;
|
||||
blocks[i].nTime = startTime + i * consensus.nPowTargetSpacing;
|
||||
blocks[i].nBits = anchorBits;
|
||||
}
|
||||
|
||||
// Block 6499 is still governed by the legacy DAA.
|
||||
const unsigned int preActivationBits =
|
||||
GetNextWorkRequired(&blocks[6498], nullptr, consensus);
|
||||
BOOST_CHECK_EQUAL(preActivationBits, anchorBits);
|
||||
|
||||
// Block 6500 is the first ASERT block. Ideal 10-minute spacing
|
||||
// must preserve the anchor target.
|
||||
const unsigned int idealBits =
|
||||
GetNextWorkRequired(&blocks[6499], nullptr, consensus);
|
||||
BOOST_CHECK_EQUAL(idealBits, anchorBits);
|
||||
|
||||
// Block 6501 after a very fast previous block: target must decrease
|
||||
// (difficulty increases).
|
||||
blocks[6500].nTime =
|
||||
blocks[6499].nTime + consensus.nPowTargetSpacing / 10;
|
||||
|
||||
const unsigned int fastBits =
|
||||
GetNextWorkRequired(&blocks[6500], nullptr, consensus);
|
||||
|
||||
arith_uint256 fastTarget;
|
||||
fastTarget.SetCompact(fastBits);
|
||||
|
||||
arith_uint256 anchorTarget;
|
||||
anchorTarget.SetCompact(anchorBits);
|
||||
|
||||
BOOST_CHECK(fastTarget < anchorTarget);
|
||||
|
||||
// Block 6501 after a slow previous block: target must increase
|
||||
// (difficulty decreases).
|
||||
blocks[6500].nTime =
|
||||
blocks[6499].nTime + consensus.nPowTargetSpacing * 3;
|
||||
|
||||
const unsigned int slowBits =
|
||||
GetNextWorkRequired(&blocks[6500], nullptr, consensus);
|
||||
|
||||
arith_uint256 slowTarget;
|
||||
slowTarget.SetCompact(slowBits);
|
||||
|
||||
BOOST_CHECK(slowTarget > anchorTarget);
|
||||
|
||||
// Extreme delay must never produce a target above powLimit.
|
||||
blocks[6500].nTime =
|
||||
blocks[6499].nTime + consensus.asertHalfLife * 16;
|
||||
|
||||
const unsigned int extremeSlowBits =
|
||||
GetNextWorkRequired(&blocks[6500], nullptr, consensus);
|
||||
|
||||
BOOST_CHECK_EQUAL(
|
||||
extremeSlowBits,
|
||||
UintToArith256(consensus.powLimit).GetCompact());
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(ASERT_reference_vector_run04_test)
|
||||
{
|
||||
auto chainParams = CreateChainParams(*m_node.args, CBaseChainParams::MAIN);
|
||||
auto consensus = chainParams->GetConsensus();
|
||||
|
||||
consensus.asertActivationHeight = 2;
|
||||
consensus.asertHalfLife = 2 * 24 * 60 * 60;
|
||||
|
||||
std::vector<CBlockIndex> blocks(3);
|
||||
|
||||
blocks[0].pprev = nullptr;
|
||||
blocks[0].nHeight = 0;
|
||||
blocks[0].nTime = 0;
|
||||
blocks[0].nBits = 0x01010000;
|
||||
|
||||
blocks[1].pprev = &blocks[0];
|
||||
blocks[1].nHeight = 1;
|
||||
blocks[1].nTime = 600;
|
||||
blocks[1].nBits = 0x01010000;
|
||||
|
||||
// BCHN official ASERT run04 vector:
|
||||
// anchor height = 1
|
||||
// anchor ancestor time = 0
|
||||
// evaluation height = 2
|
||||
// evaluation time = 174000
|
||||
// expected next target = 0x01020000
|
||||
blocks[2].pprev = &blocks[1];
|
||||
blocks[2].nHeight = 2;
|
||||
blocks[2].nTime = 174000;
|
||||
blocks[2].nBits = 0x01010000;
|
||||
|
||||
const unsigned int result =
|
||||
GetNextWorkRequired(&blocks[2], nullptr, consensus);
|
||||
|
||||
BOOST_CHECK_EQUAL(result, 0x01020000U);
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(ASERT_reference_vector_run05_test)
|
||||
{
|
||||
auto chainParams = CreateChainParams(*m_node.args, CBaseChainParams::MAIN);
|
||||
auto consensus = chainParams->GetConsensus();
|
||||
|
||||
consensus.asertActivationHeight = 2;
|
||||
consensus.asertHalfLife = 2 * 24 * 60 * 60;
|
||||
|
||||
std::vector<CBlockIndex> blocks(291);
|
||||
|
||||
blocks[0].pprev = nullptr;
|
||||
blocks[0].nHeight = 0;
|
||||
blocks[0].nTime = 0;
|
||||
blocks[0].nBits = 0x1d00ffff;
|
||||
|
||||
blocks[1].pprev = &blocks[0];
|
||||
blocks[1].nHeight = 1;
|
||||
blocks[1].nTime = 600;
|
||||
blocks[1].nBits = 0x1d00ffff;
|
||||
|
||||
// BCHN official ASERT run05 vector, iteration 1:
|
||||
blocks[2].pprev = &blocks[1];
|
||||
blocks[2].nHeight = 2;
|
||||
blocks[2].nTime = 0;
|
||||
blocks[2].nBits = 0x1d00ffff;
|
||||
|
||||
BOOST_CHECK_EQUAL(
|
||||
GetNextWorkRequired(&blocks[2], nullptr, consensus),
|
||||
0x1d00fec5U);
|
||||
|
||||
// BCHN official ASERT run05 vector, iteration 2:
|
||||
// evaluation height = 290, time = 0
|
||||
for (int h = 3; h <= 290; ++h) {
|
||||
blocks[h].pprev = &blocks[h - 1];
|
||||
blocks[h].nHeight = h;
|
||||
blocks[h].nTime = 0;
|
||||
blocks[h].nBits = 0x1d00ffff;
|
||||
}
|
||||
|
||||
BOOST_CHECK_EQUAL(
|
||||
GetNextWorkRequired(&blocks[290], nullptr, consensus),
|
||||
0x1c7f62c0U);
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(ASERT_reference_vector_run06_test)
|
||||
{
|
||||
auto chainParams = CreateChainParams(*m_node.args, CBaseChainParams::MAIN);
|
||||
auto consensus = chainParams->GetConsensus();
|
||||
|
||||
consensus.asertActivationHeight = 2;
|
||||
consensus.asertHalfLife = 2 * 24 * 60 * 60;
|
||||
|
||||
std::vector<CBlockIndex> blocks(13);
|
||||
|
||||
blocks[0].pprev = nullptr;
|
||||
blocks[0].nHeight = 0;
|
||||
blocks[0].nTime = 0;
|
||||
blocks[0].nBits = 0x1802aee8;
|
||||
|
||||
blocks[1].pprev = &blocks[0];
|
||||
blocks[1].nHeight = 1;
|
||||
blocks[1].nTime = 600;
|
||||
blocks[1].nBits = 0x1802aee8;
|
||||
|
||||
const int64_t times[] = {
|
||||
0, 600,
|
||||
1200, 1310, 1327, 1739, 2219, 2604,
|
||||
2746, 7099, 7099, 7657, 8626
|
||||
};
|
||||
|
||||
const unsigned int expected[] = {
|
||||
0,
|
||||
0,
|
||||
0x1802aee8U,
|
||||
0x1802ad91U,
|
||||
0x1802abf8U,
|
||||
0x1802ab73U,
|
||||
0x1802ab20U,
|
||||
0x1802aa89U,
|
||||
0x1802a94bU,
|
||||
0x1802b39cU,
|
||||
0x1802b1f2U,
|
||||
0x1802b1d4U,
|
||||
0x1802b2dbU
|
||||
};
|
||||
|
||||
for (int h = 2; h <= 12; ++h) {
|
||||
blocks[h].pprev = &blocks[h - 1];
|
||||
blocks[h].nHeight = h;
|
||||
blocks[h].nTime = times[h];
|
||||
blocks[h].nBits = 0x1802aee8;
|
||||
|
||||
BOOST_CHECK_EQUAL(
|
||||
GetNextWorkRequired(&blocks[h], nullptr, consensus),
|
||||
expected[h]);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
|
|
|||
Loading…
Reference in a new issue