mirror of
https://github.com/wownero/wownero.git
synced 2026-10-24 10:58:33 +02:00
added LWMA
This commit is contained in:
@@ -33,6 +33,7 @@
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
#include <boost/math/special_functions/round.hpp>
|
||||
|
||||
#include "common/int-util.h"
|
||||
#include "crypto/hash.h"
|
||||
@@ -162,4 +163,81 @@ namespace cryptonote {
|
||||
return (low + time_span - 1) / time_span;
|
||||
}
|
||||
|
||||
// LWMA difficulty algorithm
|
||||
// Background: https://github.com/zawy12/difficulty-algorithms/issues/3
|
||||
// Copyright (c) 2017-2018 Zawy (pseudocode)
|
||||
// MIT license http://www.opensource.org/licenses/mit-license.php
|
||||
// Copyright (c) 2018 Wownero Inc., a Monero Enterprise Alliance partner company
|
||||
// Copyright (c) 2018 The Karbowanec developers (initial code)
|
||||
// Copyright (c) 2018 Haven Protocol (refinements)
|
||||
// Degnr8, Karbowanec, Masari, Bitcoin Gold, Bitcoin Candy, and Haven have contributed.
|
||||
|
||||
// This algorithm is: next_difficulty = harmonic_mean(Difficulties) * T / LWMA(Solvetimes)
|
||||
// The harmonic_mean(Difficulties) = 1/average(Targets) so it is also:
|
||||
// next_target = avg(Targets) * LWMA(Solvetimes) / T.
|
||||
// This is "the best algorithm" because it has lowest root-mean-square error between
|
||||
// needed & actual difficulty during hash attacks while having the lowest standard
|
||||
// deviation during stable hashrate. That is, it's the fastest for a given stability and vice versa.
|
||||
// Do not use "if solvetime < 1 then solvetime = 1" which allows a catastrophic exploit.
|
||||
// Do not sort timestamps. "Solvetimes" and "LWMA" variables must allow negatives.
|
||||
// Do not use MTP as most recent block. Do not use (POW)Limits, filtering, or tempering.
|
||||
// Do not forget to set N (aka DIFFICULTY_WINDOW in Cryptonote) to recommendation below.
|
||||
// The nodes' future time limit (FTL) aka CRYPTONOTE_BLOCK_FUTURE_TIME_LIMIT needs to
|
||||
// be reduced from 60*60*2 to 500 seconds to prevent timestamp manipulation from miner's with
|
||||
// > 50% hash power. If this is too small, it can be increased to 1000 at a cost in protection.
|
||||
|
||||
// Cryptonote clones: #define DIFFICULTY_BLOCKS_COUNT_V2 DIFFICULTY_WINDOW_V2 + 1
|
||||
|
||||
|
||||
difficulty_type next_difficulty_v2(std::vector<std::uint64_t> timestamps, std::vector<difficulty_type> cumulative_difficulties, size_t target_seconds) {
|
||||
|
||||
const int64_t T = static_cast<int64_t>(target_seconds);
|
||||
|
||||
size_t N = DIFFICULTY_WINDOW_V2;
|
||||
|
||||
// Return a difficulty of 1 for first 3 blocks if it's the start of the chain.
|
||||
if (timestamps.size() < 4) {
|
||||
return 1;
|
||||
}
|
||||
// Otherwise, use a smaller N if the start of the chain is less than N+1.
|
||||
else if ( timestamps.size() < N+1 ) {
|
||||
N = timestamps.size() - 1;
|
||||
}
|
||||
// Otherwise make sure timestamps and cumulative_difficulties are correct size.
|
||||
else {
|
||||
timestamps.resize(N+1);
|
||||
cumulative_difficulties.resize(N+1);
|
||||
}
|
||||
// To get an average solvetime to within +/- ~0.1%, use an adjustment factor.
|
||||
// adjust=0.999 for 80 < N < 120(?)
|
||||
const double adjust = 0.998;
|
||||
// The divisor k normalizes the LWMA sum to a standard LWMA.
|
||||
const double k = N * (N + 1) / 2;
|
||||
|
||||
double LWMA(0), sum_inverse_D(0), harmonic_mean_D(0), nextDifficulty(0);
|
||||
int64_t solveTime(0);
|
||||
uint64_t difficulty(0), next_difficulty(0);
|
||||
|
||||
// Loop through N most recent blocks. N is most recently solved block.
|
||||
for (size_t i = 1; i <= N; i++) {
|
||||
solveTime = static_cast<int64_t>(timestamps[i]) - static_cast<int64_t>(timestamps[i - 1]);
|
||||
solveTime = std::min<int64_t>((T * 7), std::max<int64_t>(solveTime, (-7 * T)));
|
||||
difficulty = cumulative_difficulties[i] - cumulative_difficulties[i - 1];
|
||||
LWMA += solveTime * i / k;
|
||||
sum_inverse_D += 1 / static_cast<double>(difficulty);
|
||||
}
|
||||
|
||||
harmonic_mean_D = N / sum_inverse_D;
|
||||
|
||||
// Keep LWMA sane in case something unforeseen occurs.
|
||||
if (static_cast<int64_t>(boost::math::round(LWMA)) < T / 20)
|
||||
LWMA = static_cast<double>(T / 20);
|
||||
|
||||
nextDifficulty = harmonic_mean_D * T / LWMA * adjust;
|
||||
|
||||
// No limits should be employed, but this is correct way to employ a 20% symmetrical limit:
|
||||
// nextDifficulty=max(previous_Difficulty*0.8,min(previous_Difficulty/0.8, next_Difficulty));
|
||||
next_difficulty = static_cast<uint64_t>(nextDifficulty);
|
||||
return next_difficulty;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user