zawy12 / difficulty-algorithms

See the Issues for difficulty algorithms
MIT License
107 stars 25 forks source link

Simple EMA difficulty algorithm #21

Open zawy12 opened 6 years ago

zawy12 commented 6 years ago

This is probably better than 95% of all difficulty algorithms currently in use. This has half as many delays and blocks lost to big miners as Digishield. It's a few steps above a simple moving average. See EMA-Z for full discussion of EMA math.

Email me at zawy@yahoo.com before you go to testnet to show me your code. If you have a public api send me link to it so that it can be included in the Difficulty Watch page.

Cryptonote coin need to apply the Jagerman MTP Patch You can read his summary of it here and full background and description is here. All Cryptonote coins need to do this ASAP. It does not require a fork.

Cryptonote coins might use the following (I'll edit this later after someone has told me it works or fails in testnet):

// Simple EMA difficulty
// Copyright (c) 2018 Zawy 
// https://github.com/zawy12/difficulty-algorithms/issues/21
// N=28 chosen to be same speed as LWMA N=60 and 30% faster than Digishield
// EMA math by Jacob Eliosoff and Tom Harding
// const uint64_t CRYPTONOTE_BLOCK_FUTURE_TIME_LIMIT   = 3xT;  // (360 for T=120 seconds)
// const size_t   BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW  = 11;
// const size_t   DIFFICULTY_WINDOW  = 28+1; 
// Difficulty must be > 100 and < 1E13.

difficulty_type next_difficulty(std::vector<std::uint64_t> timestamps, 
    std::vector<difficulty_type> cumulative_difficulties) {

// For readability and portability, clone vectors 
vector<T> TS(timestamps);
vector<T> CD(cumulative_difficulties);

// Startup
uint64_t initial_difficulty_guess = 100;
if ( timestamps.size() < 2 ) { return initial_difficulty_guess; }

// Suggestion for forks if new hash rate < 1/10 of old hash rate.
// if (height < fork_height +2 ) { return initial_difficulty_guess; }

// ST must be signed.
int64_t N = DIFFICULTY_WINDOW - 1; 
int64_t T  = DIFFICULTY_TARGET*0.982; // seconds
// The following cast results in a disaster after fork if done with doubles
int64_t ST = static_cast<int64_t>(TS.back()) - static_cast<int64_t>(TS[TS.size()-2]) ; 
int64_t D  = CD.back() - CD[CD.size()-2];

// Limit allowable solvetimes to help prevent oscillations and manipulations.
ST = std::max( -5*T, std::min( ST, 6*T));

// Do the magic.
int64_t next_D = (D*N*T)/(N*T-T+ST);   

return static_cast<uint64_t>(next_D);
}

Similarity to Digishield's tempered SMA

Just out of mathematical interest, re-arranging Digishield's math gives: next_D = avg(17 D) * 4 / ( 3 + avg(17 ST)/T) The simplified EMA with a similar speed of response is next_D = prev_D * 36 / ( 35 + prev_ST/T)