Skip to content

Commit

Permalink
Merge devel branch #28
Browse files Browse the repository at this point in the history
LWMA difficulty adjustment algorithm
  • Loading branch information
MarkLTZ authored Nov 19, 2020
2 parents ed3cc9c + e73b023 commit 3a1fe07
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 58 deletions.
11 changes: 9 additions & 2 deletions src/chain.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
18 changes: 9 additions & 9 deletions src/chainparams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
14 changes: 6 additions & 8 deletions src/consensus/params.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
79 changes: 43 additions & 36 deletions src/pow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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)
Expand Down
4 changes: 2 additions & 2 deletions src/rpc/mining.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
8 changes: 7 additions & 1 deletion src/timedata.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,13 @@
#include <stdint.h>
#include <vector>

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;

Expand Down

0 comments on commit 3a1fe07

Please sign in to comment.