1use crate::constants::*;
4use crate::error::{ConsensusError, Result};
5use crate::types::*;
6use blvm_spec_lock::spec_locked;
7use sha2::{Digest, Sha256};
8
9#[spec_locked("7.1")]
34pub fn get_next_work_required(
35 _current_header: &BlockHeader,
36 prev_headers: &[BlockHeader],
37) -> Result<Natural> {
38 get_next_work_required_internal(_current_header, prev_headers, false)
39}
40
41#[spec_locked("7.1")]
53pub fn get_next_work_required_corrected(
54 _current_header: &BlockHeader,
55 prev_headers: &[BlockHeader],
56) -> Result<Natural> {
57 get_next_work_required_internal(_current_header, prev_headers, true)
58}
59
60fn get_next_work_required_internal(
65 _current_header: &BlockHeader,
66 prev_headers: &[BlockHeader],
67 use_corrected: bool,
68) -> Result<Natural> {
69 if prev_headers.len() < 2 {
71 return Err(ConsensusError::InvalidProofOfWork(
72 "Insufficient headers for difficulty adjustment".into(),
73 ));
74 }
75
76 let last_header = &prev_headers[prev_headers.len() - 1];
78 let previous_bits = last_header.bits;
79
80 let first_timestamp = prev_headers[0].timestamp;
83 let last_timestamp = last_header.timestamp;
84
85 if last_timestamp < first_timestamp {
87 return Err(ConsensusError::InvalidProofOfWork(
88 "Invalid timestamp order in difficulty adjustment".into(),
89 ));
90 }
91
92 let time_span = last_timestamp - first_timestamp;
93
94 let expected_time = if use_corrected {
99 let num_intervals = prev_headers.len() as u64;
103 if num_intervals == DIFFICULTY_ADJUSTMENT_INTERVAL {
104 (DIFFICULTY_ADJUSTMENT_INTERVAL - 1) * TARGET_TIME_PER_BLOCK
105 } else {
106 (num_intervals - 1) * TARGET_TIME_PER_BLOCK
108 }
109 } else {
110 DIFFICULTY_ADJUSTMENT_INTERVAL * TARGET_TIME_PER_BLOCK
112 };
113
114 let clamped_timespan = time_span.max(expected_time / 4).min(expected_time * 4);
117
118 debug_assert!(
120 clamped_timespan >= expected_time / 4,
121 "Clamped timespan ({}) must be >= expected_time/4 ({})",
122 clamped_timespan,
123 expected_time / 4
124 );
125 debug_assert!(
126 clamped_timespan <= expected_time * 4,
127 "Clamped timespan ({}) must be <= expected_time*4 ({})",
128 clamped_timespan,
129 expected_time * 4
130 );
131
132 let old_target = expand_target(previous_bits)?;
134
135 if old_target.is_zero() {
136 return Err(ConsensusError::InvalidProofOfWork(
137 "Previous block target is zero (invalid compact bits)".into(),
138 ));
139 }
140
141 let multiplied_target = match old_target.checked_mul_u64(clamped_timespan) {
146 Some(t) => t,
147 None => {
148 return Ok(previous_bits);
149 }
150 };
151
152 debug_assert!(
154 multiplied_target >= old_target || clamped_timespan < expected_time,
155 "Multiplied target should be >= old target when timespan >= expected_time"
156 );
157
158 let new_target = multiplied_target.div_u64(expected_time);
160
161 if new_target.is_zero() {
162 return Err(ConsensusError::InvalidProofOfWork(
163 "Difficulty adjustment produced zero expanded target".into(),
164 ));
165 }
166
167 let new_bits = compress_target(&new_target)?;
169
170 let clamped_bits = new_bits.min(MAX_TARGET as Natural);
172
173 debug_assert!(
175 clamped_bits > 0,
176 "Clamped bits ({clamped_bits}) must be positive"
177 );
178 debug_assert!(
179 clamped_bits <= MAX_TARGET as Natural,
180 "Clamped bits ({clamped_bits}) must be <= MAX_TARGET ({MAX_TARGET})"
181 );
182
183 if clamped_bits == 0 {
185 return Err(ConsensusError::InvalidProofOfWork(
186 "Difficulty adjustment resulted in zero target".into(),
187 ));
188 }
189
190 Ok(clamped_bits)
191}
192
193#[spec_locked("7.2")]
198#[cfg_attr(feature = "production", inline(always))]
199#[cfg_attr(not(feature = "production"), inline)]
200pub fn check_proof_of_work(header: &BlockHeader) -> Result<bool> {
201 let header_bytes = serialize_header(header);
203
204 let hash1 = Sha256::digest(header_bytes);
206 let hash2 = Sha256::digest(hash1);
207
208 let mut hash_bytes = [0u8; 32];
210 hash_bytes.copy_from_slice(&hash2);
211 let hash_value = U256::from_bytes(&hash_bytes);
212
213 let target = expand_target(header.bits)?;
215
216 Ok(hash_value < target)
218}
219
220#[cfg(feature = "production")]
233#[spec_locked("7.2")]
234pub fn batch_check_proof_of_work(headers: &[BlockHeader]) -> Result<Vec<(bool, Option<Hash>)>> {
235 use crate::optimizations::simd_vectorization;
236
237 if headers.is_empty() {
238 return Ok(Vec::new());
239 }
240
241 let header_bytes_vec: Vec<[u8; 80]> = {
243 #[cfg(feature = "rayon")]
244 {
245 use rayon::prelude::*;
246 headers.par_iter().map(serialize_header).collect()
247 }
248 #[cfg(not(feature = "rayon"))]
249 {
250 headers.iter().map(serialize_header).collect()
251 }
252 };
253
254 let header_refs: Vec<&[u8]> = header_bytes_vec.iter().map(|v| v.as_slice()).collect();
256 let aligned_hashes = simd_vectorization::batch_double_sha256_aligned(&header_refs);
257 let hashes: Vec<[u8; 32]> = aligned_hashes.iter().map(|h| *h.as_bytes()).collect();
259
260 let mut results = Vec::with_capacity(headers.len());
262 for (i, header) in headers.iter().enumerate() {
263 let hash = hashes[i];
264
265 let hash_value = U256::from_bytes(&hash);
267
268 match expand_target(header.bits) {
270 Ok(target) => {
271 let is_valid = hash_value < target;
272 results.push((is_valid, if is_valid { Some(hash) } else { None }));
273 }
274 Err(_e) => {
275 results.push((false, None));
277 }
278 }
279 }
280
281 Ok(results)
282}
283
284#[derive(Debug, Clone, PartialEq, Eq)]
286pub struct U256([u64; 4]); impl U256 {
289 fn zero() -> Self {
290 U256([0; 4])
291 }
292
293 fn from_u32(value: u32) -> Self {
294 U256([value as u64, 0, 0, 0])
295 }
296
297 #[cfg(test)]
298 fn from_u64(value: u64) -> Self {
299 U256([value, 0, 0, 0])
300 }
301
302 fn get_low_64(&self) -> u64 {
305 self.0[0]
306 }
307
308 #[cfg(test)]
309 fn to_bytes(&self) -> [u8; 32] {
310 let mut bytes = [0u8; 32];
311 for (i, &word) in self.0.iter().enumerate() {
312 let word_bytes = word.to_le_bytes();
313 bytes[i * 8..(i + 1) * 8].copy_from_slice(&word_bytes);
314 }
315 bytes
316 }
317
318 fn shl(&self, shift: u32) -> Self {
319 if shift >= 256 {
320 return U256::zero();
321 }
322
323 let mut result = U256::zero();
324 let word_shift = (shift / 64) as usize;
325 let bit_shift = shift % 64;
326
327 for i in 0..4 {
328 if i + word_shift < 4 {
329 result.0[i + word_shift] |= self.0[i] << bit_shift;
330 if bit_shift > 0 && i + word_shift + 1 < 4 {
331 result.0[i + word_shift + 1] |= self.0[i] >> (64 - bit_shift);
332 }
333 }
334 }
335
336 result
337 }
338
339 fn shr(&self, shift: u32) -> Self {
340 if shift >= 256 {
341 return U256::zero();
342 }
343
344 let mut result = U256::zero();
345 let word_shift = (shift / 64) as usize;
346 let bit_shift = shift % 64;
347
348 debug_assert!(
350 word_shift < 4,
351 "Word shift ({word_shift}) must be < 4 (shift: {shift})"
352 );
353
354 debug_assert!(
356 bit_shift < 64,
357 "Bit shift ({bit_shift}) must be < 64 (shift: {shift})"
358 );
359
360 if bit_shift == 0 {
361 for i in word_shift..4 {
362 result.0[i - word_shift] = self.0[i];
363 }
364 } else {
365 for i in word_shift..4 {
368 let mut word = self.0[i] >> bit_shift;
369 if i + 1 < 4 {
370 word |= self.0[i + 1] << (64 - bit_shift);
371 }
372 result.0[i - word_shift] = word;
373 }
374 }
375
376 result
377 }
378
379 fn from_bytes(bytes: &[u8; 32]) -> Self {
380 let mut words = [0u64; 4];
381 for (i, word) in words.iter_mut().enumerate() {
382 let start = i * 8;
383 let _end = start + 8;
384 *word = u64::from_le_bytes([
385 bytes[start],
386 bytes[start + 1],
387 bytes[start + 2],
388 bytes[start + 3],
389 bytes[start + 4],
390 bytes[start + 5],
391 bytes[start + 6],
392 bytes[start + 7],
393 ]);
394 }
395 U256(words)
396 }
397
398 fn checked_mul_u64(&self, rhs: u64) -> Option<Self> {
401 let mut carry = 0u128;
403 let mut result = U256::zero();
404
405 #[cfg(feature = "production")]
408 {
409 let product = (self.0[0] as u128) * (rhs as u128) + carry;
412 result.0[0] = product as u64;
413 carry = product >> 64;
414
415 let product = (self.0[1] as u128) * (rhs as u128) + carry;
417 result.0[1] = product as u64;
418 carry = product >> 64;
419
420 let product = (self.0[2] as u128) * (rhs as u128) + carry;
422 result.0[2] = product as u64;
423 carry = product >> 64;
424
425 let product = (self.0[3] as u128) * (rhs as u128) + carry;
427 result.0[3] = product as u64;
428 carry = product >> 64;
429
430 if carry > 0 {
432 return None; }
434 }
435
436 #[cfg(not(feature = "production"))]
437 {
438 for i in 0..4 {
439 let product = (self.0[i] as u128) * (rhs as u128) + carry;
440 result.0[i] = product as u64;
441 carry = product >> 64;
442
443 if i == 3 && carry > 0 {
445 return None; }
447 }
448 }
449
450 Some(result)
451 }
452
453 fn div_u64(&self, rhs: u64) -> Self {
460 if rhs == 0 {
461 return U256([u64::MAX; 4]);
464 }
465
466 let mut remainder = 0u128;
467 let mut result = U256::zero();
468
469 #[cfg(feature = "production")]
473 {
474 let dividend = (remainder << 64) | (self.0[3] as u128);
477 let quotient = dividend / (rhs as u128);
478 remainder = dividend % (rhs as u128);
479 debug_assert!(quotient <= u64::MAX as u128, "Quotient must fit in u64");
480 result.0[3] = quotient as u64;
481
482 let dividend = (remainder << 64) | (self.0[2] as u128);
484 let quotient = dividend / (rhs as u128);
485 remainder = dividend % (rhs as u128);
486 debug_assert!(quotient <= u64::MAX as u128, "Quotient must fit in u64");
487 result.0[2] = quotient as u64;
488
489 let dividend = (remainder << 64) | (self.0[1] as u128);
491 let quotient = dividend / (rhs as u128);
492 remainder = dividend % (rhs as u128);
493 debug_assert!(quotient <= u64::MAX as u128, "Quotient must fit in u64");
494 result.0[1] = quotient as u64;
495
496 let dividend = (remainder << 64) | (self.0[0] as u128);
498 let quotient = dividend / (rhs as u128);
499 remainder = dividend % (rhs as u128);
500 debug_assert!(quotient <= u64::MAX as u128, "Quotient must fit in u64");
501 result.0[0] = quotient as u64;
502 }
503
504 #[cfg(not(feature = "production"))]
505 {
506 for i in (0..4).rev() {
508 let dividend = (remainder << 64) | (self.0[i] as u128);
509 let quotient = dividend / (rhs as u128);
510 remainder = dividend % (rhs as u128);
511 debug_assert!(
512 quotient <= u64::MAX as u128,
513 "Quotient ({quotient}) must fit in u64"
514 );
515 result.0[i] = quotient as u64;
516 }
517 }
518
519 debug_assert!(
521 result <= *self,
522 "Division result ({result:?}) must be <= dividend ({self:?})"
523 );
524
525 debug_assert!(
527 remainder < rhs as u128,
528 "Remainder ({remainder}) must be < divisor ({rhs})"
529 );
530
531 result
532 }
533
534 fn highest_set_bit(&self) -> Option<u32> {
537 for (i, &word) in self.0.iter().rev().enumerate() {
538 if word != 0 {
539 let word_index = (3 - i) as u32;
540 let bit_pos = word_index * 64 + (63 - word.leading_zeros());
541 return Some(bit_pos);
542 }
543 }
544 None
545 }
546
547 fn is_zero(&self) -> bool {
549 self.0.iter().all(|&x| x == 0)
550 }
551
552 fn to_f64(&self) -> f64 {
555 if self.is_zero() {
556 return 0.0;
557 }
558 let mut result = 0.0_f64;
559 result += self.0[0] as f64;
560 result += (self.0[1] as f64) * 2.0_f64.powi(64);
561 result += (self.0[2] as f64) * 2.0_f64.powi(128);
562 result += (self.0[3] as f64) * 2.0_f64.powi(192);
563 result
564 }
565}
566
567impl PartialOrd for U256 {
568 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
569 Some(self.cmp(other))
570 }
571}
572
573impl Ord for U256 {
574 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
575 for (a, b) in self.0.iter().rev().zip(other.0.iter().rev()) {
576 match a.cmp(b) {
577 std::cmp::Ordering::Equal => continue,
578 other => return other,
579 }
580 }
581 std::cmp::Ordering::Equal
582 }
583}
584
585#[spec_locked("7.1")]
590pub fn difficulty_from_bits(bits: Natural) -> Result<f64> {
591 let target = expand_target(bits)?;
592 if target.is_zero() {
593 return Ok(1.0);
594 }
595 let max_target = U256::from_bytes(&[
597 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00, 0x00, 0xFF,
598 0xFF, 0x00, 0x00, 0x00, 0x00,
599 ]);
600 let max_f64 = max_target.to_f64();
601 let target_f64 = target.to_f64();
602 if target_f64 == 0.0 {
603 return Ok(1.0);
604 }
605 Ok((max_f64 / target_f64).max(1.0))
606}
607
608#[spec_locked("7.1")]
638pub fn expand_target(bits: Natural) -> Result<U256> {
639 let exponent = (bits >> 24) as u8;
651 let mantissa = bits & 0x007fffff;
653
654 if !(3..=32).contains(&exponent) {
657 return Err(ConsensusError::InvalidProofOfWork(
658 "Invalid target exponent".into(),
659 ));
660 }
661
662 if mantissa == 0 {
663 return Ok(U256::zero());
664 }
665
666 if exponent <= 3 {
668 let shift = 8 * (3 - exponent);
673 let mantissa_u256 = U256::from_u32(mantissa as u32);
674 Ok(mantissa_u256.shr(shift as u32))
675 } else {
676 let shift = 8u32 * (exponent as u32 - 3);
680 if shift >= 256 {
681 return Err(crate::error::ConsensusError::InvalidProofOfWork(
682 "Target too large".into(),
683 ));
684 }
685 let mantissa_u256 = U256::from_u32(mantissa as u32);
686 Ok(mantissa_u256.shl(shift))
687 }
688}
689
690#[spec_locked("7.1")]
719fn compress_target(target: &U256) -> Result<Natural> {
720 if target.is_zero() {
722 return Ok(0x1d000000); }
724
725 let highest_bit = target
727 .highest_set_bit()
728 .ok_or_else(|| ConsensusError::InvalidProofOfWork("Cannot compress zero target".into()))?;
729
730 let n_size = (highest_bit + 1).div_ceil(8);
733
734 let mut n_compact: u64;
737
738 if n_size <= 3 {
739 let low_64 = target.get_low_64();
742 let shift_bytes = 3 - n_size;
743 n_compact = low_64 << (8 * shift_bytes);
744 } else {
745 let shift_bytes = n_size - 3;
748 let shifted = target.shr(shift_bytes * 8);
749 n_compact = shifted.get_low_64();
750 }
751
752 let mut n_size_final = n_size;
756 while (n_compact & 0x00800000) != 0 {
757 n_compact >>= 8;
758 n_size_final += 1;
759 }
760
761 let mantissa = (n_compact & 0x007fffff) as u32;
764
765 if n_size_final > 29 {
767 return Err(ConsensusError::InvalidProofOfWork(
768 format!("Target too large: exponent {n_size_final} exceeds maximum 29").into(),
769 ));
770 }
771
772 let bits = (n_size_final << 24) | mantissa;
774
775 Ok(bits as Natural)
776}
777
778fn serialize_header(header: &BlockHeader) -> [u8; 80] {
780 let mut bytes = [0u8; 80];
782
783 bytes[0..4].copy_from_slice(&(header.version as u32).to_le_bytes());
784 bytes[4..36].copy_from_slice(&header.prev_block_hash);
785 bytes[36..68].copy_from_slice(&header.merkle_root);
786 bytes[68..72].copy_from_slice(&(header.timestamp as u32).to_le_bytes());
787 bytes[72..76].copy_from_slice(&(header.bits as u32).to_le_bytes());
788 bytes[76..80].copy_from_slice(&(header.nonce as u32).to_le_bytes());
789
790 bytes
791}
792
793#[cfg(test)]
794fn u256_from_bytes(bytes: &[u8]) -> u128 {
796 let mut value = 0u128;
797 for (i, &byte) in bytes.iter().enumerate() {
798 if i < 16 {
799 value |= (byte as u128) << (8 * (15 - i));
801 }
802 }
803 value
804}
805
806#[cfg(test)]
820mod property_tests {
821 use super::*;
822 use proptest::prelude::*;
823
824 fn arb_block_header() -> impl Strategy<Value = BlockHeader> {
825 (
826 any::<i64>(),
827 any::<[u8; 32]>(),
828 any::<[u8; 32]>(),
829 any::<u64>(),
830 0x03000000u32..0x1d00ffffu32,
831 any::<u64>(),
832 )
833 .prop_map(
834 |(version, prev_block_hash, merkle_root, timestamp, bits, nonce)| BlockHeader {
835 version,
836 prev_block_hash,
837 merkle_root,
838 timestamp,
839 bits: bits as u64,
840 nonce,
841 },
842 )
843 }
844
845 proptest! {
847 #[test]
848 fn prop_expand_target_valid_range(
849 bits in 0x03000000u32..0x1d00ffffu32
850 ) {
851 let result = expand_target(bits as u64);
852 let mantissa = bits & 0x00ffffff;
853
854 match result {
855 Ok(target) => {
856 prop_assert!(target >= U256::zero(), "Target must be non-negative");
858
859 if mantissa == 0 {
864 prop_assert!(target.is_zero(), "Zero mantissa should produce zero target");
865 } else {
866 prop_assert!(!target.is_zero(), "Non-zero mantissa should produce non-zero target");
867 }
868 },
869 Err(_) => {
870 }
872 }
873 }
874 }
875
876 proptest! {
878 #[test]
879 fn prop_check_proof_of_work_deterministic(
880 header in arb_block_header()
881 ) {
882 let mut valid_header = header;
884 valid_header.bits = 0x1d00ffff; let result1 = check_proof_of_work(&valid_header).unwrap_or(false);
888 let result2 = check_proof_of_work(&valid_header).unwrap_or(false);
889
890 prop_assert_eq!(result1, result2, "Proof of work check must be deterministic");
892 }
893 }
894
895 proptest! {
897 #[test]
898 fn prop_get_next_work_required_bounds(
899 current_header in arb_block_header(),
900 prev_headers in proptest::collection::vec(arb_block_header(), 2..6)
901 ) {
902 let mut valid_headers = prev_headers;
904 if let Some(first_header) = valid_headers.first_mut() {
905 first_header.timestamp = current_header.timestamp - 86400 * 14; }
907
908 let result = get_next_work_required(¤t_header, &valid_headers);
909
910 match result {
911 Ok(work) => {
912 prop_assert!(work <= MAX_TARGET as Natural,
914 "Next work required must not exceed maximum target");
915 prop_assert!(work > 0, "Next work required must be positive");
916 },
917 Err(_) => {
918 }
920 }
921 }
922 }
923}
924
925#[cfg(test)]
926mod tests {
927 use super::*;
928 use crate::constants::MAX_TARGET;
929
930 #[test]
931 fn test_get_next_work_required_insufficient_headers() {
932 let header = BlockHeader {
933 version: 1,
934 prev_block_hash: [0; 32],
935 merkle_root: [0; 32],
936 timestamp: 1231006505,
937 bits: 0x1d00ffff,
938 nonce: 0,
939 };
940
941 let prev_headers = vec![header.clone()];
942 let result = get_next_work_required(&header, &prev_headers);
943
944 assert!(result.is_err());
946 }
947
948 #[test]
949 fn test_get_next_work_required_normal_adjustment() {
950 let header1 = BlockHeader {
951 version: 1,
952 prev_block_hash: [0; 32],
953 merkle_root: [0; 32],
954 timestamp: 1000000,
955 bits: 0x1d00ffff,
956 nonce: 0,
957 };
958
959 let header2 = BlockHeader {
960 version: 1,
961 prev_block_hash: [0; 32],
962 merkle_root: [0; 32],
963 timestamp: 1000000 + (DIFFICULTY_ADJUSTMENT_INTERVAL * TARGET_TIME_PER_BLOCK), bits: 0x1d00ffff,
965 nonce: 0,
966 };
967
968 let prev_headers = vec![header1, header2.clone()];
969 let result = get_next_work_required(&header2, &prev_headers).unwrap();
970
971 assert_eq!(result, 0x1d00ffff);
973 }
974
975 #[test]
976 fn test_difficulty_from_bits() {
977 let d = difficulty_from_bits(0x1d00ffff).unwrap();
979 assert!(
980 (d - 1.0).abs() < 0.01,
981 "Genesis difficulty should be ~1.0, got {d}"
982 );
983 let d_harder = difficulty_from_bits(0x1d000800).unwrap();
985 assert!(d_harder > d, "Harder target should have higher difficulty");
986 }
987
988 #[test]
989 fn test_expand_target() {
990 let target = expand_target(0x0300ffff).unwrap(); assert!(!target.is_zero());
994 }
995
996 #[test]
997 fn test_check_proof_of_work_genesis() {
998 let header = BlockHeader {
1000 version: 1,
1001 prev_block_hash: [0; 32],
1002 merkle_root: [0; 32],
1003 timestamp: 1231006505,
1004 bits: 0x0300ffff, nonce: 0,
1006 };
1007
1008 let result = check_proof_of_work(&header).unwrap();
1010 let _ = result;
1013 }
1014
1015 #[test]
1020 fn test_get_next_work_required_fast_blocks() {
1021 let header1 = BlockHeader {
1022 version: 1,
1023 prev_block_hash: [0; 32],
1024 merkle_root: [0; 32],
1025 timestamp: 1000000,
1026 bits: 0x1d00ffff,
1027 nonce: 0,
1028 };
1029
1030 let header2 = BlockHeader {
1032 version: 1,
1033 prev_block_hash: [0; 32],
1034 merkle_root: [0; 32],
1035 timestamp: 1000000 + (DIFFICULTY_ADJUSTMENT_INTERVAL * TARGET_TIME_PER_BLOCK / 2),
1036 bits: 0x1d00ffff,
1037 nonce: 0,
1038 };
1039
1040 let prev_headers = vec![header1, header2.clone()];
1041 let result = get_next_work_required(&header2, &prev_headers).unwrap();
1042
1043 assert!(result <= 0x1d00ffff);
1046 }
1047
1048 #[test]
1049 fn test_get_next_work_required_slow_blocks() {
1050 let header1 = BlockHeader {
1051 version: 1,
1052 prev_block_hash: [0; 32],
1053 merkle_root: [0; 32],
1054 timestamp: 1000000,
1055 bits: 0x1d00ffff,
1056 nonce: 0,
1057 };
1058
1059 let header2 = BlockHeader {
1061 version: 1,
1062 prev_block_hash: [0; 32],
1063 merkle_root: [0; 32],
1064 timestamp: 1000000 + (DIFFICULTY_ADJUSTMENT_INTERVAL * TARGET_TIME_PER_BLOCK * 2),
1065 bits: 0x1d00ffff,
1066 nonce: 0,
1067 };
1068
1069 let prev_headers = vec![header1, header2.clone()];
1070 let result = get_next_work_required(&header2, &prev_headers).unwrap();
1071
1072 assert!(result <= 0x1d00ffff);
1075 }
1076
1077 #[test]
1078 fn test_get_next_work_required_extreme_fast_blocks() {
1079 let header1 = BlockHeader {
1080 version: 1,
1081 prev_block_hash: [0; 32],
1082 merkle_root: [0; 32],
1083 timestamp: 1000000,
1084 bits: 0x1d00ffff,
1085 nonce: 0,
1086 };
1087
1088 let header2 = BlockHeader {
1090 version: 1,
1091 prev_block_hash: [0; 32],
1092 merkle_root: [0; 32],
1093 timestamp: 1000000 + (DIFFICULTY_ADJUSTMENT_INTERVAL * TARGET_TIME_PER_BLOCK / 14),
1094 bits: 0x1d00ffff,
1095 nonce: 0,
1096 };
1097
1098 let prev_headers = vec![header1, header2.clone()];
1099 let result = get_next_work_required(&header2, &prev_headers).unwrap();
1100
1101 assert!(result <= 0x1d00ffff);
1104 }
1105
1106 #[test]
1107 fn test_get_next_work_required_extreme_slow_blocks() {
1108 let header1 = BlockHeader {
1109 version: 1,
1110 prev_block_hash: [0; 32],
1111 merkle_root: [0; 32],
1112 timestamp: 1000000,
1113 bits: 0x1d00ffff,
1114 nonce: 0,
1115 };
1116
1117 let header2 = BlockHeader {
1119 version: 1,
1120 prev_block_hash: [0; 32],
1121 merkle_root: [0; 32],
1122 timestamp: 1000000 + (DIFFICULTY_ADJUSTMENT_INTERVAL * TARGET_TIME_PER_BLOCK * 4),
1123 bits: 0x1d00ffff,
1124 nonce: 0,
1125 };
1126
1127 let prev_headers = vec![header1, header2.clone()];
1128 let result = get_next_work_required(&header2, &prev_headers).unwrap();
1129
1130 assert!(result <= 0x1d00ffff);
1133 }
1134
1135 #[test]
1136 fn test_expand_target_zero_mantissa() {
1137 let result = expand_target(0x1d000000).unwrap();
1138 assert!(result.is_zero());
1139 }
1140
1141 #[test]
1142 fn test_expand_target_invalid_exponent_too_small() {
1143 let result = expand_target(0x0200ffff);
1144 assert!(result.is_err());
1145 }
1146
1147 #[test]
1148 fn test_expand_target_invalid_exponent_too_large() {
1149 let result = expand_target(0x2100ffff);
1150 assert!(result.is_err());
1151 }
1152
1153 #[test]
1154 fn test_expand_target_exponent_31() {
1155 let result = expand_target(0x1f00ffff).unwrap(); assert!(!result.is_zero());
1157 }
1158
1159 #[test]
1160 fn test_expand_target_exponent_32_regtest_bits() {
1161 let result = expand_target(0x2000ffff).unwrap();
1163 assert!(!result.is_zero());
1164 }
1165
1166 #[test]
1167 fn test_expand_target_exponent_3() {
1168 let result = expand_target(0x0300ffff).unwrap();
1169 assert!(!result.is_zero());
1170 }
1171
1172 #[test]
1173 fn test_expand_target_exponent_4() {
1174 let result = expand_target(0x0400ffff).unwrap();
1175 assert!(!result.is_zero());
1176 }
1177
1178 #[test]
1179 fn test_expand_target_exponent_29() {
1180 let result = expand_target(0x1d00ffff).unwrap();
1181 assert!(!result.is_zero());
1182 }
1183
1184 #[test]
1185 fn test_check_proof_of_work_invalid_target() {
1186 let header = BlockHeader {
1189 version: 1,
1190 prev_block_hash: [0; 32],
1191 merkle_root: [0; 32],
1192 timestamp: 1231006505,
1193 bits: 0x0200ffff, nonce: 0,
1195 };
1196
1197 let result = check_proof_of_work(&header);
1198 assert!(result.is_err());
1199 }
1200
1201 #[test]
1202 fn test_check_proof_of_work_valid_target() {
1203 let header = BlockHeader {
1204 version: 1,
1205 prev_block_hash: [0; 32],
1206 merkle_root: [0; 32],
1207 timestamp: 1231006505,
1208 bits: 0x1d00ffff, nonce: 0,
1210 };
1211
1212 let result = check_proof_of_work(&header).unwrap();
1213 let _ = result;
1215 }
1216
1217 #[test]
1218 fn test_u256_zero() {
1219 let zero = U256::zero();
1220 assert!(zero.is_zero());
1221 }
1222
1223 #[test]
1224 fn test_u256_from_u32() {
1225 let value = U256::from_u32(0x12345678);
1226 assert!(!value.is_zero());
1227 }
1228
1229 #[test]
1230 fn test_u256_from_u64() {
1231 let value = U256::from_u64(0x123456789abcdef0);
1232 assert!(!value.is_zero());
1233 }
1234
1235 #[test]
1236 fn test_u256_shl_zero_shift() {
1237 let value = U256::from_u32(0x12345678);
1238 let result = value.shl(0);
1239 assert_eq!(result, value);
1240 }
1241
1242 #[test]
1243 fn test_u256_shl_large_shift() {
1244 let value = U256::from_u32(0x12345678);
1245 let result = value.shl(300); assert!(result.is_zero());
1247 }
1248
1249 #[test]
1250 fn test_u256_shr_zero_shift() {
1251 let value = U256::from_u32(0x12345678);
1252 let result = value.shr(0);
1253 assert_eq!(result, value);
1254 }
1255
1256 #[test]
1257 fn test_u256_shr_large_shift() {
1258 let value = U256::from_u32(0x12345678);
1259 let result = value.shr(300); assert!(result.is_zero());
1261 }
1262
1263 #[test]
1264 fn test_u256_shl_small_shift() {
1265 let value = U256::from_u32(0x12345678);
1266 let result = value.shl(8);
1267 assert!(!result.is_zero());
1268 assert_ne!(result, value);
1269 }
1270
1271 #[test]
1272 fn test_u256_shr_small_shift() {
1273 let value = U256::from_u32(0x12345678);
1274 let result = value.shr(8);
1275 assert!(!result.is_zero());
1276 assert_ne!(result, value);
1277 }
1278
1279 #[test]
1280 fn test_u256_to_bytes() {
1281 let value = U256::from_u32(0x12345678);
1282 let bytes = value.to_bytes();
1283 assert_eq!(bytes.len(), 32);
1284 }
1285
1286 #[test]
1287 fn test_u256_from_bytes() {
1288 let mut bytes = [0u8; 32];
1289 bytes[0] = 0x78;
1290 bytes[1] = 0x56;
1291 bytes[2] = 0x34;
1292 bytes[3] = 0x12;
1293 let value = U256::from_bytes(&bytes);
1294 assert!(!value.is_zero());
1295 }
1296
1297 #[test]
1298 fn test_u256_ordering() {
1299 let small = U256::from_u32(0x12345678);
1300 let large = U256::from_u32(0x87654321);
1301
1302 assert!(small < large);
1303 assert!(large > small);
1304 assert_eq!(small.cmp(&small), std::cmp::Ordering::Equal);
1305 }
1306
1307 #[test]
1308 fn test_expand_compress_round_trip() {
1309 let test_bits = vec![
1311 0x1d00ffff, 0x1b0404cb, 0x0300ffff, ];
1318
1319 for &bits in &test_bits {
1320 let expanded = match expand_target(bits) {
1322 Ok(t) => t,
1323 Err(_) => continue, };
1325
1326 let compressed = match compress_target(&expanded) {
1328 Ok(b) => b,
1329 Err(_) => {
1330 continue;
1333 }
1334 };
1335
1336 let re_expanded = match expand_target(compressed) {
1338 Ok(t) => t,
1339 Err(_) => continue,
1340 };
1341
1342 if re_expanded > expanded {
1346 panic!(
1347 "Round-trip failed for bits 0x{bits:08x}: re-expanded > original (compression should truncate, not add)"
1348 );
1349 }
1350 #[allow(clippy::eq_op)]
1357 let significant_words_match =
1358 expanded.0[2] == re_expanded.0[2] && expanded.0[3] == re_expanded.0[3];
1359 if !significant_words_match {
1360 panic!(
1361 "Round-trip failed for bits 0x{:08x}: significant bits differ (expanded: {:?}, re-expanded: {:?})",
1362 bits, expanded.0, re_expanded.0
1363 );
1364 }
1365 }
1367 }
1368
1369 #[test]
1370 fn test_compress_target_genesis() {
1371 let genesis_bits = 0x1d00ffff;
1373 let expanded = expand_target(genesis_bits).unwrap();
1374 let compressed = compress_target(&expanded).unwrap();
1375
1376 assert!(compressed <= MAX_TARGET as u64);
1378 assert!(compressed > 0);
1379
1380 let re_expanded = expand_target(compressed).unwrap();
1382 assert_eq!(expanded, re_expanded);
1383 }
1384
1385 #[test]
1386 fn test_serialize_header() {
1387 let header = BlockHeader {
1388 version: 1,
1389 prev_block_hash: [1; 32],
1390 merkle_root: [2; 32],
1391 timestamp: 1234567890,
1392 bits: 0x1d00ffff,
1393 nonce: 0x12345678,
1394 };
1395
1396 let bytes = serialize_header(&header);
1397 assert_eq!(bytes.len(), 80); }
1399
1400 #[test]
1405 fn test_serialize_header_returns_fixed_80_bytes() {
1406 let header = BlockHeader {
1408 version: 1,
1409 prev_block_hash: [0; 32],
1410 merkle_root: [0; 32],
1411 timestamp: 0,
1412 bits: 0,
1413 nonce: 0,
1414 };
1415 let bytes: [u8; 80] = serialize_header(&header);
1416 assert_eq!(bytes.len(), 80);
1417 }
1418
1419 #[test]
1420 fn test_serialize_header_field_layout() {
1421 let header = BlockHeader {
1423 version: 0x01020304,
1424 prev_block_hash: {
1425 let mut h = [0u8; 32];
1426 h[0] = 0xAA;
1427 h[31] = 0xBB;
1428 h
1429 },
1430 merkle_root: {
1431 let mut h = [0u8; 32];
1432 h[0] = 0xCC;
1433 h[31] = 0xDD;
1434 h
1435 },
1436 timestamp: 0x05060708,
1437 bits: 0x090A0B0C,
1438 nonce: 0x0D0E0F10,
1439 };
1440
1441 let bytes = serialize_header(&header);
1442
1443 assert_eq!(bytes[0], 0x04); assert_eq!(bytes[1], 0x03);
1446 assert_eq!(bytes[2], 0x02);
1447 assert_eq!(bytes[3], 0x01);
1448
1449 assert_eq!(bytes[4], 0xAA);
1451 assert_eq!(bytes[35], 0xBB);
1452
1453 assert_eq!(bytes[36], 0xCC);
1455 assert_eq!(bytes[67], 0xDD);
1456
1457 assert_eq!(bytes[68], 0x08);
1459 assert_eq!(bytes[69], 0x07);
1460 assert_eq!(bytes[70], 0x06);
1461 assert_eq!(bytes[71], 0x05);
1462
1463 assert_eq!(bytes[72], 0x0C);
1465 assert_eq!(bytes[73], 0x0B);
1466 assert_eq!(bytes[74], 0x0A);
1467 assert_eq!(bytes[75], 0x09);
1468
1469 assert_eq!(bytes[76], 0x10);
1471 assert_eq!(bytes[77], 0x0F);
1472 assert_eq!(bytes[78], 0x0E);
1473 assert_eq!(bytes[79], 0x0D);
1474 }
1475
1476 #[test]
1477 fn test_serialize_header_deterministic() {
1478 let header = BlockHeader {
1479 version: 1,
1480 prev_block_hash: [0xFF; 32],
1481 merkle_root: [0xAA; 32],
1482 timestamp: 1231006505,
1483 bits: 0x1d00ffff,
1484 nonce: 2083236893,
1485 };
1486
1487 let bytes1 = serialize_header(&header);
1488 let bytes2 = serialize_header(&header);
1489 assert_eq!(bytes1, bytes2, "Header serialization must be deterministic");
1490 }
1491
1492 #[test]
1493 fn test_serialize_header_different_headers_different_bytes() {
1494 let header1 = BlockHeader {
1495 version: 1,
1496 prev_block_hash: [0; 32],
1497 merkle_root: [0; 32],
1498 timestamp: 1231006505,
1499 bits: 0x1d00ffff,
1500 nonce: 0,
1501 };
1502
1503 let mut header2 = header1.clone();
1504 header2.nonce = 1;
1505
1506 let bytes1 = serialize_header(&header1);
1507 let bytes2 = serialize_header(&header2);
1508 assert_ne!(
1509 bytes1, bytes2,
1510 "Different nonces must produce different serializations"
1511 );
1512
1513 assert_eq!(
1515 bytes1[..76],
1516 bytes2[..76],
1517 "Non-nonce bytes should be identical"
1518 );
1519 assert_ne!(bytes1[76..], bytes2[76..], "Nonce bytes should differ");
1520 }
1521
1522 #[test]
1523 fn test_u256_from_bytes_simple() {
1524 let bytes = [0u8; 32];
1525 let value = u256_from_bytes(&bytes);
1526 assert_eq!(value, 0);
1527 }
1528
1529 #[test]
1530 fn test_u256_from_bytes_with_data() {
1531 let mut bytes = [0u8; 32];
1532 bytes[0] = 0x78;
1533 bytes[1] = 0x56;
1534 bytes[2] = 0x34;
1535 bytes[3] = 0x12;
1536 let value = u256_from_bytes(&bytes);
1537 assert_eq!(value, 0x78563412000000000000000000000000);
1540 }
1541}