From 11c77dd2f687f72c47bcd922bea09023bfbcf767 Mon Sep 17 00:00:00 2001 From: SW van Heerden Date: Wed, 1 Nov 2023 17:51:34 +0200 Subject: [PATCH 1/3] adaptable min difficulty check --- .../comms_interface/inbound_handlers.rs | 30 +++++++++++++++---- .../core/src/proof_of_work/difficulty.rs | 12 ++++++++ 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/base_layer/core/src/base_node/comms_interface/inbound_handlers.rs b/base_layer/core/src/base_node/comms_interface/inbound_handlers.rs index 2346022546..fe45d3d470 100644 --- a/base_layer/core/src/base_node/comms_interface/inbound_handlers.rs +++ b/base_layer/core/src/base_node/comms_interface/inbound_handlers.rs @@ -448,10 +448,11 @@ where B: BlockchainBackend + 'static return Ok(()); } - // lets check that the difficulty at least matches the min required difficulty - // We cannot check the target difficulty as orphan blocks dont have a target difficulty. - // All we care here is that bad blocks are not free to make, and that they are more expensive to make then they - // are to validate. As soon as a block can be linked to the main chain, a proper full proof of work check will + // lets check that the difficulty at least matches 50% of the tip header. The max difficulty drop is 16%, thus + // 50% is way more than that and in order to attack the node, you need 50% of the mining power. We cannot check + // the target difficulty as orphan blocks dont have a target difficulty. All we care here is that bad + // blocks are not free to make, and that they are more expensive to make then they are to validate. As + // soon as a block can be linked to the main chain, a proper full proof of work check will // be done before any other validation. self.check_min_block_difficulty(&new_block).await?; @@ -504,7 +505,26 @@ where B: BlockchainBackend + 'static async fn check_min_block_difficulty(&self, new_block: &NewBlock) -> Result<(), CommsInterfaceError> { let constants = self.consensus_manager.consensus_constants(new_block.header.height); - let min_difficulty = constants.min_pow_difficulty(new_block.header.pow.pow_algo); + let mut min_difficulty = constants.min_pow_difficulty(new_block.header.pow.pow_algo); + let mut header = self.blockchain_db.fetch_last_chain_header().await?; + loop { + if new_block.header.pow_algo() == header.header().pow_algo() { + min_difficulty = header + .accumulated_data() + .target_difficulty + .checked_div_u64(2) + .unwrap_or(min_difficulty); + break; + } + if header.height() == 0 { + break; + } + // we have not reached gen block, and the pow algo does not match, so lets go further back + header = self + .blockchain_db + .fetch_chain_header(header.height().saturating_sub(1)) + .await?; + } let achieved = match new_block.header.pow_algo() { PowAlgorithm::RandomX => randomx_difficulty(&new_block.header, &self.randomx_factory)?, PowAlgorithm::Sha3x => sha3x_difficulty(&new_block.header)?, diff --git a/base_layer/core/src/proof_of_work/difficulty.rs b/base_layer/core/src/proof_of_work/difficulty.rs index e24dec9f6f..c0111535be 100644 --- a/base_layer/core/src/proof_of_work/difficulty.rs +++ b/base_layer/core/src/proof_of_work/difficulty.rs @@ -83,6 +83,18 @@ impl Difficulty { let result = result.min(u64::MAX.into()); Difficulty::from_u64(result.low_u64()) } + + pub fn checked_div_u64(&self, other: u64) -> Option { + if other == 0 { + return None; + } + let result = Difficulty(self.0 / other); + if result.0 < MIN_DIFFICULTY { + None + } else { + Some(result) + } + } } /// These traits should not be implemented for `Difficulty`: From a44d43a79421eb9e303f3dd35a41002b4b0a04c1 Mon Sep 17 00:00:00 2001 From: SW van Heerden Date: Mon, 6 Nov 2023 14:23:47 +0200 Subject: [PATCH 2/3] Update base_layer/core/src/proof_of_work/difficulty.rs Co-authored-by: Brian Pearce --- base_layer/core/src/proof_of_work/difficulty.rs | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/base_layer/core/src/proof_of_work/difficulty.rs b/base_layer/core/src/proof_of_work/difficulty.rs index c0111535be..20e067be94 100644 --- a/base_layer/core/src/proof_of_work/difficulty.rs +++ b/base_layer/core/src/proof_of_work/difficulty.rs @@ -84,15 +84,12 @@ impl Difficulty { Difficulty::from_u64(result.low_u64()) } - pub fn checked_div_u64(&self, other: u64) -> Option { - if other == 0 { - return None; - } - let result = Difficulty(self.0 / other); - if result.0 < MIN_DIFFICULTY { - None - } else { - Some(result) + pub fn min_difficulty_checked_div(&self, other: u64) -> Option { + return match self.0.checked_div(other) { + None => None, + Some(n) => { + n < MIN_DIFFICULTY ? None : Some(Difficulty(n)) + } } } } From b66d5886b4654fed084f45399b4489218f7ced73 Mon Sep 17 00:00:00 2001 From: SW van Heerden Date: Mon, 6 Nov 2023 14:53:51 +0200 Subject: [PATCH 3/3] code review --- .../base_node/comms_interface/inbound_handlers.rs | 14 +++++++++----- base_layer/core/src/proof_of_work/difficulty.rs | 12 ++++++++---- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/base_layer/core/src/base_node/comms_interface/inbound_handlers.rs b/base_layer/core/src/base_node/comms_interface/inbound_handlers.rs index fe45d3d470..de0af66acb 100644 --- a/base_layer/core/src/base_node/comms_interface/inbound_handlers.rs +++ b/base_layer/core/src/base_node/comms_interface/inbound_handlers.rs @@ -21,6 +21,7 @@ // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. use std::{ + cmp::max, collections::HashSet, convert::{TryFrom, TryInto}, sync::Arc, @@ -509,11 +510,14 @@ where B: BlockchainBackend + 'static let mut header = self.blockchain_db.fetch_last_chain_header().await?; loop { if new_block.header.pow_algo() == header.header().pow_algo() { - min_difficulty = header - .accumulated_data() - .target_difficulty - .checked_div_u64(2) - .unwrap_or(min_difficulty); + min_difficulty = max( + header + .accumulated_data() + .target_difficulty + .checked_div_u64(2) + .unwrap_or(min_difficulty), + min_difficulty, + ); break; } if header.height() == 0 { diff --git a/base_layer/core/src/proof_of_work/difficulty.rs b/base_layer/core/src/proof_of_work/difficulty.rs index 20e067be94..2d7a38a600 100644 --- a/base_layer/core/src/proof_of_work/difficulty.rs +++ b/base_layer/core/src/proof_of_work/difficulty.rs @@ -84,12 +84,16 @@ impl Difficulty { Difficulty::from_u64(result.low_u64()) } - pub fn min_difficulty_checked_div(&self, other: u64) -> Option { - return match self.0.checked_div(other) { + pub fn checked_div_u64(&self, other: u64) -> Option { + match self.0.checked_div(other) { None => None, Some(n) => { - n < MIN_DIFFICULTY ? None : Some(Difficulty(n)) - } + if n < MIN_DIFFICULTY { + None + } else { + Some(Difficulty(n)) + } + }, } } }