71 lines
2.4 KiB
Rust
71 lines
2.4 KiB
Rust
// SPDX-License-Identifier: CC0-1.0
|
|
|
|
//! Proof-of-work related integer types.
|
|
|
|
use core::fmt;
|
|
|
|
/// 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
|
|
/// in the original version of Bitcoin, likely copying an idea from OpenSSL.
|
|
///
|
|
/// OpenSSL's bignum (BN) type has an encoding, which is even called "compact" as in bitcoin, which
|
|
/// is exactly this format.
|
|
///
|
|
/// # Note on order/equality
|
|
///
|
|
/// Usage of the ordering and equality traits for this type may be surprising. Converting between
|
|
/// `CompactTarget` and `Target` is lossy *in both directions* (there are multiple `CompactTarget`
|
|
/// values that map to the same `Target` value). Ordering and equality for this type are defined in
|
|
/// terms of the underlying `u32`.
|
|
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
|
pub struct CompactTarget(u32);
|
|
|
|
impl CompactTarget {
|
|
/// Constructs a new [`CompactTarget`] from a consensus encoded `u32`.
|
|
#[inline]
|
|
pub fn from_consensus(bits: u32) -> Self { Self(bits) }
|
|
|
|
/// Returns the consensus encoded `u32` representation of this [`CompactTarget`].
|
|
#[inline]
|
|
pub fn to_consensus(self) -> u32 { self.0 }
|
|
}
|
|
|
|
impl fmt::LowerHex for CompactTarget {
|
|
#[inline]
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(&self.0, f) }
|
|
}
|
|
#[cfg(feature = "alloc")]
|
|
internals::impl_to_hex_from_lower_hex!(CompactTarget, |compact_target: &CompactTarget| {
|
|
8 - compact_target.0.leading_zeros() as usize / 4
|
|
});
|
|
|
|
impl fmt::UpperHex for CompactTarget {
|
|
#[inline]
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::UpperHex::fmt(&self.0, f) }
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn compact_target_ordering() {
|
|
let lower = CompactTarget::from_consensus(0x1d00_fffe);
|
|
let lower_copy = CompactTarget::from_consensus(0x1d00_fffe);
|
|
let higher = CompactTarget::from_consensus(0x1d00_ffff);
|
|
|
|
assert!(lower < higher);
|
|
assert!(lower == lower_copy);
|
|
}
|
|
|
|
#[test]
|
|
fn compact_target_formatting() {
|
|
let compact_target = CompactTarget::from_consensus(0x1d00_ffff);
|
|
assert_eq!(format!("{:x}", compact_target), "1d00ffff");
|
|
assert_eq!(format!("{:X}", compact_target), "1D00FFFF");
|
|
assert_eq!(compact_target.to_consensus(), 0x1d00_ffff);
|
|
}
|
|
}
|