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.difficultyMinActualTimespan = consensus.difficultyTargetTimespan * 92 / 100;
|
||||||
consensus.difficultyMaxActualTimespan = consensus.difficultyTargetTimespan * 116 / 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.difficultyMinActualTimespan = consensus.difficultyTargetTimespan * 92 / 100;
|
||||||
consensus.difficultyMaxActualTimespan = consensus.difficultyTargetTimespan * 116 / 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.difficultyMinActualTimespan = consensus.difficultyTargetTimespan * 92 / 100;
|
||||||
consensus.difficultyMaxActualTimespan = consensus.difficultyTargetTimespan * 116 / 100;
|
consensus.difficultyMaxActualTimespan = consensus.difficultyTargetTimespan * 116 / 100;
|
||||||
|
consensus.asertActivationHeight = 6500;
|
||||||
|
consensus.asertHalfLife = 2 * 24 * 60 * 60;
|
||||||
|
|
||||||
|
|
||||||
consensus.BIP65Height = 1351;
|
consensus.BIP65Height = 1351;
|
||||||
|
|
|
||||||
|
|
@ -121,6 +121,8 @@ struct Params {
|
||||||
|
|
||||||
int64_t difficultyMinActualTimespan;
|
int64_t difficultyMinActualTimespan;
|
||||||
int64_t difficultyMaxActualTimespan;
|
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);
|
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)
|
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) {
|
if (pindexLast == nullptr) {
|
||||||
return InitialDifficulty(params);
|
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;
|
const CBlockIndex* pindexFirst = pindexLast;
|
||||||
for (int i = 0; pindexFirst && i < params.difficultyAveragingWindow; i++) {
|
for (int i = 0; pindexFirst && i < params.difficultyAveragingWindow; i++) {
|
||||||
pindexFirst = pindexFirst->pprev;
|
pindexFirst = pindexFirst->pprev;
|
||||||
|
|
|
||||||
|
|
@ -141,4 +141,214 @@ BOOST_AUTO_TEST_CASE(ChainParams_SIGNET_sanity)
|
||||||
sanity_check_chainparams(*m_node.args, CBaseChainParams::SIGNET);
|
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()
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue