[DAA] Add ASERT DAA with heightbased fork
...  ...  @@ 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 mindifficulty 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 fixedpoint 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 (fixedpoint) 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(x1) 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 bitcoincashnode/bitcoincashnode!692 (merged)