|
33 | 33 | #include <cstddef> |
34 | 34 | #include <cstdint> |
35 | 35 | #include <vector> |
| 36 | +#include <boost/math/special_functions/round.hpp> |
36 | 37 |
|
37 | 38 | #include "common/int-util.h" |
38 | 39 | #include "crypto/hash.h" |
@@ -185,7 +186,6 @@ namespace cryptonote { |
185 | 186 | // > 50% hash power. If this is too small, it can be increased to 1000 at a cost in protection. |
186 | 187 | // Cryptonote clones: #define DIFFICULTY_BLOCKS_COUNT_V2 DIFFICULTY_WINDOW_V2 + 1 |
187 | 188 | // difficulty_type should be uint64_t |
188 | | - |
189 | 189 | difficulty_type next_difficulty_V8(std::vector<std::uint64_t> timestamps,std::vector<difficulty_type> cumulative_difficulties, uint64_t block_height) { |
190 | 190 | int64_t T = DIFFICULTY_TARGET_V8; // target solvetime seconds |
191 | 191 | int64_t N = DIFFICULTY_WINDOW_V8; // N=45, 60, and 90 for T=600, 120, 60. |
@@ -224,4 +224,78 @@ return static_cast<uint64_t>(next_D); |
224 | 224 | // next_Target = sumTargets*L*2/0.998/T/(N+1)/N/N; // To show the difference. |
225 | 225 | } |
226 | 226 |
|
| 227 | + |
| 228 | + |
| 229 | + |
| 230 | + |
| 231 | + |
| 232 | + |
| 233 | +// LWMA difficulty algorithm |
| 234 | +// Background: https://github.com/zawy12/difficulty-algorithms/issues/3 |
| 235 | +// Copyright (c) 2017-2018 Zawy (pseudocode) |
| 236 | +// MIT license http://www.opensource.org/licenses/mit-license.php |
| 237 | +// Copyright (c) 2018 The Stellite Project |
| 238 | +// Copyright (c) 2018 The Masari Project (10x for quicker recoveries, minimum to be symmetric with FTL) |
| 239 | +// Copyright (c) 2018 Wownero Inc., a Monero Enterprise Alliance partner company |
| 240 | +// Copyright (c) 2018 The Karbowanec developers (initial code) |
| 241 | +// Copyright (c) 2018 Haven Protocol (refinements) |
| 242 | +// Degnr8, Karbowanec, Masari, Bitcoin Gold, Bitcoin Candy, and Haven have contributed. |
| 243 | +// This algorithm is: next_difficulty = harmonic_mean(Difficulties) * T / LWMA(Solvetimes) |
| 244 | +// The harmonic_mean(Difficulties) = 1/average(Targets) so it is also: |
| 245 | +// next_target = avg(Targets) * LWMA(Solvetimes) / T. |
| 246 | +// This is "the best algorithm" because it has lowest root-mean-square error between |
| 247 | +// needed & actual difficulty during hash attacks while having the lowest standard |
| 248 | +// deviation during stable hashrate. That is, it's the fastest for a given stability and vice versa. |
| 249 | +// Do not use "if solvetime < 1 then solvetime = 1" which allows a catastrophic exploit. |
| 250 | +// Do not sort timestamps. "Solvetimes" and "LWMA" variables must allow negatives. |
| 251 | +// Do not use MTP as most recent block. Do not use (POW)Limits, filtering, or tempering. |
| 252 | +// Do not forget to set N (aka DIFFICULTY_WINDOW in Cryptonote) to recommendation below. |
| 253 | +// The nodes' future time limit (FTL) aka CRYPTONOTE_BLOCK_FUTURE_TIME_LIMIT needs to |
| 254 | +// be reduced from 60*60*2 to 500 seconds to prevent timestamp manipulation from miner's with |
| 255 | +// > 50% hash power. If this is too small, it can be increased to 1000 at a cost in protection. |
| 256 | +difficulty_type next_difficulty_V9(std::vector<std::uint64_t> timestamps, std::vector<difficulty_type> cumulative_difficulties, size_t target_seconds) { |
| 257 | + const int64_t T = static_cast<int64_t>(target_seconds); |
| 258 | + size_t N = DIFFICULTY_WINDOW_V9; |
| 259 | + int64_t FTL = static_cast<int64_t>(CRYPTONOTE_BLOCK_FUTURE_TIME_LIMIT_V9); |
| 260 | + // Return a difficulty of 1 for first 3 blocks if it's the start of the chain. |
| 261 | + if (timestamps.size() < 4) { |
| 262 | + return 1; |
| 263 | + } |
| 264 | + // Otherwise, use a smaller N if the start of the chain is less than N+1. |
| 265 | + else if ( timestamps.size() < N+1 ) { |
| 266 | + N = timestamps.size() - 1; |
| 267 | + } |
| 268 | + // Otherwise make sure timestamps and cumulative_difficulties are correct size. |
| 269 | + else { |
| 270 | + timestamps.resize(N+1); |
| 271 | + cumulative_difficulties.resize(N+1); |
| 272 | + } |
| 273 | + // To get an average solvetime to within +/- ~0.1%, use an adjustment factor. |
| 274 | + // adjust=0.998 for N = 60 |
| 275 | + const double adjust = 0.998; |
| 276 | + // The divisor k normalizes the LWMA sum to a standard LWMA. |
| 277 | + const double k = N * (N + 1) / 2; |
| 278 | + double LWMA(0), sum_inverse_D(0), harmonic_mean_D(0), nextDifficulty(0); |
| 279 | + int64_t solveTime(0); |
| 280 | + uint64_t difficulty(0), next_difficulty(0); |
| 281 | + // Loop through N most recent blocks. N is most recently solved block. |
| 282 | + for (size_t i = 1; i <= N; i++) { |
| 283 | + solveTime = static_cast<int64_t>(timestamps[i]) - static_cast<int64_t>(timestamps[i - 1]); |
| 284 | + solveTime = std::min<int64_t>((T * 10), std::max<int64_t>(solveTime, -FTL)); |
| 285 | + difficulty = cumulative_difficulties[i] - cumulative_difficulties[i - 1]; |
| 286 | + LWMA += (int64_t)(solveTime * i) / k; |
| 287 | + sum_inverse_D += 1 / static_cast<double>(difficulty); |
| 288 | + } |
| 289 | + harmonic_mean_D = N / sum_inverse_D; |
| 290 | + // Limit LWMA same as Bitcoin's 1/4 in case something unforeseen occurs. |
| 291 | + if (static_cast<int64_t>(boost::math::round(LWMA)) < T / 4) |
| 292 | + LWMA = static_cast<double>(T / 4); |
| 293 | + nextDifficulty = harmonic_mean_D * T / LWMA * adjust; |
| 294 | + // No limits should be employed, but this is correct way to employ a 20% symmetrical limit: |
| 295 | + // nextDifficulty=max(previous_Difficulty*0.8,min(previous_Difficulty/0.8, next_Difficulty)); |
| 296 | + next_difficulty = static_cast<uint64_t>(nextDifficulty); |
| 297 | + return next_difficulty; |
| 298 | +} |
| 299 | + |
| 300 | + |
227 | 301 | } |
0 commit comments