diff --git a/src/cryptonote_basic/cryptonote_format_utils.cpp b/src/cryptonote_basic/cryptonote_format_utils.cpp index c91c5d315ca4eb7659e890c1a60e0beb1eb88843..e92ad59f91c725900628a6aab87673c1de5c6920 100644 --- a/src/cryptonote_basic/cryptonote_format_utils.cpp +++ b/src/cryptonote_basic/cryptonote_format_utils.cpp @@ -1229,6 +1229,8 @@ namespace cryptonote { switch (b.major_version) { + case 16: + return get_block_longhash_v13(b, res, height, bc); case 14: return get_block_longhash_v13(b, res, height, bc); case 13: diff --git a/src/cryptonote_basic/difficulty.cpp b/src/cryptonote_basic/difficulty.cpp index dac0893eb2971f830a68be86d92df016a5f0f627..9ad70af370bdd670b0e9a7899e7fcafba47a8691 100644 --- a/src/cryptonote_basic/difficulty.cpp +++ b/src/cryptonote_basic/difficulty.cpp @@ -126,12 +126,12 @@ namespace cryptonote { return !carry; } - difficulty_type next_difficulty(std::vector timestamps, std::vector cumulative_difficulties, size_t target_seconds) { + difficulty_type next_difficulty_v1(std::vector timestamps, std::vector cumulative_difficulties, size_t target_seconds) { - if(timestamps.size() > DIFFICULTY_WINDOW) + if(timestamps.size() > DIFFICULTY_WINDOW_V1) { - timestamps.resize(DIFFICULTY_WINDOW); - cumulative_difficulties.resize(DIFFICULTY_WINDOW); + timestamps.resize(DIFFICULTY_WINDOW_V1); + cumulative_difficulties.resize(DIFFICULTY_WINDOW_V1); } @@ -140,17 +140,17 @@ namespace cryptonote { if (length <= 1) { return 1; } - static_assert(DIFFICULTY_WINDOW >= 2, "Window is too small"); - assert(length <= DIFFICULTY_WINDOW); + static_assert(DIFFICULTY_WINDOW_V1 >= 2, "Window is too small"); + assert(length <= DIFFICULTY_WINDOW_V1); sort(timestamps.begin(), timestamps.end()); size_t cut_begin, cut_end; - static_assert(2 * DIFFICULTY_CUT <= DIFFICULTY_WINDOW - 2, "Cut length is too large"); - if (length <= DIFFICULTY_WINDOW - 2 * DIFFICULTY_CUT) { + static_assert(2 * DIFFICULTY_CUT_V1 <= DIFFICULTY_WINDOW_V1 - 2, "Cut length is too large"); + if (length <= DIFFICULTY_WINDOW_V1 - 2 * DIFFICULTY_CUT_V1) { cut_begin = 0; cut_end = length; } else { - cut_begin = (length - (DIFFICULTY_WINDOW - 2 * DIFFICULTY_CUT) + 1) / 2; - cut_end = cut_begin + (DIFFICULTY_WINDOW - 2 * DIFFICULTY_CUT); + cut_begin = (length - (DIFFICULTY_WINDOW_V1 - 2 * DIFFICULTY_CUT_V1) + 1) / 2; + cut_end = cut_begin + (DIFFICULTY_WINDOW_V1 - 2 * DIFFICULTY_CUT_V1); } assert(/*cut_begin >= 0 &&*/ cut_begin + 2 <= cut_end && cut_end <= length); uint64_t time_span = timestamps[cut_end - 1] - timestamps[cut_begin]; @@ -264,7 +264,7 @@ namespace cryptonote { t=T*N/2 if t < T*N/2 # in case of startup weirdness, keep t reasonable next_D = d * k / t */ - difficulty_type next_difficulty_v3(std::vector timestamps, std::vector cumulative_difficulties, size_t target_seconds, bool v4) { + difficulty_type next_difficulty_v3(std::vector timestamps, std::vector cumulative_difficulties, size_t target_seconds) { if (timestamps.size() > DIFFICULTY_BLOCKS_COUNT_V3) { @@ -281,45 +281,81 @@ namespace cryptonote { uint64_t weighted_timespans = 0; uint64_t target; - if (v4 == true) { - uint64_t previous_max = timestamps[0]; - for (size_t i = 1; i < length; i++) { - uint64_t timespan; - uint64_t max_timestamp; + // adjust = 0.99 for N=60, leaving the + 1 for now as it's not affecting N + target = 99 * (((length + 1) / 2) * target_seconds) / 100; + for (size_t i = 1; i < length; i++) { + uint64_t timespan; + if (timestamps[i - 1] >= timestamps[i]) { + timespan = 1; + } else { + timespan = timestamps[i] - timestamps[i - 1]; + } + if (timespan > 10 * target_seconds) { + timespan = 10 * target_seconds; + } + weighted_timespans += i * timespan; + } + target = ((length + 1) / 2) * target_seconds; - if (timestamps[i] > previous_max) { - max_timestamp = timestamps[i]; - } else { - max_timestamp = previous_max; - } + uint64_t minimum_timespan = target_seconds * length / 2; + if (weighted_timespans < minimum_timespan) { + weighted_timespans = minimum_timespan; + } - timespan = max_timestamp - previous_max; - if (timespan == 0) { - timespan = 1; - } else if (timespan > 10 * target_seconds) { - timespan = 10 * target_seconds; - } + difficulty_type total_work = cumulative_difficulties.back() - cumulative_difficulties.front(); + assert(total_work > 0); - weighted_timespans += i * timespan; - previous_max = max_timestamp; + uint64_t low, high; + mul(total_work, target, low, high); + if (high != 0) { + return 0; + } + if (low < weighted_timespans) { + return 1; + } + return low / weighted_timespans; + } + + difficulty_type next_difficulty_v4(std::vector timestamps, std::vector cumulative_difficulties, size_t target_seconds) { + + if (timestamps.size() > DIFFICULTY_BLOCKS_COUNT_V3) + { + timestamps.resize(DIFFICULTY_BLOCKS_COUNT_V3); + cumulative_difficulties.resize(DIFFICULTY_BLOCKS_COUNT_V3); + } + + size_t length = timestamps.size(); + assert(length == cumulative_difficulties.size()); + if (length <= 1) { + return 1; + } + + uint64_t weighted_timespans = 0; + uint64_t target; + + uint64_t previous_max = timestamps[0]; + for (size_t i = 1; i < length; i++) { + uint64_t timespan; + uint64_t max_timestamp; + + if (timestamps[i] > previous_max) { + max_timestamp = timestamps[i]; + } else { + max_timestamp = previous_max; } - // adjust = 0.99 for N=60, leaving the + 1 for now as it's not affecting N - target = 99 * (((length + 1) / 2) * target_seconds) / 100; - } else { - for (size_t i = 1; i < length; i++) { - uint64_t timespan; - if (timestamps[i - 1] >= timestamps[i]) { - timespan = 1; - } else { - timespan = timestamps[i] - timestamps[i - 1]; - } - if (timespan > 10 * target_seconds) { - timespan = 10 * target_seconds; - } - weighted_timespans += i * timespan; + + timespan = max_timestamp - previous_max; + if (timespan == 0) { + timespan = 1; + } else if (timespan > 10 * target_seconds) { + timespan = 10 * target_seconds; } - target = ((length + 1) / 2) * target_seconds; + + weighted_timespans += i * timespan; + previous_max = max_timestamp; } + // adjust = 0.99 for N=60, leaving the + 1 for now as it's not affecting N + target = 99 * (((length + 1) / 2) * target_seconds) / 100; uint64_t minimum_timespan = target_seconds * length / 2; if (weighted_timespans < minimum_timespan) { @@ -340,6 +376,7 @@ namespace cryptonote { return low / weighted_timespans; } + // LWMA difficulty algorithm // Background: https://github.com/zawy12/difficulty-algorithms/issues/3 // Copyright (c) 2017-2018 Zawy (pseudocode) @@ -366,6 +403,62 @@ namespace cryptonote { // Cryptonote clones: #define DIFFICULTY_BLOCKS_COUNT_V2 DIFFICULTY_WINDOW_V2 + 1 + difficulty_type next_difficulty_v5(std::vector timestamps, std::vector cumulative_difficulties, size_t target_seconds) { + + const int64_t T = static_cast(target_seconds); + size_t N = DIFFICULTY_WINDOW_V5; + int64_t FTL = static_cast(CRYPTONOTE_BLOCK_FUTURE_TIME_LIMIT_V6); + + // 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.998 for N = 60 + 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(timestamps[i]) - static_cast(timestamps[i - 1]); + solveTime = std::min((T * 10), std::max(solveTime, -FTL)); + difficulty = cumulative_difficulties[i] - cumulative_difficulties[i - 1]; + LWMA += (int64_t)(solveTime * i) / k; + sum_inverse_D += 1 / static_cast(difficulty); + } + + harmonic_mean_D = N / sum_inverse_D; + + // Limit LWMA same as Bitcoin's 1/4 in case something unforeseen occurs. + if (static_cast(boost::math::round(LWMA)) < T / 4) + LWMA = static_cast(T / 4); + + 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(nextDifficulty); + + if (next_difficulty == 0) { + return 1; + } + + return next_difficulty; + } difficulty_type next_difficulty_v6(std::vector timestamps, std::vector cumulative_difficulties, size_t target_seconds) { const int64_t T = static_cast(target_seconds); diff --git a/src/cryptonote_basic/difficulty.h b/src/cryptonote_basic/difficulty.h index 4f831b81774473a00cef65613573e457134205d6..560f7837c31e8eebb782fa3b395334572e6f5b3d 100644 --- a/src/cryptonote_basic/difficulty.h +++ b/src/cryptonote_basic/difficulty.h @@ -54,8 +54,10 @@ namespace cryptonote */ bool check_hash(const crypto::hash &hash, difficulty_type difficulty); + difficulty_type next_difficulty_v1(std::vector timestamps, std::vector cumulative_difficulties, size_t target_seconds); difficulty_type next_difficulty_v2(std::vector timestamps, std::vector cumulative_difficulties, size_t target_seconds); - difficulty_type next_difficulty(std::vector timestamps, std::vector cumulative_difficulties, size_t target_seconds); - difficulty_type next_difficulty_v3(std::vector timestamps, std::vector cumulative_difficulties, size_t target_seconds, bool v4); + difficulty_type next_difficulty_v3(std::vector timestamps, std::vector cumulative_difficulties, size_t target_seconds); + difficulty_type next_difficulty_v4(std::vector timestamps, std::vector cumulative_difficulties, size_t target_seconds); + difficulty_type next_difficulty_v5(std::vector timestamps, std::vector cumulative_difficulties, size_t target_seconds); difficulty_type next_difficulty_v6(std::vector timestamps, std::vector cumulative_difficulties, size_t target_seconds); } diff --git a/src/cryptonote_config.h b/src/cryptonote_config.h index 794e4253a59e0b17d0dbf62739017baebc674e2a..c41260eed720eacf55730d5bea2075549fa3bf07 100644 --- a/src/cryptonote_config.h +++ b/src/cryptonote_config.h @@ -87,28 +87,27 @@ #define DYNAMIC_FEE_PER_KB_BASE_BLOCK_REWARD ((uint64_t)100000000) // 10 * pow(10,12) #define DIFFICULTY_TARGET_V1 60 // seconds -#define DIFFICULTY_TARGET_V2 20 // seconds (after v16) -#define DIFFICULTY_WINDOW 720 // blocks -#define DIFFICULTY_LAG 15 // !!! -#define DIFFICULTY_CUT 60 // timestamps to cut after sorting -#define DIFFICULTY_BLOCKS_COUNT DIFFICULTY_WINDOW + DIFFICULTY_LAG - -#define UNCLE_DIFFICULTY_TARGET DIFFICULTY_TARGET_V2/4 -#define UNCLE_REWARD_RATIO 2 -#define NEPHEW_REWARD_RATIO 20 -#define UNCLE_MINING_FORK_HEIGHT 15 - +#define DIFFICULTY_TARGET_V2 20 // seconds (after v15) +#define DIFFICULTY_WINDOW_V1 720 // blocks +#define DIFFICULTY_LAG_V1 15 // !!! +#define DIFFICULTY_CUT_V1 60 // timestamps to cut after sorting +#define DIFFICULTY_BLOCKS_COUNT_V1 DIFFICULTY_WINDOW_V1 + DIFFICULTY_LAG_V1 #define DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN DIFFICULTY_TARGET_V1 //just alias; used by tests #define DIFFICULTY_WINDOW_V2 17 #define DIFFICULTY_CUT_V2 6 #define DIFFICULTY_BLOCKS_COUNT_V2 DIFFICULTY_WINDOW_V2 + DIFFICULTY_CUT_V2*2 - #define DIFFICULTY_WINDOW_V3 60 #define DIFFICULTY_BLOCKS_COUNT_V3 DIFFICULTY_WINDOW_V3 - -#define DIFFICULTY_WINDOW_V6 60 +#define DIFFICULTY_WINDOW_V5 60 +#define DIFFICULTY_BLOCKS_COUNT_V5 DIFFICULTY_WINDOW_V5 + 1 +#define DIFFICULTY_WINDOW_V6 180 #define DIFFICULTY_BLOCKS_COUNT_V6 DIFFICULTY_WINDOW_V6 + 1 +#define UNCLE_DIFFICULTY_TARGET DIFFICULTY_TARGET_V2 / 4 +#define UNCLE_REWARD_RATIO 2 +#define NEPHEW_REWARD_RATIO 20 +#define UNCLE_MINING_FORK_HEIGHT 15 + #define CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS_V1 DIFFICULTY_TARGET_V1 * CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_BLOCKS #define CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS_V2 DIFFICULTY_TARGET_V2 * CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_BLOCKS #define CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_BLOCKS 1 diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 0060e2d50a0318764a0d4f239ea758ec12408514..e6c79d97035dede1961e0b3e2bdb997aeaca675e 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -106,6 +106,7 @@ static const struct { { 13, 81001, 0, 1546179019 }, { 14, 88001, 0, 1546602163 }, { 15, 227001, 0, 1554902709 }, + { 16, 277001, 0, 1555950611 }, }; static const struct { @@ -129,8 +130,7 @@ static const struct { { 13, 160, 0, 1546396236 }, { 14, 170, 0, 1546602163 }, { 15, 180, 0, 1546701111 }, - { 16, 1460, 0, 1546801111 }, - { 17, 5300, 0, 1546901111 }, + { 16, 190, 0, 1546801111 }, }; static const struct { @@ -989,11 +989,13 @@ difficulty_type Blockchain::get_difficulty_for_next_block() size_t difficulty_blocks_count; uint8_t version = get_current_hard_fork_version(); if (version == 1) { - difficulty_blocks_count = DIFFICULTY_BLOCKS_COUNT; + difficulty_blocks_count = DIFFICULTY_BLOCKS_COUNT_V1; } else if (version == 2) { difficulty_blocks_count = DIFFICULTY_BLOCKS_COUNT_V2; - } else if (version < 6) { + } else if (version >= 3 && version <= 5 ) { difficulty_blocks_count = DIFFICULTY_BLOCKS_COUNT_V3; + } else if (version >= 6 && version <= 15) { + difficulty_blocks_count = DIFFICULTY_BLOCKS_COUNT_V5; } else { difficulty_blocks_count = DIFFICULTY_BLOCKS_COUNT_V6; } @@ -1038,13 +1040,15 @@ difficulty_type Blockchain::get_difficulty_for_next_block() } size_t target = get_current_hard_fork_version() < BLOCK_TARGET_FORK_HEIGHT ? DIFFICULTY_TARGET_V1 : DIFFICULTY_TARGET_V2; if (version == 1) { - return next_difficulty(timestamps, difficulties, target); + return next_difficulty_v1(timestamps, difficulties, target); } else if (version == 2) { return next_difficulty_v2(timestamps, difficulties, target); } else if (version == 3) { - return next_difficulty_v3(timestamps, difficulties, target, false); - } else if (version < 6) { - return next_difficulty_v3(timestamps, difficulties, target, true); + return next_difficulty_v3(timestamps, difficulties, target); + } else if (version >= 3 && version <= 5) { + return next_difficulty_v4(timestamps, difficulties, target); + } else if (version >= 6 && version <= 15) { + return next_difficulty_v5(timestamps, difficulties, target); } else { return next_difficulty_v6(timestamps, difficulties, target); } @@ -1226,11 +1230,13 @@ difficulty_type Blockchain::get_next_difficulty_for_alternative_chain(const std: size_t difficulty_blocks_count; uint8_t version = get_current_hard_fork_version(); if (version == 1) { - difficulty_blocks_count = DIFFICULTY_BLOCKS_COUNT; + difficulty_blocks_count = DIFFICULTY_BLOCKS_COUNT_V1; } else if (version == 2) { difficulty_blocks_count = DIFFICULTY_BLOCKS_COUNT_V2; - } else if (version < 6) { + } else if (version >= 3 && version <= 5) { difficulty_blocks_count = DIFFICULTY_BLOCKS_COUNT_V3; + } else if (version >= 6 && version <= 15) { + difficulty_blocks_count = DIFFICULTY_BLOCKS_COUNT_V5; } else { difficulty_blocks_count = DIFFICULTY_BLOCKS_COUNT_V6; } @@ -1290,13 +1296,15 @@ difficulty_type Blockchain::get_next_difficulty_for_alternative_chain(const std: // calculate the difficulty target for the block and return it if (version == 1) { - return next_difficulty(timestamps, cumulative_difficulties, target); + return next_difficulty_v1(timestamps, cumulative_difficulties, target); } else if (version == 2) { return next_difficulty_v2(timestamps, cumulative_difficulties, target); } else if (version == 3) { - return next_difficulty_v3(timestamps, cumulative_difficulties, target, false); - } else if (version < 6) { - return next_difficulty_v3(timestamps, cumulative_difficulties, target, true); + return next_difficulty_v3(timestamps, cumulative_difficulties, target); + } else if (version == 4 || version == 5) { + return next_difficulty_v4(timestamps, cumulative_difficulties, target); + } else if (version >= 6 && version <= 15) { + return next_difficulty_v5(timestamps, cumulative_difficulties, target); } else { return next_difficulty_v6(timestamps, cumulative_difficulties, target); } diff --git a/src/version.cpp.in b/src/version.cpp.in index a79cbde9713c37007c5d08578d78a1c54dbe513b..8f954fb33f58355f3a67dde1e32136561001fd2b 100644 --- a/src/version.cpp.in +++ b/src/version.cpp.in @@ -1,5 +1,5 @@ #define DEF_MONERO_VERSION_TAG "@VERSIONTAG@" -#define DEF_MONERO_VERSION "1.0.3.5" +#define DEF_MONERO_VERSION "1.0.3.6" #define DEF_MONERO_RELEASE_NAME "Han" #define DEF_MONERO_VERSION_FULL DEF_MONERO_VERSION "-" DEF_MONERO_VERSION_TAG