Move hex parsing functions on CompactTarget to units
What changed, and why it matters
This commit is a routine code reorganization. It moves two helper functions that parse hexadecimal strings into a CompactTarget value from one internal module to another. The actual logic and behavior of the functions are unchanged, and no security issue is present.
No security action required. Treat as normal maintenance/refactoring.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch relocates CompactTarget::from_hex and CompactTarget::from_unprefixed_hex from the bitcoin crate’s CompactTargetExt extension trait to inherent impl methods on CompactTarget in the units crate. The implementations, error types, and unit tests are copied verbatim (with only formatting adjustments to hex literals). This is a pure refactoring step toward moving the proof-of-work module into the units crate.
Changed components
bitcoin/src/pow.rsunits/src/pow.rsInspect captured patch +61 / −49
diff --git a/bitcoin/src/pow.rs b/bitcoin/src/pow.rs
index 8669c35d..96d721a2 100644
--- a/bitcoin/src/pow.rs
+++ b/bitcoin/src/pow.rs
@@ -481,24 +481,6 @@ fn is_retarget_height(height: BlockHeight, adjustment_interval: u32) -> bool {
internal_macros::define_extension_trait! {
/// Extension functionality for the [`CompactTarget`] type.
pub trait CompactTargetExt impl for CompactTarget {
- /// Constructs a new `CompactTarget` from a prefixed hex string.
- fn from_hex(s: &str) -> Result<Self, PrefixedHexError>
- where
- Self: Sized
- {
- let target = parse_int::hex_u32_prefixed(s)?;
- Ok(Self::from_consensus(target))
- }
-
- /// Constructs a new `CompactTarget` from an unprefixed hex string.
- fn from_unprefixed_hex(s: &str) -> Result<Self, UnprefixedHexError>
- where
- Self: Sized
- {
- let target = parse_int::hex_u32_unprefixed(s)?;
- Ok(Self::from_consensus(target))
- }
-
/// Computes the [`CompactTarget`] from a difficulty adjustment.
///
/// ref: <https://github.com/bitcoin/bitcoin/blob/0503cbea9aab47ec0a87d34611e5453158727169/src/pow.cpp>
@@ -1980,37 +1962,6 @@ mod tests {
assert!(((U256::from(u) << 128) + U256::from(u)).is_max());
}
- #[test]
- fn compact_target_from_hex_lower() {
- let target = CompactTarget::from_hex("0x010034ab").unwrap();
- assert_eq!(target, CompactTarget::from_consensus(0x010034ab));
- }
-
- #[test]
- fn compact_target_from_hex_upper() {
- let target = CompactTarget::from_hex("0X010034AB").unwrap();
- assert_eq!(target, CompactTarget::from_consensus(0x010034ab));
- }
-
- #[test]
- fn compact_target_from_unprefixed_hex_lower() {
- let target = CompactTarget::from_unprefixed_hex("010034ab").unwrap();
- assert_eq!(target, CompactTarget::from_consensus(0x010034ab));
- }
-
- #[test]
- fn compact_target_from_unprefixed_hex_upper() {
- let target = CompactTarget::from_unprefixed_hex("010034AB").unwrap();
- assert_eq!(target, CompactTarget::from_consensus(0x010034ab));
- }
-
- #[test]
- fn compact_target_from_hex_invalid_hex_should_err() {
- let hex = "0xzbf9";
- let result = CompactTarget::from_hex(hex);
- assert!(result.is_err());
- }
-
#[test]
fn compact_target_from_upwards_difficulty_adjustment() {
let params = Params::new(crate::Network::Signet);
diff --git a/units/src/pow.rs b/units/src/pow.rs
index f8e73d09..c80dea06 100644
--- a/units/src/pow.rs
+++ b/units/src/pow.rs
@@ -13,6 +13,8 @@ use internals::write_err;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
+use crate::parse_int::{self, PrefixedHexError, UnprefixedHexError};
+
/// Encoding of 256-bit target as 32-bit float.
///
/// This is used to encode a target into the block header. Satoshi made this part of consensus code
@@ -45,6 +47,34 @@ impl CompactTarget {
#[inline]
#[deprecated(since = "1.0.0-rc.0", note = "use `format!(\"{var:x}\")` instead")]
pub fn to_hex(self) -> alloc::string::String { alloc::format!("{:x}", self) }
+
+ /// Constructs a new `CompactTarget` from a prefixed hex string.
+ ///
+ /// # Errors
+ ///
+ /// - If the input string does not contain a `0x` (or `0X`) prefix.
+ /// - If the input string is not a valid hex encoding of a `u32`.
+ pub fn from_hex(s: &str) -> Result<Self, PrefixedHexError>
+ where
+ Self: Sized
+ {
+ let target = parse_int::hex_u32_prefixed(s)?;
+ Ok(Self::from_consensus(target))
+ }
+
+ /// Constructs a new `CompactTarget` from an unprefixed hex string.
+ ///
+ /// # Errors
+ ///
+ /// - If the input string contains a `0x` (or `0X`) prefix.
+ /// - If the input string is not a valid hex encoding of a `u32`.
+ pub fn from_unprefixed_hex(s: &str) -> Result<Self, UnprefixedHexError>
+ where
+ Self: Sized
+ {
+ let target = parse_int::hex_u32_unprefixed(s)?;
+ Ok(Self::from_consensus(target))
+ }
}
impl fmt::Display for CompactTarget {
@@ -239,6 +269,37 @@ mod tests {
assert_eq!(compact_target.to_consensus(), 0x1d00_ffff);
}
+ #[test]
+ fn compact_target_from_hex_lower() {
+ let target = CompactTarget::from_hex("0x010034ab").unwrap();
+ assert_eq!(target, CompactTarget::from_consensus(0x0100_34ab));
+ }
+
+ #[test]
+ fn compact_target_from_hex_upper() {
+ let target = CompactTarget::from_hex("0X010034AB").unwrap();
+ assert_eq!(target, CompactTarget::from_consensus(0x0100_34ab));
+ }
+
+ #[test]
+ fn compact_target_from_unprefixed_hex_lower() {
+ let target = CompactTarget::from_unprefixed_hex("010034ab").unwrap();
+ assert_eq!(target, CompactTarget::from_consensus(0x0100_34ab));
+ }
+
+ #[test]
+ fn compact_target_from_unprefixed_hex_upper() {
+ let target = CompactTarget::from_unprefixed_hex("010034AB").unwrap();
+ assert_eq!(target, CompactTarget::from_consensus(0x0100_34ab));
+ }
+
+ #[test]
+ fn compact_target_from_hex_invalid_hex_should_err() {
+ let hex = "0xzbf9";
+ let result = CompactTarget::from_hex(hex);
+ assert!(result.is_err());
+ }
+
#[test]
#[cfg(feature = "alloc")]
fn compact_target_lower_hex_and_upper_hex() {
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.