From e73b023dd82657cd32fba2bf15e0c8ceda689d9e Mon Sep 17 00:00:00 2001 From: LitecoinZ Date: Fri, 6 Nov 2020 03:14:51 +0100 Subject: [PATCH] LWMA difficulty adjustment algorithm --- src/chain.h | 11 ++++-- src/chainparams.cpp | 18 +++++----- src/consensus/params.h | 14 ++++---- src/pow.cpp | 79 +++++++++++++++++++++++------------------- src/rpc/mining.cpp | 4 +-- src/timedata.h | 8 ++++- 6 files changed, 76 insertions(+), 58 deletions(-) diff --git a/src/chain.h b/src/chain.h index 594f0171a702f..d3ff6ad7dc9db 100644 --- a/src/chain.h +++ b/src/chain.h @@ -19,16 +19,23 @@ /** * Maximum amount of time that a block timestamp is allowed to exceed the * current network-adjusted time before the block will be accepted. + * + * Based on: https://github.com/zawy12/difficulty-algorithms/issues/3 + * FTL = N*T/20 = 45 * 600 / 20 + * Bitcoin original value: 2 * 60 * 60 */ -static constexpr int64_t MAX_FUTURE_BLOCK_TIME = 2 * 60 * 60; +static constexpr int64_t MAX_FUTURE_BLOCK_TIME = 45 * 600 / 20; +static constexpr int64_t BITCOIN_MAX_FUTURE_BLOCK_TIME = 2 * 60 * 60; /** * Timestamp window used as a grace period by code that compares external * timestamps (such as timestamps passed to RPCs, or wallet key creation times) * to block timestamps. This should be set at least as high as * MAX_FUTURE_BLOCK_TIME. + * + * Folloing the change in MAX_FUTURE_BLOCK_TIME maintaining the original value. */ -static constexpr int64_t TIMESTAMP_WINDOW = MAX_FUTURE_BLOCK_TIME; +static constexpr int64_t TIMESTAMP_WINDOW = BITCOIN_MAX_FUTURE_BLOCK_TIME; /** * Maximum gap between node time and block time used diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 203f269aec6ca..c75ada6a55c90 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -92,9 +92,9 @@ class CMainParams : public CChainParams { consensus.nDigishieldMaxAdjustDown = 32; // 32% adjustment down consensus.nDigishieldMaxAdjustUp = 16; // 16% adjustment up - consensus.nZawyLWMAHeight = 600000; - consensus.nZawyLwmaAveragingWindow = 45; - consensus.nZawyLwmaAdjustedWeight = 13772; + // POW DDA LWMA Parameters + consensus.nLwmaForkHeight = 600000; + consensus.nLwmaAveragingWindow = 45; consensus.nPowTargetSpacing = 10 * 60; consensus.fPowAllowMinDifficultyBlocks = false; @@ -252,9 +252,9 @@ class CTestNetParams : public CChainParams { consensus.nDigishieldMaxAdjustDown = 32; // 32% adjustment down consensus.nDigishieldMaxAdjustUp = 16; // 16% adjustment up - consensus.nZawyLWMAHeight = 6500; - consensus.nZawyLwmaAveragingWindow = 45; - consensus.nZawyLwmaAdjustedWeight = 13772; + // POW DDA LWMA Parameters + consensus.nLwmaForkHeight = 6500; + consensus.nLwmaAveragingWindow = 45; consensus.nPowTargetSpacing = 10 * 60; consensus.fPowAllowMinDifficultyBlocks = false; @@ -393,9 +393,9 @@ class CRegTestParams : public CChainParams { consensus.nDigishieldMaxAdjustDown = 0; // Turn off adjustment down consensus.nDigishieldMaxAdjustUp = 0; // Turn off adjustment up - consensus.nZawyLWMAHeight = -1; // Activated on regtest - consensus.nZawyLwmaAveragingWindow = 45; - consensus.nZawyLwmaAdjustedWeight = 13772; + // POW DDA LWMA Parameters + consensus.nLwmaForkHeight = -1; // Activated on regtest + consensus.nLwmaAveragingWindow = 45; consensus.nPowTargetSpacing = 10 * 60; consensus.fPowAllowMinDifficultyBlocks = true; diff --git a/src/consensus/params.h b/src/consensus/params.h index caa3028973533..06082865e1582 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -148,11 +148,12 @@ struct Params { uint32_t nMinerConfirmationWindow; BIP9Deployment vDeployments[MAX_VERSION_BITS_DEPLOYMENTS]; - /** Block height at which Zawy's LWMA difficulty algorithm becomes active */ - int nZawyLWMAHeight; - /** Block height where Equihash<144,5> becomes active */ int nEquihashForkHeight; + + /** Block height at which Zawy's LWMA difficulty algorithm becomes active */ + int nLwmaForkHeight; + /** Proof of work parameters */ unsigned int nEquihashN1 = 0; unsigned int nEquihashK1 = 0; @@ -187,11 +188,8 @@ struct Params { int64_t DigishieldMinActualTimespan() const { return (DigishieldAveragingWindowTimespan() * (100 - nDigishieldMaxAdjustUp )) / 100; } int64_t DigishieldMaxActualTimespan() const { return (DigishieldAveragingWindowTimespan() * (100 + nDigishieldMaxAdjustDown)) / 100; } - // Params for Zawy's LWMA difficulty adjustment algorithm. - int64_t nZawyLwmaAveragingWindow; - int64_t nZawyLwmaAdjustedWeight; // k = (N+1)/2 * 0.998 * T - int64_t nZawyLwmaMinDenominator; - bool bZawyLwmaSolvetimeLimitation; + // Params for Lwma difficulty adjustment algorithm. + int64_t nLwmaAveragingWindow; int64_t nPowTargetSpacing; uint256 nMinimumChainWork; diff --git a/src/pow.cpp b/src/pow.cpp index 76195b6774abf..9c54689982262 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -20,7 +20,10 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead assert(pindexLast != nullptr); int nHeight = pindexLast->nHeight + 1; - if (nHeight < params.nZawyLWMAHeight) { + if (params.fPowNoRetargeting) + return pindexLast->nBits; + + if (nHeight < params.nLwmaForkHeight) { // Regular Digishield v3. return DigishieldGetNextWorkRequired(pindexLast, pblock, params); } else { @@ -85,9 +88,6 @@ unsigned int DigishieldGetNextWorkRequired(const CBlockIndex* pindexLast, const unsigned int DigishieldCalculateNextWorkRequired(const CBlockIndex* pindexLast, arith_uint256 bnAvg, int64_t nFirstBlockTime, const Consensus::Params& params) { - if (params.fPowNoRetargeting) - return pindexLast->nBits; - // Use medians to prevent time-warp attacks int64_t nActualTimespan = pindexLast->GetMedianTimePast() - nFirstBlockTime; LogPrint(BCLog::POW, " nActualTimespan = %d before dampening\n", nActualTimespan); @@ -132,52 +132,59 @@ unsigned int LwmaGetNextWorkRequired(const CBlockIndex* pindexLast, const CBlock unsigned int LwmaCalculateNextWorkRequired(const CBlockIndex* pindexLast, const Consensus::Params& params) { - if (params.fPowNoRetargeting) - return pindexLast->nBits; - - const int height = pindexLast->nHeight + 1; const int64_t T = params.nPowTargetSpacing; - const int N = params.nZawyLwmaAveragingWindow; - const int k = params.nZawyLwmaAdjustedWeight; - const int dnorm = params.nZawyLwmaMinDenominator; - const bool limit_st = params.bZawyLwmaSolvetimeLimitation; - assert(height > N); - arith_uint256 sum_target; - int t = 0, j = 0; + // For T=600, 300, 150 use approximately N=60, 90, 120 + const int64_t N = params.nLwmaAveragingWindow; + + // Define a k that will be used to get a proper average after weighting the solvetimes. + const int64_t k = N * (N + 1) * T / 2; + + const int64_t height = pindexLast->nHeight; + const arith_uint256 powLimit = UintToArith256(params.powLimit); + + // New coins just "give away" first N blocks. It's better to guess + // this value instead of using powLimit, but err on high side to not get stuck. + if (height < N) { return powLimit.GetCompact(); } + + arith_uint256 avgTarget, nextTarget; + int64_t thisTimestamp, previousTimestamp; + int64_t sumWeightedSolvetimes = 0, j = 0; + + const CBlockIndex* blockPreviousTimestamp = pindexLast->GetAncestor(height - N); + previousTimestamp = blockPreviousTimestamp->GetBlockTime(); // Loop through N most recent blocks. - for (int i = height - N; i < height; i++) { + for (int64_t i = height - N + 1; i <= height; i++) { const CBlockIndex* block = pindexLast->GetAncestor(i); - const CBlockIndex* block_Prev = block->GetAncestor(i - 1); - int64_t solvetime = block->GetBlockTime() - block_Prev->GetBlockTime(); - if (limit_st && solvetime > 6 * T) { - solvetime = 6 * T; - } + // Prevent solvetimes from being negative in a safe way. It must be done like this. + // Do not attempt anything like if (solvetime < 1) {solvetime=1;} + // The +1 ensures new coins do not calculate nextTarget = 0. + thisTimestamp = (block->GetBlockTime() > previousTimestamp) ? block->GetBlockTime() : previousTimestamp + 1; + // 6*T limit prevents large drops in diff from long solvetimes which would cause oscillations. + int64_t solvetime = std::min(6 * T, thisTimestamp - previousTimestamp); + + // The following is part of "preventing negative solvetimes". + previousTimestamp = thisTimestamp; + + // Give linearly higher weight to more recent solvetimes. j++; - t += solvetime * j; // Weighted solvetime sum. + sumWeightedSolvetimes += solvetime * j; - // Target sum divided by a factor, (k N^2). - // The factor is a part of the final equation. However we divide sum_target here to avoid - // potential overflow. arith_uint256 target; target.SetCompact(block->nBits); - sum_target += target / (k * N * N); - } - // Keep t reasonable in case strange solvetimes occurred. - if (t < N * k / dnorm) { - t = N * k / dnorm; + avgTarget += target / N / k; // Dividing by k here prevents an overflow below. } - const arith_uint256 pow_limit = UintToArith256(params.powLimit); - arith_uint256 next_target = t * sum_target; - if (next_target > pow_limit) { - next_target = pow_limit; - } + // Desired equation in next line was nextTarget = avgTarget * sumWeightSolvetimes / k + // but 1/k was moved to line above to prevent overflow in new coins + nextTarget = avgTarget * sumWeightedSolvetimes; + + if (nextTarget > powLimit) { nextTarget = powLimit; } - return next_target.GetCompact(); + return nextTarget.GetCompact(); } bool CheckProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params& params) diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index c593c4b98b2ac..77d6db820e931 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -52,10 +52,10 @@ static UniValue GetNetworkHashPS(int lookup, int height) { // If lookup is -1, then use difficulty averaging window. if (lookup <= 0) { - if (::ChainActive().Height() < Params().GetConsensus().nZawyLWMAHeight) + if (::ChainActive().Height() < Params().GetConsensus().nLwmaForkHeight) lookup = Params().GetConsensus().nDigishieldAveragingWindow; else - lookup = Params().GetConsensus().nZawyLwmaAveragingWindow; + lookup = Params().GetConsensus().nLwmaAveragingWindow; } // If lookup is larger than chain, then set it to chain length. diff --git a/src/timedata.h b/src/timedata.h index 172e834a415f2..d354933db4c53 100644 --- a/src/timedata.h +++ b/src/timedata.h @@ -11,7 +11,13 @@ #include #include -static const int64_t DEFAULT_MAX_TIME_ADJUSTMENT = 35 * 60; +/** + * Based on: https://github.com/zcash/zcash/issues/4021 + * Following the reduction of MAX_FUTURE_BLOCK_TIME to 45 * 600 / 20 = 1350 + * DEFAULT_MAX_TIME_ADJUSTMENT is set to MAX_FUTURE_BLOCK_TIME / 2 + * (Bitcoin original value: 70 * 60) +*/ +static const int64_t DEFAULT_MAX_TIME_ADJUSTMENT = 675; class CNetAddr;