added LWMA

This commit is contained in:
wowario
2018-09-18 00:55:51 +03:00
parent 328b7be391
commit 2c959a9b21
5 changed files with 126 additions and 15 deletions
+78
View File
@@ -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;
}
}