From 6adcc5c60107f68b075e7014433a75bc738792f6 Mon Sep 17 00:00:00 2001 From: "crypro.zoidberg" Date: Wed, 6 Feb 2019 13:50:51 +0300 Subject: [PATCH] simulation few lines --- src/currency_core/difficulty.cpp | 6 +- src/currency_core/difficulty.h | 2 +- .../functional_tests/difficulty_analysis.cpp | 215 +++++++++++++++++- 3 files changed, 216 insertions(+), 7 deletions(-) diff --git a/src/currency_core/difficulty.cpp b/src/currency_core/difficulty.cpp index a496d463..ca48c338 100644 --- a/src/currency_core/difficulty.cpp +++ b/src/currency_core/difficulty.cpp @@ -184,7 +184,9 @@ namespace currency { return (low + time_span - 1) / time_span; } - wide_difficulty_type next_difficulty(vector timestamps, vector cumulative_difficulties, size_t target_seconds) { + wide_difficulty_type next_difficulty(vector& timestamps, vector& cumulative_difficulties, size_t target_seconds) + { + // timestamps - first is latest, back - is oldest timestamps //cutoff DIFFICULTY_LAG if(timestamps.size() > DIFFICULTY_WINDOW) { @@ -210,7 +212,7 @@ namespace currency { 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); + CHECK_AND_ASSERT_THROW_MES(/*cut_begin >= 0 &&*/ cut_begin + 2 <= cut_end && cut_end <= length, "validation in next_difficulty is failed"); uint64_t time_span = timestamps[cut_begin] - timestamps[cut_end - 1]; if (time_span == 0) { time_span = 1; diff --git a/src/currency_core/difficulty.h b/src/currency_core/difficulty.h index 127fadce..4335719e 100644 --- a/src/currency_core/difficulty.h +++ b/src/currency_core/difficulty.h @@ -23,7 +23,7 @@ namespace currency 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); + 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); void difficulty_to_boundary_long(wide_difficulty_type difficulty, crypto::hash& result); } diff --git a/tests/functional_tests/difficulty_analysis.cpp b/tests/functional_tests/difficulty_analysis.cpp index 4f7520a9..28843926 100644 --- a/tests/functional_tests/difficulty_analysis.cpp +++ b/tests/functional_tests/difficulty_analysis.cpp @@ -13,6 +13,10 @@ using namespace epee; #include "wallet/wallet2.h" #include "currency_core/blockchain_storage.h" + +using std::size_t; +using std::uint64_t; +using std::vector; bool parse_file(const std::string& path, std::vector>& blocks, uint64_t reserve_size) { @@ -41,11 +45,133 @@ bool parse_file(const std::string& path, std::vector>& blo } -void run_difficulty_analysis(const std::string& path) -{ - //hash_rate_analysis(path); - run_emulation(path); +#define BBR_DIFFICULTY_TARGET 120 // seconds +#define BBR_DIFFICULTY_WINDOW 720 // blocks +#define BBR_DIFFICULTY_LAG 15 // !!! +#define BBR_DIFFICULTY_CUT 60 // timestamps to cut after sorting +#define BBR_DIFFICULTY_STARTER 1 +#define NEW_DIFFICULTY_WINDOW 360 +#define NEW_DIFFICULTY_CUT_OLD 60 // timestamps to cut after sorting on the oldest timestamps +#define NEW_DIFFICULTY_CUT_LAST 0 // timestamps to cut after sorting on the most recent timestamps + +const boost::multiprecision::uint256_t max128bit(std::numeric_limits::max()); +currency::wide_difficulty_type bbr_next_difficulty(std::vector& timestamps, std::vector& cumulative_difficulties, size_t target_seconds) +{ + // timestamps - first is latest, back - is oldest timestamps + //cutoff DIFFICULTY_LAG + if (timestamps.size() > BBR_DIFFICULTY_WINDOW) + { + timestamps.resize(BBR_DIFFICULTY_WINDOW); + cumulative_difficulties.resize(BBR_DIFFICULTY_WINDOW); + } + + + size_t length = timestamps.size(); + CHECK_AND_ASSERT_MES(length == cumulative_difficulties.size(), 0, "Check \"length == cumulative_difficulties.size()\" failed"); + if (length <= 1) { + return BBR_DIFFICULTY_STARTER; + } + static_assert(BBR_DIFFICULTY_WINDOW >= 2, "Window is too small"); + CHECK_AND_ASSERT_MES(length <= BBR_DIFFICULTY_WINDOW, 0, "length <= BBR_DIFFICULTY_WINDOW check failed, length=" << length); + sort(timestamps.begin(), timestamps.end(), std::greater()); + size_t cut_begin, cut_end; + static_assert(2 * BBR_DIFFICULTY_CUT <= BBR_DIFFICULTY_WINDOW - 2, "Cut length is too large"); + if (length <= BBR_DIFFICULTY_WINDOW - 2 * BBR_DIFFICULTY_CUT) { + cut_begin = 0; + cut_end = length; + } + else { + cut_begin = (length - (BBR_DIFFICULTY_WINDOW - 2 * BBR_DIFFICULTY_CUT) + 1) / 2; + cut_end = cut_begin + (BBR_DIFFICULTY_WINDOW - 2 * BBR_DIFFICULTY_CUT); + } + CHECK_AND_ASSERT_THROW_MES(/*cut_begin >= 0 &&*/ cut_begin + 2 <= cut_end && cut_end <= length, "validation in next_difficulty is failed"); + uint64_t time_span = timestamps[cut_begin] - timestamps[cut_end - 1]; + if (time_span == 0) { + time_span = 1; + } + currency::wide_difficulty_type total_work = cumulative_difficulties[cut_begin] - cumulative_difficulties[cut_end - 1]; + 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(); +} + + +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) + { + cut_begin = 0; + cut_end = length; + } + else + { + cut_begin = REDEF_DIFFICULTY_WINDOW - REDEF_DIFFICULTY_CUT_LAST + 1; + cut_end = cut_begin + (REDEF_DIFFICULTY_WINDOW - (REDEF_DIFFICULTY_CUT_OLD + REDEF_DIFFICULTY_CUT_LAST)); + } +} + +currency::wide_difficulty_type bbr_next_difficulty_configurable(std::vector& timestamps, std::vector& cumulative_difficulties, size_t target_seconds, size_t REDEF_DIFFICULTY_WINDOW, size_t REDEF_DIFFICULTY_CUT_OLD, size_t REDEF_DIFFICULTY_CUT_LAST) +{ + // timestamps - first is latest, back - is oldest timestamps + //cutoff DIFFICULTY_LAG + if (timestamps.size() > REDEF_DIFFICULTY_WINDOW) + { + timestamps.resize(REDEF_DIFFICULTY_WINDOW); + cumulative_difficulties.resize(REDEF_DIFFICULTY_WINDOW); + } + + + size_t length = timestamps.size(); + CHECK_AND_ASSERT_MES(length == cumulative_difficulties.size(), 0, "Check \"length == cumulative_difficulties.size()\" failed"); + if (length <= 1) { + return BBR_DIFFICULTY_STARTER; + } + CHECK_AND_ASSERT_THROW_MES(REDEF_DIFFICULTY_WINDOW >= 2, "Window is too small"); + CHECK_AND_ASSERT_MES(length <= REDEF_DIFFICULTY_WINDOW, 0, "length <= REDEF_DIFFICULTY_WINDOW check failed, length=" << length); + sort(timestamps.begin(), timestamps.end(), std::greater()); + size_t cut_begin, cut_end; + CHECK_AND_ASSERT_THROW_MES( (REDEF_DIFFICULTY_CUT_OLD + REDEF_DIFFICULTY_CUT_LAST) <= REDEF_DIFFICULTY_WINDOW - 2, "Cut length is too large"); + get_cut_location_from_len(length, cut_begin, cut_end, REDEF_DIFFICULTY_WINDOW, REDEF_DIFFICULTY_CUT_OLD, REDEF_DIFFICULTY_CUT_LAST); + + CHECK_AND_ASSERT_THROW_MES(/*cut_begin >= 0 &&*/ cut_begin + 2 <= cut_end && cut_end <= length, "validation in next_difficulty is failed"); + uint64_t time_span = timestamps[cut_begin] - timestamps[cut_end - 1]; + if (time_span == 0) { + time_span = 1; + } + currency::wide_difficulty_type total_work = cumulative_difficulties[cut_begin] - cumulative_difficulties[cut_end - 1]; + 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(); +} + +currency::wide_difficulty_type bbr_next_difficulty2(std::vector& timestamps, std::vector& cumulative_difficulties, size_t target_seconds) +{ + return bbr_next_difficulty_configurable(timestamps, cumulative_difficulties, target_seconds, NEW_DIFFICULTY_WINDOW, NEW_DIFFICULTY_CUT_OLD, NEW_DIFFICULTY_CUT_LAST); +} + +uint64_t get_next_timestamp_by_difficulty_and_hashrate(uint64_t last_timestamp, currency::wide_difficulty_type difficulty, uint64_t hashrate) +{ + uint64_t seconds = (difficulty / hashrate).convert_to(); + return last_timestamp + seconds; +} + +void print_blocks(const std::vector>& blocks, const std::string& res_path) +{ + std::stringstream ss; + for (size_t i = 0; i != blocks.size(); i++) + { + ss << std::left << std::setw(10) << i << std::left << std::setw(15) << blocks[i][0]; + for (size_t j = 1; j != blocks[i].size()-1; j++) + { + ss << std::left << std::setw(15) << blocks[i][j] / 120; + } + ss << std::left << std::setw(20) << blocks[i][blocks[i].size() - 1] << ENDL; + } + file_io_utils::save_string_to_file(res_path, ss.str()); + LOG_PRINT_L0("Done, saved to file " << res_path); } void run_emulation(const std::string& path) @@ -53,9 +179,90 @@ void run_emulation(const std::string& path) //0 - timestamp, 1 - difficulty/120, 2 net hashrate (h/s) std::vector> blocks; + std::vector> result_blocks; + blocks.reserve(401); + result_blocks.reserve(401); +// std::vector timestamps, timestamps_new; +// std::vector cumul_difficulties, cumul_difficulties_new; +// timestamps.reserve(4010); +// cumul_difficulties.reserve(4010); +// timestamps_new.reserve(4010); +// cumul_difficulties_new.reserve(4010); + + parse_file(path, blocks, 500); +#define DEFINE_DIFFICULTY_SIMULATION(sim_name) \ + std::vector timestamps_##sim_name; \ + std::vector cumul_difficulties_##sim_name; \ + timestamps_##sim_name.reserve(4010); \ + cumul_difficulties_##sim_name.reserve(4010); \ + timestamps_##sim_name.push_back(blocks[0][0]); \ + cumul_difficulties_##sim_name.push_back(blocks[0][1]); \ + currency::wide_difficulty_type curren_difficulty_##sim_name = 0; + DEFINE_DIFFICULTY_SIMULATION(original); + DEFINE_DIFFICULTY_SIMULATION(new_720_5_60); + DEFINE_DIFFICULTY_SIMULATION(new_300_5_60); + DEFINE_DIFFICULTY_SIMULATION(new_200_5_5); + + for (uint64_t b_no = 0; b_no != blocks.size(); b_no++) + { + auto& b_line = blocks[b_no]; + + + for (size_t i = 0; i != 10; i++) + { +#define PROCESS_DIFFICULTY_SIMULATION(sim_name, func_name, window_size, cut_old, cut_new) \ + if (timestamps_##sim_name.size() < BBR_DIFFICULTY_WINDOW) \ + { \ + curren_difficulty_##sim_name = b_line[1] * 120; \ + } \ + else \ + { \ + std::vector backward_timestamps; \ + backward_timestamps.reserve(BBR_DIFFICULTY_WINDOW); \ + std::copy(timestamps_##sim_name.rbegin(), timestamps_##sim_name.rbegin() + BBR_DIFFICULTY_WINDOW - 1, std::back_inserter(backward_timestamps)); \ + std::vector backward_cumul_difficulties; \ + backward_cumul_difficulties.reserve(BBR_DIFFICULTY_WINDOW); \ + std::copy(cumul_difficulties_##sim_name.rbegin(), cumul_difficulties_##sim_name.rbegin() + BBR_DIFFICULTY_WINDOW - 1, std::back_inserter(backward_cumul_difficulties)); \ + curren_difficulty_##sim_name = func_name(backward_timestamps, backward_cumul_difficulties, BBR_DIFFICULTY_TARGET, window_size, cut_old, cut_new); \ + } \ + cumul_difficulties_##sim_name.push_back(cumul_difficulties_##sim_name.back() + curren_difficulty_##sim_name); \ + timestamps_##sim_name.push_back(get_next_timestamp_by_difficulty_and_hashrate(timestamps_##sim_name.back(), curren_difficulty_##sim_name, b_line[2])); + + PROCESS_DIFFICULTY_SIMULATION(original, bbr_next_difficulty_configurable, BBR_DIFFICULTY_WINDOW, BBR_DIFFICULTY_CUT, BBR_DIFFICULTY_CUT); + PROCESS_DIFFICULTY_SIMULATION(new_720_5_60, bbr_next_difficulty_configurable, NEW_DIFFICULTY_WINDOW, NEW_DIFFICULTY_CUT_OLD, NEW_DIFFICULTY_CUT_LAST); + PROCESS_DIFFICULTY_SIMULATION(new_300_5_60, bbr_next_difficulty_configurable, 300, 5, 60); + PROCESS_DIFFICULTY_SIMULATION(new_200_5_5, bbr_next_difficulty_configurable, 200, 5, 5); + + std::cout << b_no << "\r"; + } + result_blocks.push_back(std::vector()); + result_blocks.back().resize(20); + size_t index = 0; + +#define SAVE_DIFFICULTY_SIMULATION_ENTRY(sim_name) \ + result_blocks.back()[index] = timestamps_##sim_name.back(); \ + result_blocks.back()[index+1] = curren_difficulty_##sim_name.convert_to(); \ + index +=2; + + SAVE_DIFFICULTY_SIMULATION_ENTRY(original); + SAVE_DIFFICULTY_SIMULATION_ENTRY(new_720_5_60); + SAVE_DIFFICULTY_SIMULATION_ENTRY(new_300_5_60); + SAVE_DIFFICULTY_SIMULATION_ENTRY(new_200_5_5); + + result_blocks.back()[index] = b_line[2]; + } + print_blocks(result_blocks, path + "result.txt"); + LOG_PRINT_L0("Done"); +} + + +void run_difficulty_analysis(const std::string& path) +{ + //hash_rate_analysis(path); + run_emulation(path); }