Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LWMA difficulty adjustment algorithm #28

Merged
merged 1 commit into from
Nov 19, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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