From c157651f8a243e6e0ad2d11e44cda531bd6b8784 Mon Sep 17 00:00:00 2001 From: t1amak Date: Fri, 20 Mar 2026 15:13:36 +0100 Subject: [PATCH] Add bounded emergency difficulty adjustment --- src/cryptonote_config.h | 6 ++++ src/cryptonote_core/blockchain.cpp | 45 +++++++++++++++++++++++++++++- src/hardforks/hardforks.cpp | 3 ++ 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/src/cryptonote_config.h b/src/cryptonote_config.h index 08d5e31..d0d4862 100644 --- a/src/cryptonote_config.h +++ b/src/cryptonote_config.h @@ -253,6 +253,7 @@ #define HF_VERSION_AUDIT2_PAUSE 9 #define HF_VERSION_CARROT 10 #define HF_VERSION_ENABLE_TOKENS 11 +#define HF_VERSION_EMERGENCY_DIFFICULTY 12 #define HF_VERSION_REQUIRE_VIEW_TAGS 255 #define HF_VERSION_ENABLE_CONVERT 255 @@ -286,6 +287,11 @@ #define PRICING_RECORD_VALID_BLOCKS 10 #define PRICING_RECORD_VALID_TIME_DIFF_FROM_BLOCK 120 // seconds +// Emergency difficulty adjustment after an abnormally slow block. +// Applied as a bounded cap on top of the regular difficulty algorithm. +#define DIFFICULTY_EDA_THRESHOLD 6 +#define DIFFICULTY_EDA_MAX_DROP_PERCENT 75 + //The limit is enough for the mandatory transaction content with 16 outputs (547 bytes), //a custom tag (1 byte) and up to 32 bytes of custom data for each recipient. // (1+32) + (1+1+16*32) + (1+16*32) = 1060 diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 8515995..d765542 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -77,6 +77,42 @@ using namespace crypto; +namespace +{ + cryptonote::difficulty_type apply_emergency_difficulty_cap( + cryptonote::difficulty_type calculated_difficulty, + const std::vector ×tamps, + const std::vector &cumulative_difficulties, + size_t target_seconds) + { + if (timestamps.size() < 2 || cumulative_difficulties.size() < 2) + return calculated_difficulty; + + const uint64_t last_ts = timestamps[timestamps.size() - 1]; + const uint64_t prev_ts = timestamps[timestamps.size() - 2]; + const uint64_t solve_time = last_ts > prev_ts ? (last_ts - prev_ts) : 1; + if (solve_time <= DIFFICULTY_EDA_THRESHOLD * target_seconds) + return calculated_difficulty; + + cryptonote::difficulty_type last_difficulty = + cumulative_difficulties[cumulative_difficulties.size() - 1] - + cumulative_difficulties[cumulative_difficulties.size() - 2]; + cryptonote::difficulty_type adjusted = (last_difficulty * target_seconds) / solve_time; + if (adjusted < 1) + adjusted = 1; + + cryptonote::difficulty_type bounded_adjusted = + (last_difficulty * (100 - DIFFICULTY_EDA_MAX_DROP_PERCENT)) / 100; + if (bounded_adjusted < 1) + bounded_adjusted = 1; + + if (adjusted < bounded_adjusted) + adjusted = bounded_adjusted; + + return adjusted < calculated_difficulty ? adjusted : calculated_difficulty; + } +} + //#include "serialization/json_archive.h" /* TODO: @@ -885,6 +921,7 @@ difficulty_type Blockchain::get_difficulty_for_next_block() ++height; uint8_t version = get_current_hard_fork_version(); + const uint8_t next_version = m_hardfork->get_ideal_version(height); size_t difficulty_blocks_count; if (version == 1) { difficulty_blocks_count = DIFFICULTY_BLOCKS_COUNT; @@ -944,6 +981,8 @@ difficulty_type Blockchain::get_difficulty_for_next_block() } else { diff = next_difficulty_v2(timestamps, difficulties, target); } + if (next_version >= HF_VERSION_EMERGENCY_DIFFICULTY) + diff = apply_emergency_difficulty_cap(diff, timestamps, difficulties, target); CRITICAL_REGION_LOCAL1(m_difficulty_lock); m_difficulty_for_next_block_top_hash = top_hash; @@ -1271,6 +1310,7 @@ difficulty_type Blockchain::get_next_difficulty_for_alternative_chain(const std: std::vector timestamps; std::vector cumulative_difficulties; uint8_t version = get_current_hard_fork_version(); + const uint8_t next_version = get_ideal_hard_fork_version(bei.height); size_t difficulty_blocks_count; if (version == 1) { difficulty_blocks_count = DIFFICULTY_BLOCKS_COUNT; @@ -1335,7 +1375,10 @@ difficulty_type Blockchain::get_next_difficulty_for_alternative_chain(const std: if (version == 1) { return next_difficulty(timestamps, cumulative_difficulties, target); } else { - return next_difficulty_v2(timestamps, cumulative_difficulties, target); + difficulty_type diff = next_difficulty_v2(timestamps, cumulative_difficulties, target); + if (next_version >= HF_VERSION_EMERGENCY_DIFFICULTY) + diff = apply_emergency_difficulty_cap(diff, timestamps, cumulative_difficulties, target); + return diff; } } //------------------------------------------------------------------ diff --git a/src/hardforks/hardforks.cpp b/src/hardforks/hardforks.cpp index 5e85d05..b730f45 100644 --- a/src/hardforks/hardforks.cpp +++ b/src/hardforks/hardforks.cpp @@ -36,6 +36,7 @@ const hardfork_t mainnet_hard_forks[] = { { 1, 0, 0, 1341378000 }, {10, 1, 0, 1341378120 }, {11, 2, 0, 1341378240 }, + {12, 3, 0, 1341378360 }, }; const size_t num_mainnet_hard_forks = sizeof(mainnet_hard_forks) / sizeof(mainnet_hard_forks[0]); const uint64_t mainnet_hard_fork_version_1_till = 0; @@ -45,6 +46,7 @@ const hardfork_t testnet_hard_forks[] = { { 1, 0, 0, 1341378000 }, {10, 1, 0, 1341378120 }, {11, 2, 0, 1341378240 }, + {12, 3, 0, 1341378360 }, }; const size_t num_testnet_hard_forks = sizeof(testnet_hard_forks) / sizeof(testnet_hard_forks[0]); const uint64_t testnet_hard_fork_version_1_till = 0; @@ -54,5 +56,6 @@ const hardfork_t stagenet_hard_forks[] = { { 1, 0, 0, 1341378000 }, {10, 1, 0, 1341378120 }, {11, 2, 0, 1341378240 }, + {12, 3, 0, 1341378360 }, }; const size_t num_stagenet_hard_forks = sizeof(stagenet_hard_forks) / sizeof(stagenet_hard_forks[0]);