[DAA] Add ASERT DAA with height-based fork
... | ... | @@ -71,3 +71,15 @@ bool IsPhononEnabled(const Consensus::Params ¶ms, |
return pindexPrev->GetMedianTimePast() >= | ||
gArgs.GetArg("-phononactivationtime", params.phononActivationTime); | ||
} | ||
bool IsASERTEnabled(const Consensus::Params ¶ms, int32_t nHeight) { | ||
return nHeight >= gArgs.GetArg("-asertactivationheight", INT_MAX); | ||
|
||
} | ||
bool IsASERTEnabled(const Consensus::Params ¶ms, const CBlockIndex *pindexPrev) { | ||
if (pindexPrev == nullptr) { | ||
return false; | ||
} | ||
return IsASERTEnabled(params, pindexPrev->nHeight); | ||
} | ||
\ No newline at end of file |
... | ... | @@ -102,6 +102,10 @@ uint32_t GetNextWorkRequired(const CBlockIndex *pindexPrev, |
return pindexPrev->nBits; | ||
} | ||
if (IsASERTEnabled(params, pindexPrev)) { | ||
return GetNextASERTWorkRequired(pindexPrev, pblock, params, gArgs.GetArg("-asertactivationheight", INT_MAX)); | ||
} | ||
if (IsDAAEnabled(params, pindexPrev)) { | ||
return GetNextCashWorkRequired(pindexPrev, pblock, params); | ||
} | ||
... | ... | @@ -282,3 +286,79 @@ uint32_t GetNextCashWorkRequired(const CBlockIndex *pindexPrev, |
return nextTarget.GetCompact(); | ||
} | ||
/** | ||
* Compute the next required proof of work using an absolutely scheduled | ||
* exponentially weighted target (ASERT). | ||
* | ||
* With ASERT, we define an ideal schedule for block issuance (e.g. 1 block every 600 seconds), and we calculate the | ||
* difficulty based on how far the most recent block's timestamp is ahead of or behind that schedule. | ||
* We set our targets (difficulty) exponentially. For every [tau] seconds ahead of or behind schedule we get, we | ||
* double or halve the difficulty. | ||
*/ | ||
uint32_t GetNextASERTWorkRequired(const CBlockIndex *pindexPrev, | ||
const CBlockHeader *pblock, | ||
const Consensus::Params ¶ms, | ||
const int32_t nforkHeight) { | ||
|
||
// This cannot handle the genesis block and early blocks in general. | ||
assert(pindexPrev); | ||
// 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 (params.fPowAllowMinDifficultyBlocks && | ||
(pblock->GetBlockTime() > | ||
pindexPrev->GetBlockTime() + 2 * params.nPowTargetSpacing)) { | ||
return UintToArith256(params.powLimit).GetCompact(); | ||
} | ||
// Diff halves/doubles for every 2 days behind/ahead of schedule we get | ||
const uint64_t tau = 2*24*60*60; | ||
|
||
// This algorithm uses fixed-point math. The lowest rbits bits are after | ||
// the radix, and represent the "decimal" (or binary) portion of the value | ||
const uint8_t rbits = 16; | ||
|
||
const CBlockIndex *pforkBlock = &pindexPrev[nforkHeight]; | ||
|
||
assert(pforkBlock != nullptr); | ||
assert(pindexPrev->nHeight >= params.DifficultyAdjustmentInterval()); | ||
|
||
int32_t nTimeDiff = pindexPrev->nTime - pforkBlock->GetBlockHeader().nTime; | ||
|
||
int32_t nHeightDiff = pindexPrev->nHeight - pforkBlock->nHeight; | ||
|
||
const arith_uint256 origTarget = arith_uint256().SetCompact(pforkBlock->nBits); | ||
arith_uint256 nextTarget = origTarget; | ||
// Ultimately, we want to approximate the following ASERT formula, using only integer (fixed-point) math: | ||
// new_target = old_target * 2^((blocks_time - IDEAL_BLOCK_TIME*(height_diff+1)) / tau) | ||
// First, we'll calculate the exponent: | ||
int64_t exponent = ((nTimeDiff - params.nPowTargetSpacing * (nHeightDiff+1)) << rbits) / tau; | ||
|
||
// Next, we use the 2^x = 2 * 2(x-1) identity to shift our exponent into the [0, 1) interval. | ||
|
||
// The truncated exponent tells us how many shifts we need to do | ||
// Note: This needs to be a right shift. Right shift rounds downward, whereas division rounds towards zero. | ||
int8_t shifts = exponent >> rbits; | ||
|
||
if (shifts < 0) { | ||
nextTarget = nextTarget >> -shifts; | ||
} else { | ||
nextTarget = nextTarget << shifts; | ||
} | ||
exponent -= (shifts << rbits); | ||
|
||
// Now we compute an approximated target * 2^(exponent) | ||
// 2^x ~= (1 + 0.695502049*x + 0.2262698*x**2 + 0.0782318*x**3) for 0 <= x < 1 | ||
// Error versus actual 2^x is less than 0.013%. | ||
uint64_t factor = (195766423245049*exponent + | ||
971821376*exponent*exponent + | ||
5127*exponent*exponent*exponent + (1ll<<47))>>(rbits*3); | ||
nextTarget += (nextTarget * factor) >> rbits; | ||
const arith_uint256 powLimit = UintToArith256(params.powLimit); | ||
|
||
if (nextTarget > powLimit) { | ||
return powLimit.GetCompact(); | ||
} | ||
return nextTarget.GetCompact(); | ||
} |
-
mentioned in merge request bitcoin-cash-node/bitcoin-cash-node!692 (merged)