diff options
Diffstat (limited to 'src/cryptonote_basic')
-rw-r--r-- | src/cryptonote_basic/cryptonote_boost_serialization.h | 29 | ||||
-rw-r--r-- | src/cryptonote_basic/cryptonote_format_utils.cpp | 55 | ||||
-rw-r--r-- | src/cryptonote_basic/cryptonote_format_utils.h | 4 | ||||
-rw-r--r-- | src/cryptonote_basic/difficulty.cpp | 83 | ||||
-rw-r--r-- | src/cryptonote_basic/difficulty.h | 7 | ||||
-rw-r--r-- | src/cryptonote_basic/miner.cpp | 5 |
6 files changed, 169 insertions, 14 deletions
diff --git a/src/cryptonote_basic/cryptonote_boost_serialization.h b/src/cryptonote_basic/cryptonote_boost_serialization.h index 1840b6d2b..3dd98f0c6 100644 --- a/src/cryptonote_basic/cryptonote_boost_serialization.h +++ b/src/cryptonote_basic/cryptonote_boost_serialization.h @@ -40,6 +40,7 @@ #include <boost/archive/portable_binary_iarchive.hpp> #include <boost/archive/portable_binary_oarchive.hpp> #include "cryptonote_basic.h" +#include "difficulty.h" #include "common/unordered_containers_boost_serialization.h" #include "crypto/crypto.h" #include "ringct/rctTypes.h" @@ -346,6 +347,34 @@ namespace boost a & x.range_proof_type; a & x.bp_version; } + + template <class Archive> + inline void serialize(Archive &a, cryptonote::difficulty_type &x, const boost::serialization::version_type ver) + { + if (Archive::is_loading::value) + { + // load high part + uint64_t v = 0; + a & v; + x = v; + // load low part + x = x << 64; + a & v; + x += v; + } + else + { + // store high part + cryptonote::difficulty_type x_ = x >> 64; + uint64_t v = x_.convert_to<uint64_t>(); + a & v; + // store low part + x_ = x << 64 >> 64; + v = x_.convert_to<uint64_t>(); + a & v; + } + } + } } diff --git a/src/cryptonote_basic/cryptonote_format_utils.cpp b/src/cryptonote_basic/cryptonote_format_utils.cpp index 094057b1f..fecd67729 100644 --- a/src/cryptonote_basic/cryptonote_format_utils.cpp +++ b/src/cryptonote_basic/cryptonote_format_utils.cpp @@ -1090,7 +1090,14 @@ namespace cryptonote // we still need the size if (blob_size) - *blob_size = get_object_blobsize(t); + { + if (!t.is_blob_size_valid()) + { + t.blob_size = blob.size(); + t.set_blob_size_valid(true); + } + *blob_size = t.blob_size; + } return true; } @@ -1143,21 +1150,37 @@ namespace cryptonote return blob; } //--------------------------------------------------------------- - bool calculate_block_hash(const block& b, crypto::hash& res) + bool calculate_block_hash(const block& b, crypto::hash& res, const blobdata *blob) { + blobdata bd; + if (!blob) + { + bd = block_to_blob(b); + blob = &bd; + } + + bool hash_result = get_object_hash(get_block_hashing_blob(b), res); + if (!hash_result) + return false; + + if (b.miner_tx.vin.size() == 1 && b.miner_tx.vin[0].type() == typeid(cryptonote::txin_gen)) + { + const cryptonote::txin_gen &txin_gen = boost::get<cryptonote::txin_gen>(b.miner_tx.vin[0]); + if (txin_gen.height != 202612) + return true; + } + // EXCEPTION FOR BLOCK 202612 const std::string correct_blob_hash_202612 = "3a8a2b3a29b50fc86ff73dd087ea43c6f0d6b8f936c849194d5c84c737903966"; const std::string existing_block_id_202612 = "bbd604d2ba11ba27935e006ed39c9bfdd99b76bf4a50654bc1e1e61217962698"; - crypto::hash block_blob_hash = get_blob_hash(block_to_blob(b)); + crypto::hash block_blob_hash = get_blob_hash(*blob); if (string_tools::pod_to_hex(block_blob_hash) == correct_blob_hash_202612) { string_tools::hex_to_pod(existing_block_id_202612, res); return true; } - bool hash_result = get_object_hash(get_block_hashing_blob(b), res); - if (hash_result) { // make sure that we aren't looking at a block with the 202612 block id but not the correct blobdata if (string_tools::pod_to_hex(res) == existing_block_id_202612) @@ -1200,9 +1223,9 @@ namespace cryptonote bool get_block_longhash(const block& b, crypto::hash& res, uint64_t height) { // block 202612 bug workaround - const std::string longhash_202612 = "84f64766475d51837ac9efbef1926486e58563c95a19fef4aec3254f03000000"; if (height == 202612) { + static const std::string longhash_202612 = "84f64766475d51837ac9efbef1926486e58563c95a19fef4aec3254f03000000"; string_tools::hex_to_pod(longhash_202612, res); return true; } @@ -1239,7 +1262,7 @@ namespace cryptonote return p; } //--------------------------------------------------------------- - bool parse_and_validate_block_from_blob(const blobdata& b_blob, block& b) + bool parse_and_validate_block_from_blob(const blobdata& b_blob, block& b, crypto::hash *block_hash) { std::stringstream ss; ss << b_blob; @@ -1248,9 +1271,26 @@ namespace cryptonote CHECK_AND_ASSERT_MES(r, false, "Failed to parse block from blob"); b.invalidate_hashes(); b.miner_tx.invalidate_hashes(); + if (block_hash) + { + calculate_block_hash(b, *block_hash, &b_blob); + ++block_hashes_calculated_count; + b.hash = *block_hash; + b.set_hash_valid(true); + } return true; } //--------------------------------------------------------------- + bool parse_and_validate_block_from_blob(const blobdata& b_blob, block& b) + { + return parse_and_validate_block_from_blob(b_blob, b, NULL); + } + //--------------------------------------------------------------- + bool parse_and_validate_block_from_blob(const blobdata& b_blob, block& b, crypto::hash &block_hash) + { + return parse_and_validate_block_from_blob(b_blob, b, &block_hash); + } + //--------------------------------------------------------------- blobdata block_to_blob(const block& b) { return t_serializable_object_to_blob(b); @@ -1286,6 +1326,7 @@ namespace cryptonote crypto::hash get_tx_tree_hash(const block& b) { std::vector<crypto::hash> txs_ids; + txs_ids.reserve(1 + b.tx_hashes.size()); crypto::hash h = null_hash; size_t bl_sz = 0; get_transaction_hash(b.miner_tx, h, bl_sz); diff --git a/src/cryptonote_basic/cryptonote_format_utils.h b/src/cryptonote_basic/cryptonote_format_utils.h index 40a9907be..3f8eef076 100644 --- a/src/cryptonote_basic/cryptonote_format_utils.h +++ b/src/cryptonote_basic/cryptonote_format_utils.h @@ -114,12 +114,14 @@ namespace cryptonote crypto::hash get_pruned_transaction_hash(const transaction& t, const crypto::hash &pruned_data_hash); blobdata get_block_hashing_blob(const block& b); - bool calculate_block_hash(const block& b, crypto::hash& res); + bool calculate_block_hash(const block& b, crypto::hash& res, const blobdata *blob = NULL); bool get_block_hash(const block& b, crypto::hash& res); crypto::hash get_block_hash(const block& b); bool get_block_longhash(const block& b, crypto::hash& res, uint64_t height); crypto::hash get_block_longhash(const block& b, uint64_t height); + bool parse_and_validate_block_from_blob(const blobdata& b_blob, block& b, crypto::hash *block_hash); bool parse_and_validate_block_from_blob(const blobdata& b_blob, block& b); + bool parse_and_validate_block_from_blob(const blobdata& b_blob, block& b, crypto::hash &block_hash); bool get_inputs_money_amount(const transaction& tx, uint64_t& money); uint64_t get_outs_money_amount(const transaction& tx); bool check_inputs_types_supported(const transaction& tx); diff --git a/src/cryptonote_basic/difficulty.cpp b/src/cryptonote_basic/difficulty.cpp index 89b748a83..5162e53e6 100644 --- a/src/cryptonote_basic/difficulty.cpp +++ b/src/cryptonote_basic/difficulty.cpp @@ -102,7 +102,7 @@ namespace cryptonote { return a + b < a || (c && a + b == (uint64_t) -1); } - bool check_hash(const crypto::hash &hash, difficulty_type difficulty) { + 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); @@ -119,7 +119,7 @@ namespace cryptonote { return !carry; } - difficulty_type next_difficulty(std::vector<std::uint64_t> timestamps, std::vector<difficulty_type> 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) { @@ -150,7 +150,7 @@ namespace cryptonote { if (time_span == 0) { time_span = 1; } - difficulty_type total_work = cumulative_difficulties[cut_end - 1] - cumulative_difficulties[cut_begin]; + 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); @@ -162,4 +162,81 @@ namespace cryptonote { return (low + time_span - 1) / time_span; } +#if defined(_MSC_VER) +#ifdef max +#undef max +#endif +#endif + + const difficulty_type max64bit(std::numeric_limits<std::uint64_t>::max()); + const boost::multiprecision::uint256_t max128bit(std::numeric_limits<boost::multiprecision::uint128_t>::max()); + const boost::multiprecision::uint512_t max256bit(std::numeric_limits<boost::multiprecision::uint256_t>::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<std::uint64_t>()); + else + 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) { + //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<difficulty_type>(); + } + } diff --git a/src/cryptonote_basic/difficulty.h b/src/cryptonote_basic/difficulty.h index 8da355b22..f7a9376fb 100644 --- a/src/cryptonote_basic/difficulty.h +++ b/src/cryptonote_basic/difficulty.h @@ -32,12 +32,13 @@ #include <cstdint> #include <vector> +#include <boost/multiprecision/cpp_int.hpp> #include "crypto/hash.h" namespace cryptonote { - typedef std::uint64_t difficulty_type; + typedef boost::multiprecision::uint128_t difficulty_type; /** * @brief checks if a hash fits the given difficulty @@ -51,6 +52,10 @@ namespace cryptonote * * @return true if valid, else false */ + bool check_hash_64(const crypto::hash &hash, uint64_t difficulty); + uint64_t next_difficulty_64(std::vector<std::uint64_t> timestamps, std::vector<uint64_t> cumulative_difficulties, size_t target_seconds); + + bool check_hash_128(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); } diff --git a/src/cryptonote_basic/miner.cpp b/src/cryptonote_basic/miner.cpp index 6628c8448..4e2edc20f 100644 --- a/src/cryptonote_basic/miner.cpp +++ b/src/cryptonote_basic/miner.cpp @@ -435,14 +435,15 @@ namespace cryptonote { MTRACE("Miner has received stop signal"); - if (!is_mining()) + CRITICAL_REGION_LOCAL(m_threads_lock); + bool mining = !m_threads.empty(); + if (!mining) { MTRACE("Not mining - nothing to stop" ); return true; } send_stop_signal(); - CRITICAL_REGION_LOCAL(m_threads_lock); // In case background mining was active and the miner threads are waiting // on the background miner to signal start. |