diff --git a/src/cryptonote_basic/difficulty.cpp b/src/cryptonote_basic/difficulty.cpp index 2965afdef..440c2fec7 100644 --- a/src/cryptonote_basic/difficulty.cpp +++ b/src/cryptonote_basic/difficulty.cpp @@ -28,247 +28,6 @@ // // Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers -#include -#include -#include -#include -#include - -#include "int-util.h" -#include "crypto/hash.h" -#include "cryptonote_config.h" -#include "difficulty.h" - -#undef MONERO_DEFAULT_LOG_CATEGORY -#define MONERO_DEFAULT_LOG_CATEGORY "difficulty" - -namespace cryptonote { - - using std::size_t; - using std::uint64_t; - using std::vector; - -#if defined(__x86_64__) - static inline void mul(uint64_t a, uint64_t b, uint64_t &low, uint64_t &high) { - low = mul128(a, b, &high); - } - -#else - - static inline void mul(uint64_t a, uint64_t b, uint64_t &low, uint64_t &high) { - // __int128 isn't part of the standard, so the previous function wasn't portable. mul128() in Windows is fine, - // but this portable function should be used elsewhere. Credit for this function goes to latexi95. - - uint64_t aLow = a & 0xFFFFFFFF; - uint64_t aHigh = a >> 32; - uint64_t bLow = b & 0xFFFFFFFF; - uint64_t bHigh = b >> 32; - - uint64_t res = aLow * bLow; - uint64_t lowRes1 = res & 0xFFFFFFFF; - uint64_t carry = res >> 32; - - res = aHigh * bLow + carry; - uint64_t highResHigh1 = res >> 32; - uint64_t highResLow1 = res & 0xFFFFFFFF; - - res = aLow * bHigh; - uint64_t lowRes2 = res & 0xFFFFFFFF; - carry = res >> 32; - - res = aHigh * bHigh + carry; - uint64_t highResHigh2 = res >> 32; - uint64_t highResLow2 = res & 0xFFFFFFFF; - - //Addition - - uint64_t r = highResLow1 + lowRes2; - carry = r >> 32; - low = (r << 32) | lowRes1; - r = highResHigh1 + highResLow2 + carry; - uint64_t d3 = r & 0xFFFFFFFF; - carry = r >> 32; - r = highResHigh2 + carry; - high = d3 | (r << 32); - } - -#endif - - static inline bool cadd(uint64_t a, uint64_t b) { - return a + b < a; - } - - static inline bool cadc(uint64_t a, uint64_t b, bool c) { - return a + b < a || (c && a + b == (uint64_t) -1); - } - - bool check_hash_64(const crypto::hash &hash, uint64_t difficulty) { - uint64_t low, high, top, cur; - // First check the highest word, this will most likely fail for a random hash. - mul(swap64le(((const uint64_t *) &hash)[3]), difficulty, top, high); - if (high != 0) { - return false; - } - mul(swap64le(((const uint64_t *) &hash)[0]), difficulty, low, cur); - mul(swap64le(((const uint64_t *) &hash)[1]), difficulty, low, high); - bool carry = cadd(cur, low); - cur = high; - mul(swap64le(((const uint64_t *) &hash)[2]), difficulty, low, high); - carry = cadc(cur, low, carry); - carry = cadc(high, top, carry); - return !carry; - } - - uint64_t next_difficulty_64(std::vector timestamps, std::vector cumulative_difficulties, size_t target_seconds) { - - if(timestamps.size() > DIFFICULTY_WINDOW) - { - timestamps.resize(DIFFICULTY_WINDOW); - cumulative_difficulties.resize(DIFFICULTY_WINDOW); - } - - - size_t length = timestamps.size(); - assert(length == cumulative_difficulties.size()); - if (length <= 1) { - return 1; - } - static_assert(DIFFICULTY_WINDOW >= 2, "Window is too small"); - assert(length <= DIFFICULTY_WINDOW); - 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) { - 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); - } - 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; - } - uint64_t total_work = cumulative_difficulties[cut_end - 1] - cumulative_difficulties[cut_begin]; - assert(total_work > 0); - uint64_t low, high; - mul(total_work, target_seconds, low, high); - // blockchain errors "difficulty overhead" if this function returns zero. - // TODO: consider throwing an exception instead - if (high != 0 || low + time_span - 1 < low) { - return 0; - } - return (low + time_span - 1) / time_span; - } - -#if defined(_MSC_VER) -#ifdef max -#undef max -#endif -#endif - - const difficulty_type max64bit(std::numeric_limits::max()); - const boost::multiprecision::uint256_t max128bit(std::numeric_limits::max()); - const boost::multiprecision::uint512_t max256bit(std::numeric_limits::max()); - -#define FORCE_FULL_128_BITS - - bool check_hash_128(const crypto::hash &hash, difficulty_type difficulty) { -#ifndef FORCE_FULL_128_BITS - // fast check - if (difficulty >= max64bit && ((const uint64_t *) &hash)[3] > 0) - return false; -#endif - // usual slow check - boost::multiprecision::uint512_t hashVal = 0; -#ifdef FORCE_FULL_128_BITS - for(int i = 0; i < 4; i++) { // highest word is zero -#else - for(int i = 1; i < 4; i++) { // highest word is zero -#endif - hashVal <<= 64; - hashVal |= swap64le(((const uint64_t *) &hash)[3 - i]); - } - return hashVal * difficulty <= max256bit; - } - - bool check_hash(const crypto::hash &hash, difficulty_type difficulty) { - if (difficulty <= max64bit) // if can convert to small difficulty - do it - return check_hash_64(hash, difficulty.convert_to()); - else - return check_hash_128(hash, difficulty); - } - - difficulty_type next_difficulty(std::vector timestamps, std::vector cumulative_difficulties, size_t target_seconds) { - //cutoff DIFFICULTY_LAG - if(timestamps.size() > DIFFICULTY_WINDOW) - { - timestamps.resize(DIFFICULTY_WINDOW); - cumulative_difficulties.resize(DIFFICULTY_WINDOW); - } - - - size_t length = timestamps.size(); - assert(length == cumulative_difficulties.size()); - if (length <= 1) { - return 1; - } - static_assert(DIFFICULTY_WINDOW >= 2, "Window is too small"); - assert(length <= DIFFICULTY_WINDOW); - 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) { - 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); - } - 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(); - } - - // Copyright (c) 2014-2023, The Monero Project -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without modification, are -// permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this list of -// conditions and the following disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright notice, this list -// of conditions and the following disclaimer in the documentation and/or other -// materials provided with the distribution. -// -// 3. Neither the name of the copyright holder nor the names of its contributors may be -// used to endorse or promote products derived from this software without specific -// prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF -// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers - #include #include #include @@ -494,7 +253,7 @@ namespace cryptonote { // N=45, 55, 70, 90, 120 for T=600, 240, 120, 90, and 60 const int64_t T = static_cast(target_seconds); - size_t N = DIFFICULTY_WINDOW_V2; + size_t N = DIFFICULTY_WINDOW; if (timestamps.size() > N) { timestamps.resize(N + 1); @@ -502,18 +261,18 @@ namespace cryptonote { } size_t n = timestamps.size(); assert(n == cumulative_difficulties.size()); - assert(n <= DIFFICULTY_WINDOW_V2); + assert(n <= DIFFICULTY_WINDOW); // If new coin, just "give away" first 5 blocks at low difficulty if ( n < 6 ) { return 1; } // If height "n" is from 6 to N, then reset N to n-1. else if (n < N+1) { N=n-1; } - + // To get an average solvetime to within +/- ~0.1%, use an adjustment factor. // adjust=0.99 for 90 < N < 130 const long double adjust = 0.998; // The divisor k normalizes LWMA. const long double k = N * (N + 1) / 2; - + long double LWMA(0), sum_inverse_D(0), harmonic_mean_D(0), nextDifficulty(0); int64_t solveTime(0); uint64_t difficulty(0), next_difficulty(0); @@ -537,7 +296,7 @@ namespace cryptonote { return next_difficulty; } - + std::string hex(difficulty_type v) { static const char chars[] = "0123456789abcdef";