difficulty is fun

This commit is contained in:
wowario 2023-01-30 22:56:07 +03:00
parent aa7564806d
commit 2ddaa7835c
No known key found for this signature in database
GPG Key ID: 793504B449C69220
4 changed files with 280 additions and 29 deletions

View File

@ -33,6 +33,7 @@
#include <cstddef> #include <cstddef>
#include <cstdint> #include <cstdint>
#include <vector> #include <vector>
#include <boost/math/special_functions/round.hpp>
#include "int-util.h" #include "int-util.h"
#include "crypto/hash.h" #include "crypto/hash.h"
@ -121,10 +122,10 @@ namespace cryptonote {
uint64_t next_difficulty_64(std::vector<std::uint64_t> timestamps, std::vector<uint64_t> cumulative_difficulties, size_t target_seconds) { uint64_t next_difficulty_64(std::vector<std::uint64_t> timestamps, std::vector<uint64_t> cumulative_difficulties, size_t target_seconds) {
if(timestamps.size() > DIFFICULTY_WINDOW) if(timestamps.size() > DIFFICULTY_WINDOW_V3)
{ {
timestamps.resize(DIFFICULTY_WINDOW); timestamps.resize(DIFFICULTY_WINDOW_V3);
cumulative_difficulties.resize(DIFFICULTY_WINDOW); cumulative_difficulties.resize(DIFFICULTY_WINDOW_V3);
} }
@ -133,17 +134,17 @@ namespace cryptonote {
if (length <= 1) { if (length <= 1) {
return 1; return 1;
} }
static_assert(DIFFICULTY_WINDOW >= 2, "Window is too small"); static_assert(DIFFICULTY_WINDOW_V3 >= 2, "Window is too small");
assert(length <= DIFFICULTY_WINDOW); assert(length <= DIFFICULTY_WINDOW_V3);
sort(timestamps.begin(), timestamps.end()); sort(timestamps.begin(), timestamps.end());
size_t cut_begin, cut_end; size_t cut_begin, cut_end;
static_assert(2 * DIFFICULTY_CUT <= DIFFICULTY_WINDOW - 2, "Cut length is too large"); static_assert(2 * DIFFICULTY_CUT_V2 <= DIFFICULTY_WINDOW_V3 - 2, "Cut length is too large");
if (length <= DIFFICULTY_WINDOW - 2 * DIFFICULTY_CUT) { if (length <= DIFFICULTY_WINDOW_V3 - 2 * DIFFICULTY_CUT_V2) {
cut_begin = 0; cut_begin = 0;
cut_end = length; cut_end = length;
} else { } else {
cut_begin = (length - (DIFFICULTY_WINDOW - 2 * DIFFICULTY_CUT) + 1) / 2; cut_begin = (length - (DIFFICULTY_WINDOW_V3 - 2 * DIFFICULTY_CUT_V2) + 1) / 2;
cut_end = cut_begin + (DIFFICULTY_WINDOW - 2 * DIFFICULTY_CUT); cut_end = cut_begin + (DIFFICULTY_WINDOW_V3 - 2 * DIFFICULTY_CUT_V2);
} }
assert(/*cut_begin >= 0 &&*/ cut_begin + 2 <= cut_end && cut_end <= length); assert(/*cut_begin >= 0 &&*/ cut_begin + 2 <= cut_end && cut_end <= length);
uint64_t time_span = timestamps[cut_end - 1] - timestamps[cut_begin]; uint64_t time_span = timestamps[cut_end - 1] - timestamps[cut_begin];
@ -200,7 +201,7 @@ namespace cryptonote {
return check_hash_128(hash, difficulty); return check_hash_128(hash, difficulty);
} }
difficulty_type next_difficulty(std::vector<uint64_t> timestamps, std::vector<difficulty_type> cumulative_difficulties, size_t target_seconds) { difficulty_type next_difficulty(std::vector<uint64_t> timestamps, std::vector<difficulty_type> cumulative_difficulties, size_t target_seconds, uint64_t HEIGHT) {
//cutoff DIFFICULTY_LAG //cutoff DIFFICULTY_LAG
if(timestamps.size() > DIFFICULTY_WINDOW) if(timestamps.size() > DIFFICULTY_WINDOW)
{ {
@ -214,6 +215,8 @@ namespace cryptonote {
if (length <= 1) { if (length <= 1) {
return 1; return 1;
} }
// reset difficulty for solo mining to 100 million
if (HEIGHT <= 331170 + DIFFICULTY_WINDOW && HEIGHT >= 331170) { return 100000000; }
static_assert(DIFFICULTY_WINDOW >= 2, "Window is too small"); static_assert(DIFFICULTY_WINDOW >= 2, "Window is too small");
assert(length <= DIFFICULTY_WINDOW); assert(length <= DIFFICULTY_WINDOW);
sort(timestamps.begin(), timestamps.end()); sort(timestamps.begin(), timestamps.end());
@ -254,4 +257,193 @@ namespace cryptonote {
return "0x" + s; return "0x" + s;
} }
// LWMA difficulty algorithm
// Background: https://github.com/zawy12/difficulty-algorithms/issues/3
// Copyright (c) 2017-2018 Zawy
difficulty_type next_difficulty_v2(std::vector<uint64_t> timestamps, std::vector<difficulty_type> cumulative_difficulties, size_t target_seconds, uint64_t HEIGHT) {
const int64_t T = static_cast<int64_t>(target_seconds);
size_t N = DIFFICULTY_WINDOW_V2;
if (timestamps.size() < 4) {
return 1;
} else if ( timestamps.size() < N+1 ) {
N = timestamps.size() - 1;
} else {
timestamps.resize(N+1);
cumulative_difficulties.resize(N+1);
}
const double adjust = 0.998;
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);
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 = static_cast<uint64_t>(cumulative_difficulties[i] - cumulative_difficulties[i - 1]);
LWMA += (int64_t)(solveTime * i) / k;
sum_inverse_D += 1 / static_cast<double>(difficulty);
}
harmonic_mean_D = N / sum_inverse_D;
if (static_cast<int64_t>(boost::math::round(LWMA)) < T / 20)
LWMA = static_cast<double>(T / 20);
nextDifficulty = harmonic_mean_D * T / LWMA * adjust;
next_difficulty = static_cast<uint64_t>(nextDifficulty);
return next_difficulty;
}
// LWMA-2
difficulty_type next_difficulty_v3(std::vector<uint64_t> timestamps, std::vector<difficulty_type> cumulative_difficulties, uint64_t HEIGHT) {
int64_t T = DIFFICULTY_TARGET_V2;
int64_t N = DIFFICULTY_WINDOW_V2;
int64_t L(0), ST, sum_3_ST(0), next_D, prev_D;
assert(timestamps.size() == cumulative_difficulties.size() && timestamps.size() <= static_cast<uint64_t>(N+1) );
for ( int64_t i = 1; i <= N; i++ ) {
ST = static_cast<int64_t>(timestamps[i]) - static_cast<int64_t>(timestamps[i-1]);
ST = std::max(-4*T, std::min(ST, 6*T));
L += ST * i ;
if ( i > N-3 ) {
sum_3_ST += ST;
}
}
next_D = (static_cast<int64_t>(cumulative_difficulties[N] - cumulative_difficulties[0])*T*(N+1)*99)/(100*2*L);
prev_D = static_cast<int64_t>(cumulative_difficulties[N] - cumulative_difficulties[N-1]);
next_D = std::max((prev_D*67)/100, std::min(next_D, (prev_D*150)/100));
if ( sum_3_ST < (8*T)/10) {
next_D = std::max(next_D,(prev_D*108)/100);
}
return static_cast<uint64_t>(next_D);
}
// LWMA-4
difficulty_type next_difficulty_v4(std::vector<uint64_t> timestamps, std::vector<difficulty_type> cumulative_difficulties, uint64_t HEIGHT) {
uint64_t T = DIFFICULTY_TARGET_V2;
uint64_t N = DIFFICULTY_WINDOW_V2;
uint64_t L(0), ST(0), next_D, prev_D, avg_D, i;
assert(timestamps.size() == cumulative_difficulties.size() && timestamps.size() <= N+1 );
if (HEIGHT <= 63469 + 1) { return 100000069; }
std::vector<uint64_t>TS(N+1);
TS[0] = timestamps[0];
for ( i = 1; i <= N; i++) {
if ( timestamps[i] > TS[i-1] ) { TS[i] = timestamps[i]; }
else { TS[i] = TS[i-1]; }
}
for ( i = 1; i <= N; i++) {
if ( i > 4 && TS[i]-TS[i-1] > 5*T && TS[i-1] - TS[i-4] < (14*T)/10 ) { ST = 2*T; }
else if ( i > 7 && TS[i]-TS[i-1] > 5*T && TS[i-1] - TS[i-7] < 4*T ) { ST = 2*T; }
else {
ST = std::min(5*T ,TS[i] - TS[i-1]);
}
L += ST * i ;
}
if (L < N*N*T/20 ) { L = N*N*T/20; }
avg_D = static_cast<uint64_t>(( cumulative_difficulties[N] - cumulative_difficulties[0] )/ N);
if (avg_D > 2000000*N*N*T) {
next_D = (avg_D/(200*L))*(N*(N+1)*T*97);
}
else { next_D = (avg_D*N*(N+1)*T*97)/(200*L); }
prev_D = static_cast<uint64_t>(cumulative_difficulties[N] - cumulative_difficulties[N-1]);
if ( ( TS[N] - TS[N-1] < (2*T)/10 ) ||
( TS[N] - TS[N-2] < (5*T)/10 ) ||
( TS[N] - TS[N-3] < (8*T)/10 ) )
{
next_D = std::max( next_D, std::min( (prev_D*110)/100, (105*avg_D)/100 ) );
}
i = 1000000000;
while (i > 1) {
if ( next_D > i*100 ) { next_D = ((next_D+i/2)/i)*i; break; }
else { i /= 10; }
}
if ( next_D > 100000 ) {
next_D = ((next_D+500)/1000)*1000 + std::min(static_cast<uint64_t>(999), (TS[N]-TS[N-10])/10);
}
return static_cast<uint64_t>(next_D);
}
// LWMA-1 difficulty algorithm
// Copyright (c) 2017-2019 Zawy, MIT License
// https://github.com/zawy12/difficulty-algorithms/issues/3
difficulty_type next_difficulty_v5(std::vector<uint64_t> timestamps, std::vector<difficulty_type> cumulative_difficulties, uint64_t HEIGHT) {
uint64_t T = DIFFICULTY_TARGET_V2;
uint64_t N = DIFFICULTY_WINDOW_V3;
assert(timestamps.size() == cumulative_difficulties.size() && timestamps.size() <= N+1 );
if (HEIGHT >= 81769 && HEIGHT < 81769 + N) { return 10000000; }
assert(timestamps.size() == N+1);
// hardcoding previously erroneously calculated difficulty entries
if(HEIGHT == 307686) return 25800000;
if(HEIGHT == 307692) return 1890000;
if(HEIGHT == 307735) return 17900000;
if(HEIGHT == 307742) return 21300000;
if(HEIGHT == 307750) return 10900000;
if(HEIGHT == 307766) return 2960000;
uint64_t i, this_timestamp(0), previous_timestamp(0);
difficulty_type L(0), next_D, avg_D;
previous_timestamp = timestamps[0]-T;
for ( i = 1; i <= N; i++) {
// Safely prevent out-of-sequence timestamps
if ( timestamps[i] > previous_timestamp ) { this_timestamp = timestamps[i]; }
else { this_timestamp = previous_timestamp+1; }
L += i*std::min(6*T ,this_timestamp - previous_timestamp);
previous_timestamp = this_timestamp;
}
if (L < N*N*T/20 ) { L = N*N*T/20; }
avg_D = ( cumulative_difficulties[N] - cumulative_difficulties[0] )/ N;
// Prevent round off error for small D and overflow for large D.
if (avg_D > 2000000*N*N*T && HEIGHT < 307800) {
next_D = (avg_D/(200*L))*(N*(N+1)*T*99);
}
else if (avg_D > uint64_t(-1)/(N*(N+1)*T*99) && HEIGHT > 307800) {
next_D = (avg_D/(200*L))*(N*(N+1)*T*99);
}
else { next_D = (avg_D*N*(N+1)*T*99)/(200*L); }
// Make all insignificant digits zero for easy reading.
i = 1000000000;
while (i > 1) {
if ( next_D > i*100 ) { next_D = ((next_D+i/2)/i)*i; break; }
else { i /= 10; }
}
return next_D;
}
difficulty_type next_difficulty_v6(std::vector<uint64_t> timestamps, std::vector<difficulty_type> cumulative_difficulties, size_t target_seconds) {
if(timestamps.size() > DIFFICULTY_WINDOW_V3)
{
timestamps.resize(DIFFICULTY_WINDOW_V3);
cumulative_difficulties.resize(DIFFICULTY_WINDOW_V3);
}
size_t length = timestamps.size();
assert(length == cumulative_difficulties.size());
if (length <= 1) {
return 1;
}
static_assert(DIFFICULTY_WINDOW_V3 >= 2, "Window is too small");
assert(length <= DIFFICULTY_WINDOW_V3);
sort(timestamps.begin(), timestamps.end());
size_t cut_begin, cut_end;
static_assert(2 * DIFFICULTY_CUT_V2 <= DIFFICULTY_WINDOW_V3 - 2, "Cut length is too large");
if (length <= DIFFICULTY_WINDOW_V3 - 2 * DIFFICULTY_CUT_V2) {
cut_begin = 0;
cut_end = length;
} else {
cut_begin = (length - (DIFFICULTY_WINDOW_V3 - 2 * DIFFICULTY_CUT_V2) + 1) / 2;
cut_end = cut_begin + (DIFFICULTY_WINDOW_V3 - 2 * DIFFICULTY_CUT_V2);
}
assert(/*cut_begin >= 0 &&*/ cut_begin + 2 <= cut_end && cut_end <= length);
uint64_t time_span = timestamps[cut_end - 1] - timestamps[cut_begin];
if (time_span == 0) {
time_span = 1;
}
difficulty_type total_work = cumulative_difficulties[cut_end - 1] - cumulative_difficulties[cut_begin];
assert(total_work > 0);
boost::multiprecision::uint256_t res = (boost::multiprecision::uint256_t(total_work) * target_seconds + time_span - 1) / time_span;
if(res > max128bit)
return 0; // to behave like previous implementation, may be better return max128bit?
return res.convert_to<difficulty_type>();
}
} }

View File

@ -57,7 +57,12 @@ namespace cryptonote
bool check_hash_128(const crypto::hash &hash, difficulty_type difficulty); bool check_hash_128(const crypto::hash &hash, difficulty_type difficulty);
bool check_hash(const crypto::hash &hash, difficulty_type difficulty); bool check_hash(const crypto::hash &hash, difficulty_type difficulty);
difficulty_type next_difficulty(std::vector<std::uint64_t> timestamps, std::vector<difficulty_type> cumulative_difficulties, size_t target_seconds); difficulty_type next_difficulty(std::vector<std::uint64_t> timestamps, std::vector<difficulty_type> cumulative_difficulties, size_t target_seconds, uint64_t HEIGHT);
difficulty_type next_difficulty_v2(std::vector<std::uint64_t> timestamps, std::vector<difficulty_type> cumulative_difficulties, size_t target_seconds, uint64_t HEIGHT);
difficulty_type next_difficulty_v3(std::vector<std::uint64_t> timestamps, std::vector<difficulty_type> cumulative_difficulties, uint64_t HEIGHT);
difficulty_type next_difficulty_v4(std::vector<std::uint64_t> timestamps, std::vector<difficulty_type> cumulative_difficulties, uint64_t HEIGHT);
difficulty_type next_difficulty_v5(std::vector<std::uint64_t> timestamps, std::vector<difficulty_type> cumulative_difficulties, uint64_t HEIGHT);
difficulty_type next_difficulty_v6(std::vector<std::uint64_t> timestamps, std::vector<difficulty_type> cumulative_difficulties, size_t target_seconds);
std::string hex(difficulty_type v); std::string hex(difficulty_type v);
} }

View File

@ -85,8 +85,13 @@
#define DIFFICULTY_WINDOW_V3 144 #define DIFFICULTY_WINDOW_V3 144
#define DIFFICULTY_WINDOW_V2 60 #define DIFFICULTY_WINDOW_V2 60
#define DIFFICULTY_WINDOW 720 // blocks #define DIFFICULTY_WINDOW 720 // blocks
#define DIFFICULTY_LAG_V2 3
#define DIFFICULTY_LAG 15 // !!! #define DIFFICULTY_LAG 15 // !!!
#define DIFFICULTY_CUT_V2 12
#define DIFFICULTY_CUT 60 // timestamps to cut after sorting #define DIFFICULTY_CUT 60 // timestamps to cut after sorting
#define DIFFICULTY_BLOCKS_COUNT_V4 DIFFICULTY_WINDOW_V3 + DIFFICULTY_LAG_V2
#define DIFFICULTY_BLOCKS_COUNT_V3 DIFFICULTY_WINDOW_V3 + 1
#define DIFFICULTY_BLOCKS_COUNT_V2 DIFFICULTY_WINDOW_V2 + 1
#define DIFFICULTY_BLOCKS_COUNT DIFFICULTY_WINDOW + DIFFICULTY_LAG #define DIFFICULTY_BLOCKS_COUNT DIFFICULTY_WINDOW + DIFFICULTY_LAG

View File

@ -897,17 +897,19 @@ start:
// pop the oldest one from the list. This only requires 1x read per height instead // pop the oldest one from the list. This only requires 1x read per height instead
// of doing 735 (DIFFICULTY_BLOCKS_COUNT). // of doing 735 (DIFFICULTY_BLOCKS_COUNT).
bool check = false; bool check = false;
uint8_t version = get_current_hard_fork_version();
uint64_t difficulty_blocks_count = version >= 20 ? DIFFICULTY_BLOCKS_COUNT_V4 : version <= 17 && version >= 11 ? DIFFICULTY_BLOCKS_COUNT_V3 : version <= 10 && version >= 8 ? DIFFICULTY_BLOCKS_COUNT_V2 : DIFFICULTY_BLOCKS_COUNT;
if (m_reset_timestamps_and_difficulties_height) if (m_reset_timestamps_and_difficulties_height)
m_timestamps_and_difficulties_height = 0; m_timestamps_and_difficulties_height = 0;
if (m_timestamps_and_difficulties_height != 0 && ((height - m_timestamps_and_difficulties_height) == 1) && m_timestamps.size() >= DIFFICULTY_BLOCKS_COUNT) if (m_timestamps_and_difficulties_height != 0 && ((height - m_timestamps_and_difficulties_height) == 1) && m_timestamps.size() >= difficulty_blocks_count)
{ {
uint64_t index = height - 1; uint64_t index = height - 1;
m_timestamps.push_back(m_db->get_block_timestamp(index)); m_timestamps.push_back(m_db->get_block_timestamp(index));
m_difficulties.push_back(m_db->get_block_cumulative_difficulty(index)); m_difficulties.push_back(m_db->get_block_cumulative_difficulty(index));
while (m_timestamps.size() > DIFFICULTY_BLOCKS_COUNT) while (m_timestamps.size() > difficulty_blocks_count)
m_timestamps.erase(m_timestamps.begin()); m_timestamps.erase(m_timestamps.begin());
while (m_difficulties.size() > DIFFICULTY_BLOCKS_COUNT) while (m_difficulties.size() > difficulty_blocks_count)
m_difficulties.erase(m_difficulties.begin()); m_difficulties.erase(m_difficulties.begin());
m_timestamps_and_difficulties_height = height; m_timestamps_and_difficulties_height = height;
@ -920,7 +922,7 @@ start:
std::vector<difficulty_type> difficulties_from_cache = difficulties; std::vector<difficulty_type> difficulties_from_cache = difficulties;
{ {
uint64_t offset = height - std::min <uint64_t> (height, static_cast<uint64_t>(DIFFICULTY_BLOCKS_COUNT)); uint64_t offset = height - std::min <uint64_t> (height, static_cast<uint64_t>(difficulty_blocks_count));
if (offset == 0) if (offset == 0)
++offset; ++offset;
@ -966,7 +968,21 @@ start:
} }
size_t target = get_difficulty_target(); size_t target = get_difficulty_target();
difficulty_type diff = next_difficulty(timestamps, difficulties, target); uint64_t HEIGHT = m_db->height();
difficulty_type diff;
if (version >= 20) {
diff = next_difficulty_v6(timestamps, difficulties, target);
} else if (version <= 17 && version >= 11) {
diff = next_difficulty_v5(timestamps, difficulties, HEIGHT);
} else if (version == 10) {
diff = next_difficulty_v4(timestamps, difficulties, HEIGHT);
} else if (version == 9) {
diff = next_difficulty_v3(timestamps, difficulties, HEIGHT);
} else if (version == 8) {
diff = next_difficulty_v2(timestamps, difficulties, target, HEIGHT);
} else {
diff = next_difficulty(timestamps, difficulties, target, HEIGHT);
}
CRITICAL_REGION_LOCAL1(m_difficulty_lock); CRITICAL_REGION_LOCAL1(m_difficulty_lock);
m_difficulty_for_next_block_top_hash = top_hash; m_difficulty_for_next_block_top_hash = top_hash;
@ -1025,11 +1041,13 @@ size_t Blockchain::recalculate_difficulties(boost::optional<uint64_t> start_heig
std::vector<uint64_t> timestamps; std::vector<uint64_t> timestamps;
std::vector<difficulty_type> difficulties; std::vector<difficulty_type> difficulties;
timestamps.reserve(DIFFICULTY_BLOCKS_COUNT + 1); uint8_t version = get_current_hard_fork_version();
difficulties.reserve(DIFFICULTY_BLOCKS_COUNT + 1); uint64_t difficulty_blocks_count = version >= 20 ? DIFFICULTY_BLOCKS_COUNT_V4 : version <= 17 && version >= 11 ? DIFFICULTY_BLOCKS_COUNT_V3 : version <= 10 && version >= 8 ? DIFFICULTY_BLOCKS_COUNT_V2 : DIFFICULTY_BLOCKS_COUNT;
timestamps.reserve(difficulty_blocks_count + 1);
difficulties.reserve(difficulty_blocks_count + 1);
if (start_height > 1) if (start_height > 1)
{ {
for (uint64_t i = 0; i < DIFFICULTY_BLOCKS_COUNT; ++i) for (uint64_t i = 0; i < difficulty_blocks_count; ++i)
{ {
uint64_t height = start_height - 1 - i; uint64_t height = start_height - 1 - i;
if (height == 0) if (height == 0)
@ -1044,7 +1062,21 @@ size_t Blockchain::recalculate_difficulties(boost::optional<uint64_t> start_heig
for (uint64_t height = start_height; height <= top_height; ++height) for (uint64_t height = start_height; height <= top_height; ++height)
{ {
size_t target = get_ideal_hard_fork_version(height) < 2 ? DIFFICULTY_TARGET_V1 : DIFFICULTY_TARGET_V2; size_t target = get_ideal_hard_fork_version(height) < 2 ? DIFFICULTY_TARGET_V1 : DIFFICULTY_TARGET_V2;
difficulty_type recalculated_diff = next_difficulty(timestamps, difficulties, target); uint64_t HEIGHT = m_db->height();
difficulty_type recalculated_diff;
if (version >= 20) {
recalculated_diff = next_difficulty_v6(timestamps, difficulties, target);
} else if (version <= 17 && version >= 11) {
recalculated_diff = next_difficulty_v5(timestamps, difficulties, HEIGHT);
} else if (version == 10) {
recalculated_diff = next_difficulty_v4(timestamps, difficulties, HEIGHT);
} else if (version == 9) {
recalculated_diff = next_difficulty_v3(timestamps, difficulties, HEIGHT);
} else if (version == 8) {
recalculated_diff = next_difficulty_v2(timestamps, difficulties, target, HEIGHT);
} else {
recalculated_diff = next_difficulty(timestamps, difficulties, target, HEIGHT);
}
boost::multiprecision::uint256_t recalculated_cum_diff_256 = boost::multiprecision::uint256_t(recalculated_diff) + last_cum_diff; boost::multiprecision::uint256_t recalculated_cum_diff_256 = boost::multiprecision::uint256_t(recalculated_diff) + last_cum_diff;
CHECK_AND_ASSERT_THROW_MES(recalculated_cum_diff_256 <= std::numeric_limits<difficulty_type>::max(), "Difficulty overflow!"); CHECK_AND_ASSERT_THROW_MES(recalculated_cum_diff_256 <= std::numeric_limits<difficulty_type>::max(), "Difficulty overflow!");
@ -1072,9 +1104,9 @@ size_t Blockchain::recalculate_difficulties(boost::optional<uint64_t> start_heig
timestamps.push_back(m_db->get_block_timestamp(height)); timestamps.push_back(m_db->get_block_timestamp(height));
difficulties.push_back(recalculated_cum_diff); difficulties.push_back(recalculated_cum_diff);
} }
if (timestamps.size() > DIFFICULTY_BLOCKS_COUNT) if (timestamps.size() > difficulty_blocks_count)
{ {
CHECK_AND_ASSERT_THROW_MES(timestamps.size() == DIFFICULTY_BLOCKS_COUNT + 1, "Wrong timestamps size: " << timestamps.size()); CHECK_AND_ASSERT_THROW_MES(timestamps.size() == difficulty_blocks_count + 1, "Wrong timestamps size: " << timestamps.size());
timestamps.erase(timestamps.begin()); timestamps.erase(timestamps.begin());
difficulties.erase(difficulties.begin()); difficulties.erase(difficulties.begin());
} }
@ -1299,16 +1331,18 @@ difficulty_type Blockchain::get_next_difficulty_for_alternative_chain(const std:
LOG_PRINT_L3("Blockchain::" << __func__); LOG_PRINT_L3("Blockchain::" << __func__);
std::vector<uint64_t> timestamps; std::vector<uint64_t> timestamps;
std::vector<difficulty_type> cumulative_difficulties; std::vector<difficulty_type> cumulative_difficulties;
uint8_t version = get_current_hard_fork_version();
uint64_t difficulty_blocks_count = version >= 20 ? DIFFICULTY_BLOCKS_COUNT_V4 : version <= 17 && version >= 11 ? DIFFICULTY_BLOCKS_COUNT_V3 : version <= 10 && version >= 8 ? DIFFICULTY_BLOCKS_COUNT_V2 : DIFFICULTY_BLOCKS_COUNT;
// if the alt chain isn't long enough to calculate the difficulty target // if the alt chain isn't long enough to calculate the difficulty target
// based on its blocks alone, need to get more blocks from the main chain // based on its blocks alone, need to get more blocks from the main chain
if(alt_chain.size()< DIFFICULTY_BLOCKS_COUNT) if(alt_chain.size()< difficulty_blocks_count)
{ {
CRITICAL_REGION_LOCAL(m_blockchain_lock); CRITICAL_REGION_LOCAL(m_blockchain_lock);
// Figure out start and stop offsets for main chain blocks // Figure out start and stop offsets for main chain blocks
size_t main_chain_stop_offset = alt_chain.size() ? alt_chain.front().height : bei.height; size_t main_chain_stop_offset = alt_chain.size() ? alt_chain.front().height : bei.height;
size_t main_chain_count = DIFFICULTY_BLOCKS_COUNT - std::min(static_cast<size_t>(DIFFICULTY_BLOCKS_COUNT), alt_chain.size()); size_t main_chain_count = difficulty_blocks_count - std::min(static_cast<size_t>(difficulty_blocks_count), alt_chain.size());
main_chain_count = std::min(main_chain_count, main_chain_stop_offset); main_chain_count = std::min(main_chain_count, main_chain_stop_offset);
size_t main_chain_start_offset = main_chain_stop_offset - main_chain_count; size_t main_chain_start_offset = main_chain_stop_offset - main_chain_count;
@ -1323,7 +1357,7 @@ difficulty_type Blockchain::get_next_difficulty_for_alternative_chain(const std:
} }
// make sure we haven't accidentally grabbed too many blocks...maybe don't need this check? // make sure we haven't accidentally grabbed too many blocks...maybe don't need this check?
CHECK_AND_ASSERT_MES((alt_chain.size() + timestamps.size()) <= DIFFICULTY_BLOCKS_COUNT, false, "Internal error, alt_chain.size()[" << alt_chain.size() << "] + vtimestampsec.size()[" << timestamps.size() << "] NOT <= DIFFICULTY_WINDOW[]" << DIFFICULTY_BLOCKS_COUNT); CHECK_AND_ASSERT_MES((alt_chain.size() + timestamps.size()) <= difficulty_blocks_count, false, "Internal error, alt_chain.size()[" << alt_chain.size() << "] + vtimestampsec.size()[" << timestamps.size() << "] NOT <= DIFFICULTY_WINDOW[]" << difficulty_blocks_count);
for (const auto &bei : alt_chain) for (const auto &bei : alt_chain)
{ {
@ -1335,8 +1369,8 @@ difficulty_type Blockchain::get_next_difficulty_for_alternative_chain(const std:
// and timestamps from it alone // and timestamps from it alone
else else
{ {
timestamps.resize(static_cast<size_t>(DIFFICULTY_BLOCKS_COUNT)); timestamps.resize(static_cast<size_t>(difficulty_blocks_count));
cumulative_difficulties.resize(static_cast<size_t>(DIFFICULTY_BLOCKS_COUNT)); cumulative_difficulties.resize(static_cast<size_t>(difficulty_blocks_count));
size_t count = 0; size_t count = 0;
size_t max_i = timestamps.size()-1; size_t max_i = timestamps.size()-1;
// get difficulties and timestamps from most recent blocks in alt chain // get difficulties and timestamps from most recent blocks in alt chain
@ -1345,7 +1379,7 @@ difficulty_type Blockchain::get_next_difficulty_for_alternative_chain(const std:
timestamps[max_i - count] = bei.bl.timestamp; timestamps[max_i - count] = bei.bl.timestamp;
cumulative_difficulties[max_i - count] = bei.cumulative_difficulty; cumulative_difficulties[max_i - count] = bei.cumulative_difficulty;
count++; count++;
if(count >= DIFFICULTY_BLOCKS_COUNT) if(count >= difficulty_blocks_count)
break; break;
} }
} }
@ -1354,7 +1388,22 @@ difficulty_type Blockchain::get_next_difficulty_for_alternative_chain(const std:
size_t target = get_ideal_hard_fork_version(bei.height) < 2 ? DIFFICULTY_TARGET_V1 : DIFFICULTY_TARGET_V2; size_t target = get_ideal_hard_fork_version(bei.height) < 2 ? DIFFICULTY_TARGET_V1 : DIFFICULTY_TARGET_V2;
// calculate the difficulty target for the block and return it // calculate the difficulty target for the block and return it
return next_difficulty(timestamps, cumulative_difficulties, target); uint64_t HEIGHT = m_db->height();
difficulty_type next_diff;
if (version >= 20) {
next_diff = next_difficulty_v6(timestamps, cumulative_difficulties, target);
} else if (version <= 17 && version >= 11) {
next_diff = next_difficulty_v5(timestamps, cumulative_difficulties, HEIGHT);
} else if (version == 10) {
next_diff = next_difficulty_v4(timestamps, cumulative_difficulties, HEIGHT);
} else if (version == 9) {
next_diff = next_difficulty_v3(timestamps, cumulative_difficulties, HEIGHT);
} else if (version == 8) {
next_diff = next_difficulty_v2(timestamps, cumulative_difficulties, target, HEIGHT);
} else {
next_diff = next_difficulty(timestamps, cumulative_difficulties, target, HEIGHT);
}
return next_diff;
} }
//------------------------------------------------------------------ //------------------------------------------------------------------
// This function does a sanity check on basic things that all miner // This function does a sanity check on basic things that all miner