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", "GetNextWorkRequired")]
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
41pub fn get_next_work_required_corrected(
53 _current_header: &BlockHeader,
54 prev_headers: &[BlockHeader],
55) -> Result<Natural> {
56 get_next_work_required_internal(_current_header, prev_headers, true)
57}
58
59fn get_next_work_required_internal(
64 _current_header: &BlockHeader,
65 prev_headers: &[BlockHeader],
66 use_corrected: bool,
67) -> Result<Natural> {
68 if prev_headers.len() < 2 {
70 return Err(ConsensusError::InvalidProofOfWork(
71 "Insufficient headers for difficulty adjustment".into(),
72 ));
73 }
74
75 let last_header = &prev_headers[prev_headers.len() - 1];
77 let previous_bits = last_header.bits;
78
79 let first_timestamp = prev_headers[0].timestamp;
82 let last_timestamp = last_header.timestamp;
83
84 if last_timestamp < first_timestamp {
86 return Err(ConsensusError::InvalidProofOfWork(
87 "Invalid timestamp order in difficulty adjustment".into(),
88 ));
89 }
90
91 let time_span = last_timestamp - first_timestamp;
92
93 let expected_time = if use_corrected {
98 let num_intervals = prev_headers.len() as u64;
102 if num_intervals == DIFFICULTY_ADJUSTMENT_INTERVAL {
103 (DIFFICULTY_ADJUSTMENT_INTERVAL - 1) * TARGET_TIME_PER_BLOCK
104 } else {
105 (num_intervals - 1) * TARGET_TIME_PER_BLOCK
107 }
108 } else {
109 DIFFICULTY_ADJUSTMENT_INTERVAL * TARGET_TIME_PER_BLOCK
111 };
112
113 let clamped_timespan = time_span.max(expected_time / 4).min(expected_time * 4);
116
117 debug_assert!(
119 clamped_timespan >= expected_time / 4,
120 "Clamped timespan ({}) must be >= expected_time/4 ({})",
121 clamped_timespan,
122 expected_time / 4
123 );
124 debug_assert!(
125 clamped_timespan <= expected_time * 4,
126 "Clamped timespan ({}) must be <= expected_time*4 ({})",
127 clamped_timespan,
128 expected_time * 4
129 );
130
131 let old_target = expand_target(previous_bits)?;
133
134 if old_target.is_zero() {
135 return Err(ConsensusError::InvalidProofOfWork(
136 "Previous block target is zero (invalid compact bits)".into(),
137 ));
138 }
139
140 let multiplied_target = match old_target.checked_mul_u64(clamped_timespan) {
145 Some(t) => t,
146 None => {
147 return Ok(previous_bits);
148 }
149 };
150
151 debug_assert!(
153 multiplied_target >= old_target || clamped_timespan < expected_time,
154 "Multiplied target should be >= old target when timespan >= expected_time"
155 );
156
157 let new_target = multiplied_target.div_u64(expected_time);
159
160 if new_target.is_zero() {
161 return Err(ConsensusError::InvalidProofOfWork(
162 "Difficulty adjustment produced zero expanded target".into(),
163 ));
164 }
165
166 let new_bits = compress_target(&new_target)?;
168
169 let clamped_bits = new_bits.min(MAX_TARGET as Natural);
171
172 debug_assert!(
174 clamped_bits > 0,
175 "Clamped bits ({clamped_bits}) must be positive"
176 );
177 debug_assert!(
178 clamped_bits <= MAX_TARGET as Natural,
179 "Clamped bits ({clamped_bits}) must be <= MAX_TARGET ({MAX_TARGET})"
180 );
181
182 if clamped_bits == 0 {
184 return Err(ConsensusError::InvalidProofOfWork(
185 "Difficulty adjustment resulted in zero target".into(),
186 ));
187 }
188
189 Ok(clamped_bits)
190}
191
192#[spec_locked("7.2", "CheckProofOfWork")]
197#[cfg_attr(feature = "production", inline(always))]
198#[cfg_attr(not(feature = "production"), inline)]
199pub fn check_proof_of_work(header: &BlockHeader) -> Result<bool> {
200 let header_bytes = serialize_header(header);
202
203 let hash1 = Sha256::digest(header_bytes);
205 let hash2 = Sha256::digest(hash1);
206
207 let mut hash_bytes = [0u8; 32];
209 hash_bytes.copy_from_slice(&hash2);
210 let hash_value = U256::from_bytes(&hash_bytes);
211
212 let target = expand_target(header.bits)?;
214
215 Ok(hash_value < target)
217}
218
219#[spec_locked("7.2", "CheckProofOfWork")]
232#[cfg(feature = "production")]
233pub fn batch_check_proof_of_work(headers: &[BlockHeader]) -> Result<Vec<(bool, Option<Hash>)>> {
234 use crate::optimizations::simd_vectorization;
235
236 if headers.is_empty() {
237 return Ok(Vec::new());
238 }
239
240 let header_bytes_vec: Vec<[u8; 80]> = {
242 #[cfg(feature = "rayon")]
243 {
244 use rayon::prelude::*;
245 headers.par_iter().map(serialize_header).collect()
246 }
247 #[cfg(not(feature = "rayon"))]
248 {
249 headers.iter().map(serialize_header).collect()
250 }
251 };
252
253 let header_refs: Vec<&[u8]> = header_bytes_vec.iter().map(|v| v.as_slice()).collect();
255 let aligned_hashes = simd_vectorization::batch_double_sha256_aligned(&header_refs);
256 let hashes: Vec<[u8; 32]> = aligned_hashes.iter().map(|h| *h.as_bytes()).collect();
258
259 let mut results = Vec::with_capacity(headers.len());
261 for (i, header) in headers.iter().enumerate() {
262 let hash = hashes[i];
263
264 let hash_value = U256::from_bytes(&hash);
266
267 match expand_target(header.bits) {
269 Ok(target) => {
270 let is_valid = hash_value < target;
271 results.push((is_valid, if is_valid { Some(hash) } else { None }));
272 }
273 Err(_e) => {
274 results.push((false, None));
276 }
277 }
278 }
279
280 Ok(results)
281}
282
283#[derive(Debug, Clone, PartialEq, Eq)]
285pub struct U256([u64; 4]); impl U256 {
288 pub fn zero() -> Self {
289 U256([0; 4])
290 }
291
292 fn from_u32(value: u32) -> Self {
293 U256([value as u64, 0, 0, 0])
294 }
295
296 #[cfg(test)]
297 fn from_u64(value: u64) -> Self {
298 U256([value, 0, 0, 0])
299 }
300
301 fn get_low_64(&self) -> u64 {
304 self.0[0]
305 }
306
307 pub fn to_le_bytes(&self) -> [u8; 32] {
309 let mut bytes = [0u8; 32];
310 for (i, &word) in self.0.iter().enumerate() {
311 let word_bytes = word.to_le_bytes();
312 bytes[i * 8..(i + 1) * 8].copy_from_slice(&word_bytes);
313 }
314 bytes
315 }
316
317 pub fn gbt_target_hex(&self) -> String {
319 let mut bytes = self.to_le_bytes();
320 bytes.reverse();
321 hex::encode(bytes)
322 }
323
324 pub fn low_u128(&self) -> u128 {
326 self.0[0] as u128 | ((self.0[1] as u128) << 64)
327 }
328
329 pub fn is_zero(&self) -> bool {
330 self.0.iter().all(|&w| w == 0)
331 }
332
333 #[cfg(test)]
334 fn to_bytes(&self) -> [u8; 32] {
335 self.to_le_bytes()
336 }
337
338 fn shl(&self, shift: u32) -> Self {
339 if shift >= 256 {
340 return U256::zero();
341 }
342
343 let mut result = U256::zero();
344 let word_shift = (shift / 64) as usize;
345 let bit_shift = shift % 64;
346
347 for i in 0..4 {
348 if i + word_shift < 4 {
349 result.0[i + word_shift] |= self.0[i] << bit_shift;
350 if bit_shift > 0 && i + word_shift + 1 < 4 {
351 result.0[i + word_shift + 1] |= self.0[i] >> (64 - bit_shift);
352 }
353 }
354 }
355
356 result
357 }
358
359 fn shr(&self, shift: u32) -> Self {
360 if shift >= 256 {
361 return U256::zero();
362 }
363
364 let mut result = U256::zero();
365 let word_shift = (shift / 64) as usize;
366 let bit_shift = shift % 64;
367
368 debug_assert!(
370 word_shift < 4,
371 "Word shift ({word_shift}) must be < 4 (shift: {shift})"
372 );
373
374 debug_assert!(
376 bit_shift < 64,
377 "Bit shift ({bit_shift}) must be < 64 (shift: {shift})"
378 );
379
380 if bit_shift == 0 {
381 for i in word_shift..4 {
382 result.0[i - word_shift] = self.0[i];
383 }
384 } else {
385 for i in word_shift..4 {
388 let mut word = self.0[i] >> bit_shift;
389 if i + 1 < 4 {
390 word |= self.0[i + 1] << (64 - bit_shift);
391 }
392 result.0[i - word_shift] = word;
393 }
394 }
395
396 result
397 }
398
399 fn from_bytes(bytes: &[u8; 32]) -> Self {
400 let mut words = [0u64; 4];
401 for (i, word) in words.iter_mut().enumerate() {
402 let start = i * 8;
403 let _end = start + 8;
404 *word = u64::from_le_bytes([
405 bytes[start],
406 bytes[start + 1],
407 bytes[start + 2],
408 bytes[start + 3],
409 bytes[start + 4],
410 bytes[start + 5],
411 bytes[start + 6],
412 bytes[start + 7],
413 ]);
414 }
415 U256(words)
416 }
417
418 fn checked_mul_u64(&self, rhs: u64) -> Option<Self> {
421 let mut carry = 0u128;
423 let mut result = U256::zero();
424
425 #[cfg(feature = "production")]
428 {
429 let product = (self.0[0] as u128) * (rhs as u128) + carry;
432 result.0[0] = product as u64;
433 carry = product >> 64;
434
435 let product = (self.0[1] as u128) * (rhs as u128) + carry;
437 result.0[1] = product as u64;
438 carry = product >> 64;
439
440 let product = (self.0[2] as u128) * (rhs as u128) + carry;
442 result.0[2] = product as u64;
443 carry = product >> 64;
444
445 let product = (self.0[3] as u128) * (rhs as u128) + carry;
447 result.0[3] = product as u64;
448 carry = product >> 64;
449
450 if carry > 0 {
452 return None; }
454 }
455
456 #[cfg(not(feature = "production"))]
457 {
458 for i in 0..4 {
459 let product = (self.0[i] as u128) * (rhs as u128) + carry;
460 result.0[i] = product as u64;
461 carry = product >> 64;
462
463 if i == 3 && carry > 0 {
465 return None; }
467 }
468 }
469
470 Some(result)
471 }
472
473 fn div_u64(&self, rhs: u64) -> Self {
480 if rhs == 0 {
481 return U256([u64::MAX; 4]);
484 }
485
486 let mut remainder = 0u128;
487 let mut result = U256::zero();
488
489 #[cfg(feature = "production")]
493 {
494 let dividend = (remainder << 64) | (self.0[3] as u128);
497 let quotient = dividend / (rhs as u128);
498 remainder = dividend % (rhs as u128);
499 debug_assert!(quotient <= u64::MAX as u128, "Quotient must fit in u64");
500 result.0[3] = quotient as u64;
501
502 let dividend = (remainder << 64) | (self.0[2] as u128);
504 let quotient = dividend / (rhs as u128);
505 remainder = dividend % (rhs as u128);
506 debug_assert!(quotient <= u64::MAX as u128, "Quotient must fit in u64");
507 result.0[2] = quotient as u64;
508
509 let dividend = (remainder << 64) | (self.0[1] as u128);
511 let quotient = dividend / (rhs as u128);
512 remainder = dividend % (rhs as u128);
513 debug_assert!(quotient <= u64::MAX as u128, "Quotient must fit in u64");
514 result.0[1] = quotient as u64;
515
516 let dividend = (remainder << 64) | (self.0[0] as u128);
518 let quotient = dividend / (rhs as u128);
519 remainder = dividend % (rhs as u128);
520 debug_assert!(quotient <= u64::MAX as u128, "Quotient must fit in u64");
521 result.0[0] = quotient as u64;
522 }
523
524 #[cfg(not(feature = "production"))]
525 {
526 for i in (0..4).rev() {
528 let dividend = (remainder << 64) | (self.0[i] as u128);
529 let quotient = dividend / (rhs as u128);
530 remainder = dividend % (rhs as u128);
531 debug_assert!(
532 quotient <= u64::MAX as u128,
533 "Quotient ({quotient}) must fit in u64"
534 );
535 result.0[i] = quotient as u64;
536 }
537 }
538
539 debug_assert!(
541 result <= *self,
542 "Division result ({result:?}) must be <= dividend ({self:?})"
543 );
544
545 debug_assert!(
547 remainder < rhs as u128,
548 "Remainder ({remainder}) must be < divisor ({rhs})"
549 );
550
551 result
552 }
553
554 fn highest_set_bit(&self) -> Option<u32> {
557 for (i, &word) in self.0.iter().rev().enumerate() {
558 if word != 0 {
559 let word_index = (3 - i) as u32;
560 let bit_pos = word_index * 64 + (63 - word.leading_zeros());
561 return Some(bit_pos);
562 }
563 }
564 None
565 }
566
567 fn to_f64(&self) -> f64 {
570 if self.is_zero() {
571 return 0.0;
572 }
573 let mut result = 0.0_f64;
574 result += self.0[0] as f64;
575 result += (self.0[1] as f64) * 2.0_f64.powi(64);
576 result += (self.0[2] as f64) * 2.0_f64.powi(128);
577 result += (self.0[3] as f64) * 2.0_f64.powi(192);
578 result
579 }
580}
581
582impl PartialOrd for U256 {
583 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
584 Some(self.cmp(other))
585 }
586}
587
588impl Ord for U256 {
589 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
590 for (a, b) in self.0.iter().rev().zip(other.0.iter().rev()) {
591 match a.cmp(b) {
592 std::cmp::Ordering::Equal => continue,
593 other => return other,
594 }
595 }
596 std::cmp::Ordering::Equal
597 }
598}
599
600pub fn difficulty_from_bits(bits: Natural) -> Result<f64> {
605 let target = expand_target(bits)?;
606 if target.is_zero() {
607 return Ok(1.0);
608 }
609 let max_target = U256::from_bytes(&[
611 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,
612 0xFF, 0x00, 0x00, 0x00, 0x00,
613 ]);
614 let max_f64 = max_target.to_f64();
615 let target_f64 = target.to_f64();
616 if target_f64 == 0.0 {
617 return Ok(1.0);
618 }
619 Ok((max_f64 / target_f64).max(1.0))
620}
621
622#[spec_locked("7.1", "ExpandTarget")]
652pub fn expand_target(bits: Natural) -> Result<U256> {
653 let exponent = (bits >> 24) as u8;
665 let mantissa = bits & 0x007fffff;
667
668 if !(3..=32).contains(&exponent) {
671 return Err(ConsensusError::InvalidProofOfWork(
672 "Invalid target exponent".into(),
673 ));
674 }
675
676 if mantissa == 0 {
677 return Ok(U256::zero());
678 }
679
680 if exponent <= 3 {
682 let shift = 8 * (3 - exponent);
687 let mantissa_u256 = U256::from_u32(mantissa as u32);
688 Ok(mantissa_u256.shr(shift as u32))
689 } else {
690 let shift = 8u32 * (exponent as u32 - 3);
694 if shift >= 256 {
695 return Err(crate::error::ConsensusError::InvalidProofOfWork(
696 "Target too large".into(),
697 ));
698 }
699 let mantissa_u256 = U256::from_u32(mantissa as u32);
700 Ok(mantissa_u256.shl(shift))
701 }
702}
703
704fn compress_target(target: &U256) -> Result<Natural> {
733 if target.is_zero() {
735 return Ok(0x1d000000); }
737
738 let highest_bit = target
740 .highest_set_bit()
741 .ok_or_else(|| ConsensusError::InvalidProofOfWork("Cannot compress zero target".into()))?;
742
743 let n_size = (highest_bit + 1).div_ceil(8);
746
747 let mut n_compact: u64;
750
751 if n_size <= 3 {
752 let low_64 = target.get_low_64();
755 let shift_bytes = 3 - n_size;
756 n_compact = low_64 << (8 * shift_bytes);
757 } else {
758 let shift_bytes = n_size - 3;
761 let shifted = target.shr(shift_bytes * 8);
762 n_compact = shifted.get_low_64();
763 }
764
765 let mut n_size_final = n_size;
769 while (n_compact & 0x00800000) != 0 {
770 n_compact >>= 8;
771 n_size_final += 1;
772 }
773
774 let mantissa = (n_compact & 0x007fffff) as u32;
777
778 if n_size_final > 29 {
780 return Err(ConsensusError::InvalidProofOfWork(
781 format!("Target too large: exponent {n_size_final} exceeds maximum 29").into(),
782 ));
783 }
784
785 let bits = (n_size_final << 24) | mantissa;
787
788 Ok(bits as Natural)
789}
790
791fn serialize_header(header: &BlockHeader) -> [u8; 80] {
793 let mut bytes = [0u8; 80];
795
796 bytes[0..4].copy_from_slice(&(header.version as u32).to_le_bytes());
797 bytes[4..36].copy_from_slice(&header.prev_block_hash);
798 bytes[36..68].copy_from_slice(&header.merkle_root);
799 bytes[68..72].copy_from_slice(&(header.timestamp as u32).to_le_bytes());
800 bytes[72..76].copy_from_slice(&(header.bits as u32).to_le_bytes());
801 bytes[76..80].copy_from_slice(&(header.nonce as u32).to_le_bytes());
802
803 bytes
804}
805
806#[cfg(test)]
807fn u256_from_bytes(bytes: &[u8]) -> u128 {
809 let mut value = 0u128;
810 for (i, &byte) in bytes.iter().enumerate() {
811 if i < 16 {
812 value |= (byte as u128) << (8 * (15 - i));
814 }
815 }
816 value
817}
818
819#[cfg(test)]
833mod property_tests {
834 use super::*;
835 use proptest::prelude::*;
836
837 fn arb_block_header() -> impl Strategy<Value = BlockHeader> {
838 (
839 any::<i64>(),
840 any::<[u8; 32]>(),
841 any::<[u8; 32]>(),
842 any::<u64>(),
843 0x03000000u32..0x1d00ffffu32,
844 any::<u64>(),
845 )
846 .prop_map(
847 |(version, prev_block_hash, merkle_root, timestamp, bits, nonce)| BlockHeader {
848 version,
849 prev_block_hash,
850 merkle_root,
851 timestamp,
852 bits: bits as u64,
853 nonce,
854 },
855 )
856 }
857
858 proptest! {
860 #[test]
861 fn prop_expand_target_valid_range(
862 bits in 0x03000000u32..0x1d00ffffu32
863 ) {
864 let result = expand_target(bits as u64);
865 let mantissa = bits & 0x00ffffff;
866
867 match result {
868 Ok(target) => {
869 prop_assert!(target >= U256::zero(), "Target must be non-negative");
871
872 if mantissa == 0 {
877 prop_assert!(target.is_zero(), "Zero mantissa should produce zero target");
878 } else {
879 prop_assert!(!target.is_zero(), "Non-zero mantissa should produce non-zero target");
880 }
881 },
882 Err(_) => {
883 }
885 }
886 }
887 }
888
889 proptest! {
891 #[test]
892 fn prop_check_proof_of_work_deterministic(
893 header in arb_block_header()
894 ) {
895 let mut valid_header = header;
897 valid_header.bits = 0x1d00ffff; let result1 = check_proof_of_work(&valid_header).unwrap_or(false);
901 let result2 = check_proof_of_work(&valid_header).unwrap_or(false);
902
903 prop_assert_eq!(result1, result2, "Proof of work check must be deterministic");
905 }
906 }
907
908 proptest! {
910 #[test]
911 fn prop_get_next_work_required_bounds(
912 current_header in arb_block_header(),
913 prev_headers in proptest::collection::vec(arb_block_header(), 2..6)
914 ) {
915 let mut valid_headers = prev_headers;
917 if let Some(first_header) = valid_headers.first_mut() {
918 first_header.timestamp = current_header.timestamp - 86400 * 14; }
920
921 let result = get_next_work_required(¤t_header, &valid_headers);
922
923 match result {
924 Ok(work) => {
925 prop_assert!(work <= MAX_TARGET as Natural,
927 "Next work required must not exceed maximum target");
928 prop_assert!(work > 0, "Next work required must be positive");
929 },
930 Err(_) => {
931 }
933 }
934 }
935 }
936}
937
938#[cfg(test)]
939mod tests {
940 use super::*;
941 use crate::constants::MAX_TARGET;
942
943 #[test]
944 fn test_get_next_work_required_insufficient_headers() {
945 let header = BlockHeader {
946 version: 1,
947 prev_block_hash: [0; 32],
948 merkle_root: [0; 32],
949 timestamp: 1231006505,
950 bits: 0x1d00ffff,
951 nonce: 0,
952 };
953
954 let prev_headers = vec![header.clone()];
955 let result = get_next_work_required(&header, &prev_headers);
956
957 assert!(result.is_err());
959 }
960
961 #[test]
962 fn test_get_next_work_required_normal_adjustment() {
963 let header1 = BlockHeader {
964 version: 1,
965 prev_block_hash: [0; 32],
966 merkle_root: [0; 32],
967 timestamp: 1000000,
968 bits: 0x1d00ffff,
969 nonce: 0,
970 };
971
972 let header2 = BlockHeader {
973 version: 1,
974 prev_block_hash: [0; 32],
975 merkle_root: [0; 32],
976 timestamp: 1000000 + (DIFFICULTY_ADJUSTMENT_INTERVAL * TARGET_TIME_PER_BLOCK), bits: 0x1d00ffff,
978 nonce: 0,
979 };
980
981 let prev_headers = vec![header1, header2.clone()];
982 let result = get_next_work_required(&header2, &prev_headers).unwrap();
983
984 assert_eq!(result, 0x1d00ffff);
986 }
987
988 #[test]
989 fn test_difficulty_from_bits() {
990 let d = difficulty_from_bits(0x1d00ffff).unwrap();
992 assert!(
993 (d - 1.0).abs() < 0.01,
994 "Genesis difficulty should be ~1.0, got {d}"
995 );
996 let d_harder = difficulty_from_bits(0x1d000800).unwrap();
998 assert!(d_harder > d, "Harder target should have higher difficulty");
999 }
1000
1001 #[test]
1002 fn test_expand_target() {
1003 let target = expand_target(0x0300ffff).unwrap(); assert!(!target.is_zero());
1007 }
1008
1009 #[test]
1010 fn test_check_proof_of_work_genesis() {
1011 let header = BlockHeader {
1013 version: 1,
1014 prev_block_hash: [0; 32],
1015 merkle_root: [0; 32],
1016 timestamp: 1231006505,
1017 bits: 0x0300ffff, nonce: 0,
1019 };
1020
1021 let result = check_proof_of_work(&header).unwrap();
1023 let _ = result;
1026 }
1027
1028 #[test]
1033 fn test_get_next_work_required_fast_blocks() {
1034 let header1 = BlockHeader {
1035 version: 1,
1036 prev_block_hash: [0; 32],
1037 merkle_root: [0; 32],
1038 timestamp: 1000000,
1039 bits: 0x1d00ffff,
1040 nonce: 0,
1041 };
1042
1043 let header2 = BlockHeader {
1045 version: 1,
1046 prev_block_hash: [0; 32],
1047 merkle_root: [0; 32],
1048 timestamp: 1000000 + (DIFFICULTY_ADJUSTMENT_INTERVAL * TARGET_TIME_PER_BLOCK / 2),
1049 bits: 0x1d00ffff,
1050 nonce: 0,
1051 };
1052
1053 let prev_headers = vec![header1, header2.clone()];
1054 let result = get_next_work_required(&header2, &prev_headers).unwrap();
1055
1056 assert!(result <= 0x1d00ffff);
1059 }
1060
1061 #[test]
1062 fn test_get_next_work_required_slow_blocks() {
1063 let header1 = BlockHeader {
1064 version: 1,
1065 prev_block_hash: [0; 32],
1066 merkle_root: [0; 32],
1067 timestamp: 1000000,
1068 bits: 0x1d00ffff,
1069 nonce: 0,
1070 };
1071
1072 let header2 = BlockHeader {
1074 version: 1,
1075 prev_block_hash: [0; 32],
1076 merkle_root: [0; 32],
1077 timestamp: 1000000 + (DIFFICULTY_ADJUSTMENT_INTERVAL * TARGET_TIME_PER_BLOCK * 2),
1078 bits: 0x1d00ffff,
1079 nonce: 0,
1080 };
1081
1082 let prev_headers = vec![header1, header2.clone()];
1083 let result = get_next_work_required(&header2, &prev_headers).unwrap();
1084
1085 assert!(result <= 0x1d00ffff);
1088 }
1089
1090 #[test]
1091 fn test_get_next_work_required_extreme_fast_blocks() {
1092 let header1 = BlockHeader {
1093 version: 1,
1094 prev_block_hash: [0; 32],
1095 merkle_root: [0; 32],
1096 timestamp: 1000000,
1097 bits: 0x1d00ffff,
1098 nonce: 0,
1099 };
1100
1101 let header2 = BlockHeader {
1103 version: 1,
1104 prev_block_hash: [0; 32],
1105 merkle_root: [0; 32],
1106 timestamp: 1000000 + (DIFFICULTY_ADJUSTMENT_INTERVAL * TARGET_TIME_PER_BLOCK / 14),
1107 bits: 0x1d00ffff,
1108 nonce: 0,
1109 };
1110
1111 let prev_headers = vec![header1, header2.clone()];
1112 let result = get_next_work_required(&header2, &prev_headers).unwrap();
1113
1114 assert!(result <= 0x1d00ffff);
1117 }
1118
1119 #[test]
1120 fn test_get_next_work_required_extreme_slow_blocks() {
1121 let header1 = BlockHeader {
1122 version: 1,
1123 prev_block_hash: [0; 32],
1124 merkle_root: [0; 32],
1125 timestamp: 1000000,
1126 bits: 0x1d00ffff,
1127 nonce: 0,
1128 };
1129
1130 let header2 = BlockHeader {
1132 version: 1,
1133 prev_block_hash: [0; 32],
1134 merkle_root: [0; 32],
1135 timestamp: 1000000 + (DIFFICULTY_ADJUSTMENT_INTERVAL * TARGET_TIME_PER_BLOCK * 4),
1136 bits: 0x1d00ffff,
1137 nonce: 0,
1138 };
1139
1140 let prev_headers = vec![header1, header2.clone()];
1141 let result = get_next_work_required(&header2, &prev_headers).unwrap();
1142
1143 assert!(result <= 0x1d00ffff);
1146 }
1147
1148 #[test]
1149 fn test_expand_target_zero_mantissa() {
1150 let result = expand_target(0x1d000000).unwrap();
1151 assert!(result.is_zero());
1152 }
1153
1154 #[test]
1155 fn test_expand_target_invalid_exponent_too_small() {
1156 let result = expand_target(0x0200ffff);
1157 assert!(result.is_err());
1158 }
1159
1160 #[test]
1161 fn test_expand_target_invalid_exponent_too_large() {
1162 let result = expand_target(0x2100ffff);
1163 assert!(result.is_err());
1164 }
1165
1166 #[test]
1167 fn test_expand_target_exponent_31() {
1168 let result = expand_target(0x1f00ffff).unwrap(); assert!(!result.is_zero());
1170 }
1171
1172 #[test]
1173 fn test_expand_target_exponent_32_regtest_bits() {
1174 let result = expand_target(0x2000ffff).unwrap();
1176 assert!(!result.is_zero());
1177 }
1178
1179 #[test]
1180 fn test_gbt_target_hex_regtest_minimum_difficulty() {
1181 let target = expand_target(0x207fffff).expect("regtest nBits");
1182 let hex = target.gbt_target_hex();
1183 assert_eq!(hex.len(), 64);
1184 assert_ne!(hex, "0".repeat(64));
1185 assert!(hex.starts_with("7fffff"));
1187 }
1188
1189 #[test]
1190 fn test_expand_target_exponent_3() {
1191 let result = expand_target(0x0300ffff).unwrap();
1192 assert!(!result.is_zero());
1193 }
1194
1195 #[test]
1196 fn test_expand_target_exponent_4() {
1197 let result = expand_target(0x0400ffff).unwrap();
1198 assert!(!result.is_zero());
1199 }
1200
1201 #[test]
1202 fn test_expand_target_exponent_29() {
1203 let result = expand_target(0x1d00ffff).unwrap();
1204 assert!(!result.is_zero());
1205 }
1206
1207 #[test]
1208 fn test_check_proof_of_work_invalid_target() {
1209 let header = BlockHeader {
1212 version: 1,
1213 prev_block_hash: [0; 32],
1214 merkle_root: [0; 32],
1215 timestamp: 1231006505,
1216 bits: 0x0200ffff, nonce: 0,
1218 };
1219
1220 let result = check_proof_of_work(&header);
1221 assert!(result.is_err());
1222 }
1223
1224 #[test]
1225 fn test_check_proof_of_work_valid_target() {
1226 let header = BlockHeader {
1227 version: 1,
1228 prev_block_hash: [0; 32],
1229 merkle_root: [0; 32],
1230 timestamp: 1231006505,
1231 bits: 0x1d00ffff, nonce: 0,
1233 };
1234
1235 let result = check_proof_of_work(&header).unwrap();
1236 let _ = result;
1238 }
1239
1240 #[test]
1241 fn test_u256_zero() {
1242 let zero = U256::zero();
1243 assert!(zero.is_zero());
1244 }
1245
1246 #[test]
1247 fn test_u256_from_u32() {
1248 let value = U256::from_u32(0x12345678);
1249 assert!(!value.is_zero());
1250 }
1251
1252 #[test]
1253 fn test_u256_from_u64() {
1254 let value = U256::from_u64(0x123456789abcdef0);
1255 assert!(!value.is_zero());
1256 }
1257
1258 #[test]
1259 fn test_u256_shl_zero_shift() {
1260 let value = U256::from_u32(0x12345678);
1261 let result = value.shl(0);
1262 assert_eq!(result, value);
1263 }
1264
1265 #[test]
1266 fn test_u256_shl_large_shift() {
1267 let value = U256::from_u32(0x12345678);
1268 let result = value.shl(300); assert!(result.is_zero());
1270 }
1271
1272 #[test]
1273 fn test_u256_shr_zero_shift() {
1274 let value = U256::from_u32(0x12345678);
1275 let result = value.shr(0);
1276 assert_eq!(result, value);
1277 }
1278
1279 #[test]
1280 fn test_u256_shr_large_shift() {
1281 let value = U256::from_u32(0x12345678);
1282 let result = value.shr(300); assert!(result.is_zero());
1284 }
1285
1286 #[test]
1287 fn test_u256_shl_small_shift() {
1288 let value = U256::from_u32(0x12345678);
1289 let result = value.shl(8);
1290 assert!(!result.is_zero());
1291 assert_ne!(result, value);
1292 }
1293
1294 #[test]
1295 fn test_u256_shr_small_shift() {
1296 let value = U256::from_u32(0x12345678);
1297 let result = value.shr(8);
1298 assert!(!result.is_zero());
1299 assert_ne!(result, value);
1300 }
1301
1302 #[test]
1303 fn test_u256_to_bytes() {
1304 let value = U256::from_u32(0x12345678);
1305 let bytes = value.to_bytes();
1306 assert_eq!(bytes.len(), 32);
1307 }
1308
1309 #[test]
1310 fn test_u256_from_bytes() {
1311 let mut bytes = [0u8; 32];
1312 bytes[0] = 0x78;
1313 bytes[1] = 0x56;
1314 bytes[2] = 0x34;
1315 bytes[3] = 0x12;
1316 let value = U256::from_bytes(&bytes);
1317 assert!(!value.is_zero());
1318 }
1319
1320 #[test]
1321 fn test_u256_ordering() {
1322 let small = U256::from_u32(0x12345678);
1323 let large = U256::from_u32(0x87654321);
1324
1325 assert!(small < large);
1326 assert!(large > small);
1327 assert_eq!(small.cmp(&small), std::cmp::Ordering::Equal);
1328 }
1329
1330 #[test]
1331 fn test_expand_compress_round_trip() {
1332 let test_bits = vec![
1334 0x1d00ffff, 0x1b0404cb, 0x0300ffff, ];
1341
1342 for &bits in &test_bits {
1343 let expanded = match expand_target(bits) {
1345 Ok(t) => t,
1346 Err(_) => continue, };
1348
1349 let compressed = match compress_target(&expanded) {
1351 Ok(b) => b,
1352 Err(_) => {
1353 continue;
1356 }
1357 };
1358
1359 let re_expanded = match expand_target(compressed) {
1361 Ok(t) => t,
1362 Err(_) => continue,
1363 };
1364
1365 if re_expanded > expanded {
1369 panic!(
1370 "Round-trip failed for bits 0x{bits:08x}: re-expanded > original (compression should truncate, not add)"
1371 );
1372 }
1373 #[allow(clippy::eq_op)]
1380 let significant_words_match =
1381 expanded.0[2] == re_expanded.0[2] && expanded.0[3] == re_expanded.0[3];
1382 if !significant_words_match {
1383 panic!(
1384 "Round-trip failed for bits 0x{:08x}: significant bits differ (expanded: {:?}, re-expanded: {:?})",
1385 bits, expanded.0, re_expanded.0
1386 );
1387 }
1388 }
1390 }
1391
1392 #[test]
1393 fn test_compress_target_genesis() {
1394 let genesis_bits = 0x1d00ffff;
1396 let expanded = expand_target(genesis_bits).unwrap();
1397 let compressed = compress_target(&expanded).unwrap();
1398
1399 assert!(compressed <= MAX_TARGET as u64);
1401 assert!(compressed > 0);
1402
1403 let re_expanded = expand_target(compressed).unwrap();
1405 assert_eq!(expanded, re_expanded);
1406 }
1407
1408 #[test]
1409 fn test_serialize_header() {
1410 let header = BlockHeader {
1411 version: 1,
1412 prev_block_hash: [1; 32],
1413 merkle_root: [2; 32],
1414 timestamp: 1234567890,
1415 bits: 0x1d00ffff,
1416 nonce: 0x12345678,
1417 };
1418
1419 let bytes = serialize_header(&header);
1420 assert_eq!(bytes.len(), 80); }
1422
1423 #[test]
1428 fn test_serialize_header_returns_fixed_80_bytes() {
1429 let header = BlockHeader {
1431 version: 1,
1432 prev_block_hash: [0; 32],
1433 merkle_root: [0; 32],
1434 timestamp: 0,
1435 bits: 0,
1436 nonce: 0,
1437 };
1438 let bytes: [u8; 80] = serialize_header(&header);
1439 assert_eq!(bytes.len(), 80);
1440 }
1441
1442 #[test]
1443 fn test_serialize_header_field_layout() {
1444 let header = BlockHeader {
1446 version: 0x01020304,
1447 prev_block_hash: {
1448 let mut h = [0u8; 32];
1449 h[0] = 0xAA;
1450 h[31] = 0xBB;
1451 h
1452 },
1453 merkle_root: {
1454 let mut h = [0u8; 32];
1455 h[0] = 0xCC;
1456 h[31] = 0xDD;
1457 h
1458 },
1459 timestamp: 0x05060708,
1460 bits: 0x090A0B0C,
1461 nonce: 0x0D0E0F10,
1462 };
1463
1464 let bytes = serialize_header(&header);
1465
1466 assert_eq!(bytes[0], 0x04); assert_eq!(bytes[1], 0x03);
1469 assert_eq!(bytes[2], 0x02);
1470 assert_eq!(bytes[3], 0x01);
1471
1472 assert_eq!(bytes[4], 0xAA);
1474 assert_eq!(bytes[35], 0xBB);
1475
1476 assert_eq!(bytes[36], 0xCC);
1478 assert_eq!(bytes[67], 0xDD);
1479
1480 assert_eq!(bytes[68], 0x08);
1482 assert_eq!(bytes[69], 0x07);
1483 assert_eq!(bytes[70], 0x06);
1484 assert_eq!(bytes[71], 0x05);
1485
1486 assert_eq!(bytes[72], 0x0C);
1488 assert_eq!(bytes[73], 0x0B);
1489 assert_eq!(bytes[74], 0x0A);
1490 assert_eq!(bytes[75], 0x09);
1491
1492 assert_eq!(bytes[76], 0x10);
1494 assert_eq!(bytes[77], 0x0F);
1495 assert_eq!(bytes[78], 0x0E);
1496 assert_eq!(bytes[79], 0x0D);
1497 }
1498
1499 #[test]
1500 fn test_serialize_header_deterministic() {
1501 let header = BlockHeader {
1502 version: 1,
1503 prev_block_hash: [0xFF; 32],
1504 merkle_root: [0xAA; 32],
1505 timestamp: 1231006505,
1506 bits: 0x1d00ffff,
1507 nonce: 2083236893,
1508 };
1509
1510 let bytes1 = serialize_header(&header);
1511 let bytes2 = serialize_header(&header);
1512 assert_eq!(bytes1, bytes2, "Header serialization must be deterministic");
1513 }
1514
1515 #[test]
1516 fn test_serialize_header_different_headers_different_bytes() {
1517 let header1 = BlockHeader {
1518 version: 1,
1519 prev_block_hash: [0; 32],
1520 merkle_root: [0; 32],
1521 timestamp: 1231006505,
1522 bits: 0x1d00ffff,
1523 nonce: 0,
1524 };
1525
1526 let mut header2 = header1.clone();
1527 header2.nonce = 1;
1528
1529 let bytes1 = serialize_header(&header1);
1530 let bytes2 = serialize_header(&header2);
1531 assert_ne!(
1532 bytes1, bytes2,
1533 "Different nonces must produce different serializations"
1534 );
1535
1536 assert_eq!(
1538 bytes1[..76],
1539 bytes2[..76],
1540 "Non-nonce bytes should be identical"
1541 );
1542 assert_ne!(bytes1[76..], bytes2[76..], "Nonce bytes should differ");
1543 }
1544
1545 #[test]
1546 fn test_u256_from_bytes_simple() {
1547 let bytes = [0u8; 32];
1548 let value = u256_from_bytes(&bytes);
1549 assert_eq!(value, 0);
1550 }
1551
1552 #[test]
1553 fn test_u256_from_bytes_with_data() {
1554 let mut bytes = [0u8; 32];
1555 bytes[0] = 0x78;
1556 bytes[1] = 0x56;
1557 bytes[2] = 0x34;
1558 bytes[3] = 0x12;
1559 let value = u256_from_bytes(&bytes);
1560 assert_eq!(value, 0x78563412000000000000000000000000);
1563 }
1564}