diff --git a/src/currency_core/blockchain_storage.cpp b/src/currency_core/blockchain_storage.cpp index 32bad122..038e3264 100644 --- a/src/currency_core/blockchain_storage.cpp +++ b/src/currency_core/blockchain_storage.cpp @@ -61,6 +61,7 @@ using namespace currency; #define BLOCKCHAIN_STORAGE_OPTIONS_ID_STORAGE_MAJOR_COMPATIBILITY_VERSION 3 //mismatch here means full resync #define BLOCKCHAIN_STORAGE_OPTIONS_ID_STORAGE_MINOR_COMPATIBILITY_VERSION 4 //mismatch here means some reinitializations +#define TARGETDATA_CACHE_SIZE DIFFICULTY_WINDOW + 10 DISABLE_VS_WARNINGS(4267) @@ -447,6 +448,8 @@ bool blockchain_storage::clear() m_db_aliases.clear(); m_db_addr_to_alias.clear(); m_db_per_block_gindex_incs.clear(); + m_pos_targetdata_cache.clear(); + m_pow_targetdata_cache.clear(); m_db.commit_transaction(); @@ -889,62 +892,21 @@ wide_difficulty_type blockchain_storage::get_next_diff_conditional(bool pos) con CRITICAL_REGION_LOCAL(m_read_lock); std::vector timestamps; std::vector commulative_difficulties; - size_t count = 0; if (!m_db_blocks.size()) return DIFFICULTY_STARTER; //skip genesis timestamp - uint64_t stop_ind = 0; - uint64_t blocks_size = m_db_blocks.size(); TIME_MEASURE_START_PD(target_calculating_enum_blocks); + std::list>& targetdata_cache = pos ? m_pos_targetdata_cache : m_pow_targetdata_cache; + if (targetdata_cache.empty()) + load_targetdata_cache(pos); - //@#@ -// #define PRINT_PERFORMANCE_DATA_NATIVE(var_name) << #var_name": " << m_db_blocks.get_performance_data_native().var_name.get_avg() << "(" << m_db_blocks.get_performance_data_native().var_name.get_count()<< ")" << ENDL -// #define PRINT_PERFORMANCE_DATA_GLOBAL(var_name) << #var_name": " << m_db_blocks.get_performance_data_global().var_name.get_avg() << "(" << m_db_blocks.get_performance_data_global().var_name.get_count()<< ")" << ENDL -// #define PRINT_PERFORMANCE_DATA(var_name) << #var_name": " << m_db_blocks.get_performance_data().var_name.get_avg() << "(" << m_db_blocks.get_performance_data().var_name.get_count()<< ")" << ENDL -// -// #define RESET_PERFORMANCE_DATA_NATIVE(var_name) m_db_blocks.get_performance_data_native().var_name.reset(); -// #define RESET_PERFORMANCE_DATA_GLOBAL(var_name) m_db_blocks.get_performance_data_global().var_name.reset(); -// #define RESET_PERFORMANCE_DATA(var_name) m_db_blocks.get_performance_data().var_name.reset(); -// -// -// RESET_PERFORMANCE_DATA_GLOBAL(backend_get_pod_time); -// RESET_PERFORMANCE_DATA_GLOBAL(backend_get_t_time); -// RESET_PERFORMANCE_DATA_GLOBAL(get_serialize_t_time); -// RESET_PERFORMANCE_DATA(hit_percent); -// RESET_PERFORMANCE_DATA(read_cache_microsec); -// RESET_PERFORMANCE_DATA(read_db_microsec); -// RESET_PERFORMANCE_DATA(update_cache_microsec); -// RESET_PERFORMANCE_DATA(write_to_cache_microsec); - for (uint64_t cur_ind = blocks_size - 1; cur_ind != stop_ind && count < DIFFICULTY_WINDOW; cur_ind--) + size_t count = 0; + for (auto it = targetdata_cache.rbegin(); it != targetdata_cache.rend() && count < DIFFICULTY_WINDOW; it++) { - auto beiptr = m_db_blocks[cur_ind]; - - bool is_pos_bl = is_pos_block(beiptr->bl); - if (pos != is_pos_bl) - continue; - timestamps.push_back(beiptr->bl.timestamp); - commulative_difficulties.push_back(beiptr->cumulative_diff_precise); + timestamps.push_back(it->second); + commulative_difficulties.push_back(it->first); ++count; } - //@#@ - - - -// LOG_PRINT_MAGENTA("[GET_NEXT_DIFF_CONDITIONAL][DB STAT]: count: " << count << ENDL -// PRINT_PERFORMANCE_DATA_NATIVE(backend_set_pod_time) -// PRINT_PERFORMANCE_DATA_NATIVE(backend_set_t_time) -// PRINT_PERFORMANCE_DATA_NATIVE(set_serialize_t_time) -// PRINT_PERFORMANCE_DATA_GLOBAL(backend_get_pod_time) -// PRINT_PERFORMANCE_DATA_GLOBAL(backend_get_t_time) -// PRINT_PERFORMANCE_DATA_GLOBAL(get_serialize_t_time) -// PRINT_PERFORMANCE_DATA(hit_percent) -// PRINT_PERFORMANCE_DATA(read_cache_microsec) -// PRINT_PERFORMANCE_DATA(read_db_microsec) -// PRINT_PERFORMANCE_DATA(update_cache_microsec) -// PRINT_PERFORMANCE_DATA(write_to_cache_microsec) -// //PRINT_PERFORMANCE_DATA(write_to_db_microsec) -// , LOG_LEVEL_0); - //!@#@ wide_difficulty_type& dif = pos ? m_cached_next_pos_difficulty : m_cached_next_pow_difficulty; TIME_MEASURE_FINISH_PD(target_calculating_enum_blocks); @@ -4600,23 +4562,67 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt bvc.m_added_to_main_chain = true; return true; } +//------------------------------------------------------------------ void blockchain_storage::on_block_added(const block_extended_info& bei, const crypto::hash& id) { update_next_comulative_size_limit(); m_timestamps_median_cache.clear(); m_tx_pool.on_blockchain_inc(bei.height, id); + + update_targetdata_cache_on_block_added(bei); + TIME_MEASURE_START_PD(raise_block_core_event); rise_core_event(CORE_EVENT_BLOCK_ADDED, void_struct()); TIME_MEASURE_FINISH_PD(raise_block_core_event); + } //------------------------------------------------------------------ void blockchain_storage::on_block_removed(const block_extended_info& bei) { m_tx_pool.on_blockchain_dec(m_db_blocks.size() - 1, get_top_block_id()); m_timestamps_median_cache.clear(); + update_targetdata_cache_on_block_removed(bei); LOG_PRINT_L2("block at height " << bei.height << " was removed from the blockchain"); } //------------------------------------------------------------------ +void blockchain_storage::update_targetdata_cache_on_block_added(const block_extended_info& bei) +{ + if (bei.height == 0) + return; //skip genesis + std::list>& targetdata_cache = is_pos_block(bei.bl) ? m_pos_targetdata_cache : m_pow_targetdata_cache; + targetdata_cache.push_back(std::pair(bei.cumulative_diff_precise, bei.bl.timestamp)); + while (targetdata_cache.size() > TARGETDATA_CACHE_SIZE) + targetdata_cache.pop_front(); +} +//------------------------------------------------------------------ +void blockchain_storage::update_targetdata_cache_on_block_removed(const block_extended_info& bei) +{ + std::list>& targetdata_cache = is_pos_block(bei.bl) ? m_pos_targetdata_cache : m_pow_targetdata_cache; + if (targetdata_cache.size()) + targetdata_cache.pop_back(); + if (targetdata_cache.size() < DIFFICULTY_WINDOW) + targetdata_cache.clear(); +} +//------------------------------------------------------------------ +void blockchain_storage::load_targetdata_cache(bool is_pos)const +{ + std::list>& targetdata_cache = is_pos? m_pos_targetdata_cache: m_pow_targetdata_cache; + targetdata_cache.clear(); + uint64_t stop_ind = 0; + uint64_t blocks_size = m_db_blocks.size(); + size_t count = 0; + for (uint64_t cur_ind = blocks_size - 1; cur_ind != stop_ind && count < DIFFICULTY_WINDOW + 5; cur_ind--) + { + auto beiptr = m_db_blocks[cur_ind]; + + bool is_pos_bl = is_pos_block(beiptr->bl); + if (is_pos != is_pos_bl) + continue; + targetdata_cache.push_front(std::pair(beiptr->cumulative_diff_precise, beiptr->bl.timestamp)); + ++count; + } +} +//------------------------------------------------------------------ void blockchain_storage::on_abort_transaction() { if (m_event_handler) m_event_handler->on_clear_events(); diff --git a/src/currency_core/blockchain_storage.h b/src/currency_core/blockchain_storage.h index 463a754c..eaa12740 100644 --- a/src/currency_core/blockchain_storage.h +++ b/src/currency_core/blockchain_storage.h @@ -501,7 +501,7 @@ namespace currency mutable core_runtime_config m_core_runtime_config; mutable i_core_event_handler* m_event_handler; mutable i_core_event_handler m_event_handler_stub; - + //tools::median_db_cache m_tx_fee_median; mutable std::unordered_map m_timestamps_median_cache; mutable performnce_data m_performance_data; @@ -510,7 +510,10 @@ namespace currency //just informational mutable wide_difficulty_type m_cached_next_pow_difficulty; mutable wide_difficulty_type m_cached_next_pos_difficulty; - //work like a cache to avoid + + mutable std::list > m_pos_targetdata_cache; + mutable std::list > m_pow_targetdata_cache; + //work like a cache to avoid recalculation on read operations mutable uint64_t m_current_fee_median; mutable uint64_t m_current_fee_median_effective_index; bool m_is_reorganize_in_process; @@ -560,9 +563,12 @@ namespace currency const std::vector& get_txin_etc_options(const txin_v& in)const; void on_block_added(const block_extended_info& bei, const crypto::hash& id); void on_block_removed(const block_extended_info& bei); + void update_targetdata_cache_on_block_added(const block_extended_info& bei); + void update_targetdata_cache_on_block_removed(const block_extended_info& bei); uint64_t tx_fee_median_for_height(uint64_t h) const; uint64_t get_tx_fee_median_effective_index(uint64_t h) const; void on_abort_transaction(); + void load_targetdata_cache(bool is_pos) const; uint64_t get_adjusted_time()const; diff --git a/src/currency_core/difficulty.cpp b/src/currency_core/difficulty.cpp index b5d90356..f2a12544 100644 --- a/src/currency_core/difficulty.cpp +++ b/src/currency_core/difficulty.cpp @@ -55,23 +55,7 @@ namespace currency { return a + b < a || (c && a + b == (uint64_t)-1); } - bool check_hash_old(const crypto::hash &hash, difficulty_type 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; - } - + #if defined(_MSC_VER) #ifdef max #undef max @@ -143,48 +127,6 @@ namespace currency { } } - difficulty_type next_difficulty_old(vector timestamps, 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 DIFFICULTY_STARTER; - } - 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); - uint64_t low, high; - mul(total_work, target_seconds, low, high); - if (high != 0 || low + time_span - 1 < low) { - return 0; - } - return (low + time_span - 1) / time_span; - } - void get_cut_location_from_len(size_t length, size_t& cut_begin, size_t& cut_end, size_t REDEF_DIFFICULTY_WINDOW, size_t REDEF_DIFFICULTY_CUT_OLD, size_t REDEF_DIFFICULTY_CUT_LAST) { if (length <= REDEF_DIFFICULTY_WINDOW) diff --git a/src/currency_core/difficulty.h b/src/currency_core/difficulty.h index 4335719e..529389e3 100644 --- a/src/currency_core/difficulty.h +++ b/src/currency_core/difficulty.h @@ -15,13 +15,9 @@ namespace currency { - typedef std::uint64_t difficulty_type; + typedef boost::multiprecision::uint128_t wide_difficulty_type; - bool check_hash_old(const crypto::hash &hash, difficulty_type difficulty); - difficulty_type next_difficulty_old(std::vector timestamps, std::vector cumulative_difficulties); - difficulty_type next_difficulty_old(std::vector timestamps, std::vector cumulative_difficulties, size_t target_seconds); - bool check_hash(const crypto::hash &hash, wide_difficulty_type difficulty); wide_difficulty_type next_difficulty(std::vector& timestamps, std::vector& cumulative_difficulties, size_t target_seconds); uint64_t difficulty_to_boundary(wide_difficulty_type difficulty); diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index 9a2ab644..70e2436e 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -893,7 +893,7 @@ namespace currency response.height = get_block_height(blk); response.depth = m_core.get_current_blockchain_size() - response.height - 1; response.hash = string_tools::pod_to_hex(get_block_hash(blk)); - response.difficulty = m_core.get_blockchain_storage().block_difficulty(response.height).convert_to(); + response.difficulty = m_core.get_blockchain_storage().block_difficulty(response.height).convert_to(); response.reward = get_block_reward(blk); return true; } diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h index 10fec97a..6c3959d8 100644 --- a/src/rpc/core_rpc_server_commands_defs.h +++ b/src/rpc/core_rpc_server_commands_defs.h @@ -834,7 +834,7 @@ namespace currency uint64_t height; uint64_t depth; std::string hash; - difficulty_type difficulty; + std::string difficulty; uint64_t reward; BEGIN_KV_SERIALIZE_MAP() diff --git a/tests/core_tests/chain_switch_pow_pos.cpp b/tests/core_tests/chain_switch_pow_pos.cpp index e199ee11..70af6850 100644 --- a/tests/core_tests/chain_switch_pow_pos.cpp +++ b/tests/core_tests/chain_switch_pow_pos.cpp @@ -52,7 +52,7 @@ bool gen_chain_switch_pow_pos::generate(std::vector& events) c for(size_t i = 0; i < CURRENCY_MINED_MONEY_UNLOCK_WINDOW; ++i) { block blk = AUTO_VAL_INIT(blk); - uint64_t ts = blk_0r.timestamp + DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN / 3; // to increase main chain difficulty + uint64_t ts = blk_0r.timestamp + DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN / 2; // to increase main chain difficulty bool r = generator.construct_block_manually(blk, blk_0r, miner_acc,test_generator::bf_timestamp, 0, 0, ts); CHECK_AND_ASSERT_MES(r, false, "construct_block_manually failed"); events.push_back(blk);