handshake_types/
compact.rs1use extended_primitives::Uint256;
2
3#[derive(Debug, PartialEq, Clone, Copy)]
4pub struct Compact(u32);
5
6impl From<u32> for Compact {
7 fn from(u: u32) -> Self {
8 Compact(u)
9 }
10}
11
12impl From<Compact> for u32 {
13 fn from(c: Compact) -> Self {
14 c.0
15 }
16}
17
18impl From<Uint256> for Compact {
19 fn from(u: Uint256) -> Self {
20 Compact::from_u256(u)
21 }
22}
23
24impl From<Compact> for Uint256 {
25 fn from(c: Compact) -> Self {
26 c.to_u256().unwrap_or_else(|x| x)
28 }
29}
30
31impl Compact {
36 pub fn new(u: u32) -> Self {
37 Compact(u)
38 }
39
40 pub fn max_value() -> Self {
41 Uint256::max_value().into()
42 }
43
44 pub fn to_u256(&self) -> Result<Uint256, Uint256> {
47 if self.0 == 0 {
48 return Ok(Uint256::from_u64(0).unwrap());
49 }
50 let exponent = self.0 >> 24;
51 let negative = (self.0 >> 23) & 1;
52
53 let mut mantissa = self.0 & 0x_7ff_fff;
54
55 let result = if exponent <= 3 {
56 mantissa >>= 8 * (3 - exponent as usize);
57 Uint256::from(mantissa)
58 } else {
59 Uint256::from(mantissa) << (8 * (exponent as usize - 3))
60 };
61
62 let overflow = (mantissa != 0 && exponent > 34)
63 || (mantissa > 0xff && exponent > 33)
64 || (mantissa > 0xffff && exponent > 32);
65
66 if negative != 0 || overflow {
67 Err(result)
68 } else {
69 Ok(result)
70 }
71 }
72
73 pub fn from_u256(val: Uint256) -> Self {
74 let mut size = (val.bits() + 7) / 8;
75 let mut compact = if size <= 3 {
76 (val.low_u64() << (8 * (3 - size))) as u32
77 } else {
78 let bn = val >> (8 * (size - 3));
79 bn.low_u32()
80 };
81
82 if (compact & 0x00800000) != 0 {
83 compact >>= 8;
84 size += 1;
85 }
86
87 assert!((compact & !0x_7ff_fff) == 0);
88 assert!(size < 256);
89 Compact(compact | (size << 24) as u32)
90 }
91
92 pub fn to_f64(&self) -> f64 {
93 let mut shift = (self.0 >> 24) & 0xff;
94 let mut diff = f64::from(0x0000ffffu32) / f64::from(self.0 & 0x00ffffffu32);
95 while shift < 29 {
96 diff *= f64::from(256);
97 shift += 1;
98 }
99 while shift > 29 {
100 diff /= f64::from(256.0);
101 shift -= 1;
102 }
103 diff
104 }
105}
106
107#[cfg(test)]
108mod tests {
109 use super::Compact;
110 use super::*;
111
112 #[test]
113 fn test_compact_to_u256() {
114 assert_eq!(Compact::new(0x01003456).to_u256(), Ok(0u64.into()));
115 assert_eq!(Compact::new(0x01123456).to_u256(), Ok(0x12u64.into()));
116 assert_eq!(Compact::new(0x02008000).to_u256(), Ok(0x80u64.into()));
117 assert_eq!(Compact::new(0x05009234).to_u256(), Ok(0x92340000u64.into()));
118 assert!(Compact::new(0x04923456).to_u256().is_err());
120 assert_eq!(Compact::new(0x04123456).to_u256(), Ok(0x12345600u64.into()));
121 }
122
123 #[test]
124 fn test_from_u256() {
125 let test1 = Uint256::from(1000u64);
126 assert_eq!(Compact::new(0x0203e800), Compact::from_u256(test1));
127
128 }
131
132 #[test]
133 fn test_compact_to_from_u256() {
134 let compact = Compact::new(0x1d00ffff);
136 let compact2 = Compact::from_u256(compact.to_u256().unwrap());
137 assert_eq!(compact, compact2);
138
139 let compact = Compact::new(0x05009234);
140 let compact2 = Compact::from_u256(compact.to_u256().unwrap());
141 assert_eq!(compact, compact2);
142 }
143
144 #[test]
145 fn difficulty() {
146 fn compare_f64(v1: f64, v2: f64) -> bool {
147 (v1 - v2).abs() < 0.00001
148 }
149
150 assert!(compare_f64(Compact::new(0x1b0404cb).to_f64(), 16307.42094));
151
152 assert!(compare_f64(Compact::new(0x1f111111).to_f64(), 0.000001));
156 assert!(compare_f64(Compact::new(0x1ef88f6f).to_f64(), 0.000016));
157 assert!(compare_f64(Compact::new(0x1df88f6f).to_f64(), 0.004023));
158 assert!(compare_f64(Compact::new(0x1cf88f6f).to_f64(), 1.029916));
159 assert!(compare_f64(
160 Compact::new(0x12345678).to_f64(),
161 5913134931067755359633408.0
162 ));
163 }
164}