diff --git a/api/bitcoin/all-features.txt b/api/bitcoin/all-features.txt index d9ad3d9b6..6ea3c5d39 100644 --- a/api/bitcoin/all-features.txt +++ b/api/bitcoin/all-features.txt @@ -7602,7 +7602,7 @@ pub fn bitcoin::blockdata::block::Header::consensus_decode_from_finite_reader(&self, r: &mut R) -> core::result::Result pub fn bitcoin::blockdata::block::Header::deserialize<__D>(__deserializer: __D) -> core::result::Result::Error> where __D: serde::de::Deserializer<'de> pub fn bitcoin::blockdata::block::Header::difficulty(&self, params: impl core::convert::AsRef) -> u128 -pub fn bitcoin::blockdata::block::Header::difficulty_float(&self) -> f64 +pub fn bitcoin::blockdata::block::Header::difficulty_float(&self, params: impl core::convert::AsRef) -> f64 pub fn bitcoin::blockdata::block::Header::eq(&self, other: &bitcoin::blockdata::block::Header) -> bool pub fn bitcoin::blockdata::block::Header::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result pub fn bitcoin::blockdata::block::Header::hash<__H: core::hash::Hasher>(&self, state: &mut __H) @@ -9087,7 +9087,7 @@ pub fn bitcoin::pow::Target::clone(&self) -> bitcoin::pow::Target pub fn bitcoin::pow::Target::cmp(&self, other: &bitcoin::pow::Target) -> core::cmp::Ordering pub fn bitcoin::pow::Target::deserialize<__D>(__deserializer: __D) -> core::result::Result::Error> where __D: serde::de::Deserializer<'de> pub fn bitcoin::pow::Target::difficulty(&self, params: impl core::convert::AsRef) -> u128 -pub fn bitcoin::pow::Target::difficulty_float(&self) -> f64 +pub fn bitcoin::pow::Target::difficulty_float(&self, params: impl core::convert::AsRef) -> f64 pub fn bitcoin::pow::Target::eq(&self, other: &bitcoin::pow::Target) -> bool pub fn bitcoin::pow::Target::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result pub fn bitcoin::pow::Target::from(c: bitcoin::pow::CompactTarget) -> Self diff --git a/api/bitcoin/default-features.txt b/api/bitcoin/default-features.txt index b56d80bba..afd4cafa9 100644 --- a/api/bitcoin/default-features.txt +++ b/api/bitcoin/default-features.txt @@ -7239,7 +7239,7 @@ pub fn bitcoin::blockdata::block::Header::consensus_decode(r: &mut R) -> core::result::Result pub fn bitcoin::blockdata::block::Header::consensus_encode(&self, r: &mut R) -> core::result::Result pub fn bitcoin::blockdata::block::Header::difficulty(&self, params: impl core::convert::AsRef) -> u128 -pub fn bitcoin::blockdata::block::Header::difficulty_float(&self) -> f64 +pub fn bitcoin::blockdata::block::Header::difficulty_float(&self, params: impl core::convert::AsRef) -> f64 pub fn bitcoin::blockdata::block::Header::eq(&self, other: &bitcoin::blockdata::block::Header) -> bool pub fn bitcoin::blockdata::block::Header::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result pub fn bitcoin::blockdata::block::Header::hash<__H: core::hash::Hasher>(&self, state: &mut __H) @@ -8618,7 +8618,7 @@ pub fn bitcoin::pow::CompactTarget::to_consensus(self) -> u32 pub fn bitcoin::pow::Target::clone(&self) -> bitcoin::pow::Target pub fn bitcoin::pow::Target::cmp(&self, other: &bitcoin::pow::Target) -> core::cmp::Ordering pub fn bitcoin::pow::Target::difficulty(&self, params: impl core::convert::AsRef) -> u128 -pub fn bitcoin::pow::Target::difficulty_float(&self) -> f64 +pub fn bitcoin::pow::Target::difficulty_float(&self, params: impl core::convert::AsRef) -> f64 pub fn bitcoin::pow::Target::eq(&self, other: &bitcoin::pow::Target) -> bool pub fn bitcoin::pow::Target::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result pub fn bitcoin::pow::Target::from(c: bitcoin::pow::CompactTarget) -> Self diff --git a/api/bitcoin/no-features.txt b/api/bitcoin/no-features.txt index 2126fff0a..4c3802f5f 100644 --- a/api/bitcoin/no-features.txt +++ b/api/bitcoin/no-features.txt @@ -6600,7 +6600,7 @@ pub fn bitcoin::blockdata::block::Header::consensus_decode(r: &mut R) -> core::result::Result pub fn bitcoin::blockdata::block::Header::consensus_encode(&self, r: &mut R) -> core::result::Result pub fn bitcoin::blockdata::block::Header::difficulty(&self, params: impl core::convert::AsRef) -> u128 -pub fn bitcoin::blockdata::block::Header::difficulty_float(&self) -> f64 +pub fn bitcoin::blockdata::block::Header::difficulty_float(&self, params: impl core::convert::AsRef) -> f64 pub fn bitcoin::blockdata::block::Header::eq(&self, other: &bitcoin::blockdata::block::Header) -> bool pub fn bitcoin::blockdata::block::Header::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result pub fn bitcoin::blockdata::block::Header::hash<__H: core::hash::Hasher>(&self, state: &mut __H) @@ -7763,7 +7763,7 @@ pub fn bitcoin::pow::CompactTarget::to_consensus(self) -> u32 pub fn bitcoin::pow::Target::clone(&self) -> bitcoin::pow::Target pub fn bitcoin::pow::Target::cmp(&self, other: &bitcoin::pow::Target) -> core::cmp::Ordering pub fn bitcoin::pow::Target::difficulty(&self, params: impl core::convert::AsRef) -> u128 -pub fn bitcoin::pow::Target::difficulty_float(&self) -> f64 +pub fn bitcoin::pow::Target::difficulty_float(&self, params: impl core::convert::AsRef) -> f64 pub fn bitcoin::pow::Target::eq(&self, other: &bitcoin::pow::Target) -> bool pub fn bitcoin::pow::Target::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result pub fn bitcoin::pow::Target::from(c: bitcoin::pow::CompactTarget) -> Self diff --git a/bitcoin/src/blockdata/block.rs b/bitcoin/src/blockdata/block.rs index 9d194d625..53945042f 100644 --- a/bitcoin/src/blockdata/block.rs +++ b/bitcoin/src/blockdata/block.rs @@ -98,7 +98,9 @@ impl Header { } /// Computes the popular "difficulty" measure for mining and returns a float value of f64. - pub fn difficulty_float(&self) -> f64 { self.target().difficulty_float() } + pub fn difficulty_float(&self, params: impl AsRef) -> f64 { + self.target().difficulty_float(params) + } /// Checks that the proof-of-work for the block is valid, returning the block hash. pub fn validate_pow(&self, required_target: Target) -> Result { @@ -541,7 +543,7 @@ mod tests { real_decode.block_hash() ); assert_eq!(real_decode.header.difficulty(¶ms), 1); - assert_eq!(real_decode.header.difficulty_float(), 1.0); + assert_eq!(real_decode.header.difficulty_float(¶ms), 1.0); assert_eq!(real_decode.total_size(), some_block.len()); assert_eq!(real_decode.base_size(), some_block.len()); @@ -583,7 +585,7 @@ mod tests { real_decode.block_hash() ); assert_eq!(real_decode.header.difficulty(¶ms), 2456598); - assert_eq!(real_decode.header.difficulty_float(), 2456598.4399242126); + assert_eq!(real_decode.header.difficulty_float(¶ms), 2456598.4399242126); assert_eq!(real_decode.total_size(), segwit_block.len()); assert_eq!(real_decode.base_size(), 4283); diff --git a/bitcoin/src/pow.rs b/bitcoin/src/pow.rs index eab1f9e3e..6bc6b3b8b 100644 --- a/bitcoin/src/pow.rs +++ b/bitcoin/src/pow.rs @@ -267,13 +267,20 @@ impl Target { /// /// See [`difficulty`] for details. /// - /// # Returns + /// # Panics /// - /// Returns [`f64::INFINITY`] if `self` is zero (caused by divide by zero). + /// Panics if `self` is zero (divide by zero). /// /// [`difficulty`]: Target::difficulty #[cfg_attr(all(test, mutate), mutate)] - pub fn difficulty_float(&self) -> f64 { TARGET_MAX_F64 / self.0.to_f64() } + pub fn difficulty_float(&self, params: impl AsRef) -> f64 { + // We want to explicitly panic to be uniform with `difficulty()` + // (float division by zero does not panic). + // Note, target 0 is basically impossible to obtain by any "normal" means. + assert_ne!(self.0, U256::ZERO, "divide by zero"); + let max = params.as_ref().max_attainable_target; + max.0.to_f64() / self.0.to_f64() + } /// Computes the minimum valid [`Target`] threshold allowed for a block in which a difficulty /// adjustment occurs. @@ -899,10 +906,6 @@ impl U256 { } } -// Target::MAX as a float value. Calculated with U256::to_f64. -// This is validated in the unit tests as well. -const TARGET_MAX_F64: f64 = 2.695953529101131e67; - impl> From for U256 { fn from(x: T) -> Self { U256(0, x.into()) } } @@ -1916,17 +1919,22 @@ mod tests { #[test] fn target_difficulty_float() { - assert_eq!(Target::MAX.difficulty_float(), 1.0_f64); + let params = Params::new(crate::Network::Bitcoin); + + assert_eq!(Target::MAX.difficulty_float(¶ms), 1.0_f64); assert_eq!( - Target::from_compact(CompactTarget::from_consensus(0x1c00ffff_u32)).difficulty_float(), + Target::from_compact(CompactTarget::from_consensus(0x1c00ffff_u32)) + .difficulty_float(¶ms), 256.0_f64 ); assert_eq!( - Target::from_compact(CompactTarget::from_consensus(0x1b00ffff_u32)).difficulty_float(), + Target::from_compact(CompactTarget::from_consensus(0x1b00ffff_u32)) + .difficulty_float(¶ms), 65536.0_f64 ); assert_eq!( - Target::from_compact(CompactTarget::from_consensus(0x1a00f3a2_u32)).difficulty_float(), + Target::from_compact(CompactTarget::from_consensus(0x1a00f3a2_u32)) + .difficulty_float(¶ms), 17628585.065897066_f64 ); } @@ -2041,8 +2049,6 @@ mod tests { #[test] fn u256_to_f64() { - // Validate that the Target::MAX value matches the constant also used in difficulty calculation. - assert_eq!(Target::MAX.0.to_f64(), TARGET_MAX_F64); assert_eq!(U256::ZERO.to_f64(), 0.0_f64); assert_eq!(U256::ONE.to_f64(), 1.0_f64); assert_eq!(U256::MAX.to_f64(), 1.157920892373162e77_f64);