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 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 #[cfg(test)]
308 fn to_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 fn shl(&self, shift: u32) -> Self {
318 if shift >= 256 {
319 return U256::zero();
320 }
321
322 let mut result = U256::zero();
323 let word_shift = (shift / 64) as usize;
324 let bit_shift = shift % 64;
325
326 for i in 0..4 {
327 if i + word_shift < 4 {
328 result.0[i + word_shift] |= self.0[i] << bit_shift;
329 if bit_shift > 0 && i + word_shift + 1 < 4 {
330 result.0[i + word_shift + 1] |= self.0[i] >> (64 - bit_shift);
331 }
332 }
333 }
334
335 result
336 }
337
338 fn shr(&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 debug_assert!(
349 word_shift < 4,
350 "Word shift ({word_shift}) must be < 4 (shift: {shift})"
351 );
352
353 debug_assert!(
355 bit_shift < 64,
356 "Bit shift ({bit_shift}) must be < 64 (shift: {shift})"
357 );
358
359 if bit_shift == 0 {
360 for i in word_shift..4 {
361 result.0[i - word_shift] = self.0[i];
362 }
363 } else {
364 for i in word_shift..4 {
367 let mut word = self.0[i] >> bit_shift;
368 if i + 1 < 4 {
369 word |= self.0[i + 1] << (64 - bit_shift);
370 }
371 result.0[i - word_shift] = word;
372 }
373 }
374
375 result
376 }
377
378 fn from_bytes(bytes: &[u8; 32]) -> Self {
379 let mut words = [0u64; 4];
380 for (i, word) in words.iter_mut().enumerate() {
381 let start = i * 8;
382 let _end = start + 8;
383 *word = u64::from_le_bytes([
384 bytes[start],
385 bytes[start + 1],
386 bytes[start + 2],
387 bytes[start + 3],
388 bytes[start + 4],
389 bytes[start + 5],
390 bytes[start + 6],
391 bytes[start + 7],
392 ]);
393 }
394 U256(words)
395 }
396
397 fn checked_mul_u64(&self, rhs: u64) -> Option<Self> {
400 let mut carry = 0u128;
402 let mut result = U256::zero();
403
404 #[cfg(feature = "production")]
407 {
408 let product = (self.0[0] as u128) * (rhs as u128) + carry;
411 result.0[0] = product as u64;
412 carry = product >> 64;
413
414 let product = (self.0[1] as u128) * (rhs as u128) + carry;
416 result.0[1] = product as u64;
417 carry = product >> 64;
418
419 let product = (self.0[2] as u128) * (rhs as u128) + carry;
421 result.0[2] = product as u64;
422 carry = product >> 64;
423
424 let product = (self.0[3] as u128) * (rhs as u128) + carry;
426 result.0[3] = product as u64;
427 carry = product >> 64;
428
429 if carry > 0 {
431 return None; }
433 }
434
435 #[cfg(not(feature = "production"))]
436 {
437 for i in 0..4 {
438 let product = (self.0[i] as u128) * (rhs as u128) + carry;
439 result.0[i] = product as u64;
440 carry = product >> 64;
441
442 if i == 3 && carry > 0 {
444 return None; }
446 }
447 }
448
449 Some(result)
450 }
451
452 fn div_u64(&self, rhs: u64) -> Self {
459 if rhs == 0 {
460 return U256([u64::MAX; 4]);
463 }
464
465 let mut remainder = 0u128;
466 let mut result = U256::zero();
467
468 #[cfg(feature = "production")]
472 {
473 let dividend = (remainder << 64) | (self.0[3] as u128);
476 let quotient = dividend / (rhs as u128);
477 remainder = dividend % (rhs as u128);
478 debug_assert!(quotient <= u64::MAX as u128, "Quotient must fit in u64");
479 result.0[3] = quotient as u64;
480
481 let dividend = (remainder << 64) | (self.0[2] as u128);
483 let quotient = dividend / (rhs as u128);
484 remainder = dividend % (rhs as u128);
485 debug_assert!(quotient <= u64::MAX as u128, "Quotient must fit in u64");
486 result.0[2] = quotient as u64;
487
488 let dividend = (remainder << 64) | (self.0[1] as u128);
490 let quotient = dividend / (rhs as u128);
491 remainder = dividend % (rhs as u128);
492 debug_assert!(quotient <= u64::MAX as u128, "Quotient must fit in u64");
493 result.0[1] = quotient as u64;
494
495 let dividend = (remainder << 64) | (self.0[0] 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[0] = quotient as u64;
501 }
502
503 #[cfg(not(feature = "production"))]
504 {
505 for i in (0..4).rev() {
507 let dividend = (remainder << 64) | (self.0[i] as u128);
508 let quotient = dividend / (rhs as u128);
509 remainder = dividend % (rhs as u128);
510 debug_assert!(
511 quotient <= u64::MAX as u128,
512 "Quotient ({quotient}) must fit in u64"
513 );
514 result.0[i] = quotient as u64;
515 }
516 }
517
518 debug_assert!(
520 result <= *self,
521 "Division result ({result:?}) must be <= dividend ({self:?})"
522 );
523
524 debug_assert!(
526 remainder < rhs as u128,
527 "Remainder ({remainder}) must be < divisor ({rhs})"
528 );
529
530 result
531 }
532
533 fn highest_set_bit(&self) -> Option<u32> {
536 for (i, &word) in self.0.iter().rev().enumerate() {
537 if word != 0 {
538 let word_index = (3 - i) as u32;
539 let bit_pos = word_index * 64 + (63 - word.leading_zeros());
540 return Some(bit_pos);
541 }
542 }
543 None
544 }
545
546 fn is_zero(&self) -> bool {
548 self.0.iter().all(|&x| x == 0)
549 }
550
551 fn to_f64(&self) -> f64 {
554 if self.is_zero() {
555 return 0.0;
556 }
557 let mut result = 0.0_f64;
558 result += self.0[0] as f64;
559 result += (self.0[1] as f64) * 2.0_f64.powi(64);
560 result += (self.0[2] as f64) * 2.0_f64.powi(128);
561 result += (self.0[3] as f64) * 2.0_f64.powi(192);
562 result
563 }
564}
565
566impl PartialOrd for U256 {
567 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
568 Some(self.cmp(other))
569 }
570}
571
572impl Ord for U256 {
573 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
574 for (a, b) in self.0.iter().rev().zip(other.0.iter().rev()) {
575 match a.cmp(b) {
576 std::cmp::Ordering::Equal => continue,
577 other => return other,
578 }
579 }
580 std::cmp::Ordering::Equal
581 }
582}
583
584pub fn difficulty_from_bits(bits: Natural) -> Result<f64> {
589 let target = expand_target(bits)?;
590 if target.is_zero() {
591 return Ok(1.0);
592 }
593 let max_target = U256::from_bytes(&[
595 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,
596 0xFF, 0x00, 0x00, 0x00, 0x00,
597 ]);
598 let max_f64 = max_target.to_f64();
599 let target_f64 = target.to_f64();
600 if target_f64 == 0.0 {
601 return Ok(1.0);
602 }
603 Ok((max_f64 / target_f64).max(1.0))
604}
605
606#[spec_locked("7.1", "ExpandTarget")]
636pub fn expand_target(bits: Natural) -> Result<U256> {
637 let exponent = (bits >> 24) as u8;
649 let mantissa = bits & 0x007fffff;
651
652 if !(3..=32).contains(&exponent) {
655 return Err(ConsensusError::InvalidProofOfWork(
656 "Invalid target exponent".into(),
657 ));
658 }
659
660 if mantissa == 0 {
661 return Ok(U256::zero());
662 }
663
664 if exponent <= 3 {
666 let shift = 8 * (3 - exponent);
671 let mantissa_u256 = U256::from_u32(mantissa as u32);
672 Ok(mantissa_u256.shr(shift as u32))
673 } else {
674 let shift = 8u32 * (exponent as u32 - 3);
678 if shift >= 256 {
679 return Err(crate::error::ConsensusError::InvalidProofOfWork(
680 "Target too large".into(),
681 ));
682 }
683 let mantissa_u256 = U256::from_u32(mantissa as u32);
684 Ok(mantissa_u256.shl(shift))
685 }
686}
687
688fn compress_target(target: &U256) -> Result<Natural> {
717 if target.is_zero() {
719 return Ok(0x1d000000); }
721
722 let highest_bit = target
724 .highest_set_bit()
725 .ok_or_else(|| ConsensusError::InvalidProofOfWork("Cannot compress zero target".into()))?;
726
727 let n_size = (highest_bit + 1).div_ceil(8);
730
731 let mut n_compact: u64;
734
735 if n_size <= 3 {
736 let low_64 = target.get_low_64();
739 let shift_bytes = 3 - n_size;
740 n_compact = low_64 << (8 * shift_bytes);
741 } else {
742 let shift_bytes = n_size - 3;
745 let shifted = target.shr(shift_bytes * 8);
746 n_compact = shifted.get_low_64();
747 }
748
749 let mut n_size_final = n_size;
753 while (n_compact & 0x00800000) != 0 {
754 n_compact >>= 8;
755 n_size_final += 1;
756 }
757
758 let mantissa = (n_compact & 0x007fffff) as u32;
761
762 if n_size_final > 29 {
764 return Err(ConsensusError::InvalidProofOfWork(
765 format!("Target too large: exponent {n_size_final} exceeds maximum 29").into(),
766 ));
767 }
768
769 let bits = (n_size_final << 24) | mantissa;
771
772 Ok(bits as Natural)
773}
774
775fn serialize_header(header: &BlockHeader) -> [u8; 80] {
777 let mut bytes = [0u8; 80];
779
780 bytes[0..4].copy_from_slice(&(header.version as u32).to_le_bytes());
781 bytes[4..36].copy_from_slice(&header.prev_block_hash);
782 bytes[36..68].copy_from_slice(&header.merkle_root);
783 bytes[68..72].copy_from_slice(&(header.timestamp as u32).to_le_bytes());
784 bytes[72..76].copy_from_slice(&(header.bits as u32).to_le_bytes());
785 bytes[76..80].copy_from_slice(&(header.nonce as u32).to_le_bytes());
786
787 bytes
788}
789
790#[cfg(test)]
791fn u256_from_bytes(bytes: &[u8]) -> u128 {
793 let mut value = 0u128;
794 for (i, &byte) in bytes.iter().enumerate() {
795 if i < 16 {
796 value |= (byte as u128) << (8 * (15 - i));
798 }
799 }
800 value
801}
802
803#[cfg(test)]
817mod property_tests {
818 use super::*;
819 use proptest::prelude::*;
820
821 fn arb_block_header() -> impl Strategy<Value = BlockHeader> {
822 (
823 any::<i64>(),
824 any::<[u8; 32]>(),
825 any::<[u8; 32]>(),
826 any::<u64>(),
827 0x03000000u32..0x1d00ffffu32,
828 any::<u64>(),
829 )
830 .prop_map(
831 |(version, prev_block_hash, merkle_root, timestamp, bits, nonce)| BlockHeader {
832 version,
833 prev_block_hash,
834 merkle_root,
835 timestamp,
836 bits: bits as u64,
837 nonce,
838 },
839 )
840 }
841
842 proptest! {
844 #[test]
845 fn prop_expand_target_valid_range(
846 bits in 0x03000000u32..0x1d00ffffu32
847 ) {
848 let result = expand_target(bits as u64);
849 let mantissa = bits & 0x00ffffff;
850
851 match result {
852 Ok(target) => {
853 prop_assert!(target >= U256::zero(), "Target must be non-negative");
855
856 if mantissa == 0 {
861 prop_assert!(target.is_zero(), "Zero mantissa should produce zero target");
862 } else {
863 prop_assert!(!target.is_zero(), "Non-zero mantissa should produce non-zero target");
864 }
865 },
866 Err(_) => {
867 }
869 }
870 }
871 }
872
873 proptest! {
875 #[test]
876 fn prop_check_proof_of_work_deterministic(
877 header in arb_block_header()
878 ) {
879 let mut valid_header = header;
881 valid_header.bits = 0x1d00ffff; let result1 = check_proof_of_work(&valid_header).unwrap_or(false);
885 let result2 = check_proof_of_work(&valid_header).unwrap_or(false);
886
887 prop_assert_eq!(result1, result2, "Proof of work check must be deterministic");
889 }
890 }
891
892 proptest! {
894 #[test]
895 fn prop_get_next_work_required_bounds(
896 current_header in arb_block_header(),
897 prev_headers in proptest::collection::vec(arb_block_header(), 2..6)
898 ) {
899 let mut valid_headers = prev_headers;
901 if let Some(first_header) = valid_headers.first_mut() {
902 first_header.timestamp = current_header.timestamp - 86400 * 14; }
904
905 let result = get_next_work_required(¤t_header, &valid_headers);
906
907 match result {
908 Ok(work) => {
909 prop_assert!(work <= MAX_TARGET as Natural,
911 "Next work required must not exceed maximum target");
912 prop_assert!(work > 0, "Next work required must be positive");
913 },
914 Err(_) => {
915 }
917 }
918 }
919 }
920}
921
922#[cfg(test)]
923mod tests {
924 use super::*;
925 use crate::constants::MAX_TARGET;
926
927 #[test]
928 fn test_get_next_work_required_insufficient_headers() {
929 let header = BlockHeader {
930 version: 1,
931 prev_block_hash: [0; 32],
932 merkle_root: [0; 32],
933 timestamp: 1231006505,
934 bits: 0x1d00ffff,
935 nonce: 0,
936 };
937
938 let prev_headers = vec![header.clone()];
939 let result = get_next_work_required(&header, &prev_headers);
940
941 assert!(result.is_err());
943 }
944
945 #[test]
946 fn test_get_next_work_required_normal_adjustment() {
947 let header1 = BlockHeader {
948 version: 1,
949 prev_block_hash: [0; 32],
950 merkle_root: [0; 32],
951 timestamp: 1000000,
952 bits: 0x1d00ffff,
953 nonce: 0,
954 };
955
956 let header2 = BlockHeader {
957 version: 1,
958 prev_block_hash: [0; 32],
959 merkle_root: [0; 32],
960 timestamp: 1000000 + (DIFFICULTY_ADJUSTMENT_INTERVAL * TARGET_TIME_PER_BLOCK), bits: 0x1d00ffff,
962 nonce: 0,
963 };
964
965 let prev_headers = vec![header1, header2.clone()];
966 let result = get_next_work_required(&header2, &prev_headers).unwrap();
967
968 assert_eq!(result, 0x1d00ffff);
970 }
971
972 #[test]
973 fn test_difficulty_from_bits() {
974 let d = difficulty_from_bits(0x1d00ffff).unwrap();
976 assert!(
977 (d - 1.0).abs() < 0.01,
978 "Genesis difficulty should be ~1.0, got {d}"
979 );
980 let d_harder = difficulty_from_bits(0x1d000800).unwrap();
982 assert!(d_harder > d, "Harder target should have higher difficulty");
983 }
984
985 #[test]
986 fn test_expand_target() {
987 let target = expand_target(0x0300ffff).unwrap(); assert!(!target.is_zero());
991 }
992
993 #[test]
994 fn test_check_proof_of_work_genesis() {
995 let header = BlockHeader {
997 version: 1,
998 prev_block_hash: [0; 32],
999 merkle_root: [0; 32],
1000 timestamp: 1231006505,
1001 bits: 0x0300ffff, nonce: 0,
1003 };
1004
1005 let result = check_proof_of_work(&header).unwrap();
1007 let _ = result;
1010 }
1011
1012 #[test]
1017 fn test_get_next_work_required_fast_blocks() {
1018 let header1 = BlockHeader {
1019 version: 1,
1020 prev_block_hash: [0; 32],
1021 merkle_root: [0; 32],
1022 timestamp: 1000000,
1023 bits: 0x1d00ffff,
1024 nonce: 0,
1025 };
1026
1027 let header2 = BlockHeader {
1029 version: 1,
1030 prev_block_hash: [0; 32],
1031 merkle_root: [0; 32],
1032 timestamp: 1000000 + (DIFFICULTY_ADJUSTMENT_INTERVAL * TARGET_TIME_PER_BLOCK / 2),
1033 bits: 0x1d00ffff,
1034 nonce: 0,
1035 };
1036
1037 let prev_headers = vec![header1, header2.clone()];
1038 let result = get_next_work_required(&header2, &prev_headers).unwrap();
1039
1040 assert!(result <= 0x1d00ffff);
1043 }
1044
1045 #[test]
1046 fn test_get_next_work_required_slow_blocks() {
1047 let header1 = BlockHeader {
1048 version: 1,
1049 prev_block_hash: [0; 32],
1050 merkle_root: [0; 32],
1051 timestamp: 1000000,
1052 bits: 0x1d00ffff,
1053 nonce: 0,
1054 };
1055
1056 let header2 = BlockHeader {
1058 version: 1,
1059 prev_block_hash: [0; 32],
1060 merkle_root: [0; 32],
1061 timestamp: 1000000 + (DIFFICULTY_ADJUSTMENT_INTERVAL * TARGET_TIME_PER_BLOCK * 2),
1062 bits: 0x1d00ffff,
1063 nonce: 0,
1064 };
1065
1066 let prev_headers = vec![header1, header2.clone()];
1067 let result = get_next_work_required(&header2, &prev_headers).unwrap();
1068
1069 assert!(result <= 0x1d00ffff);
1072 }
1073
1074 #[test]
1075 fn test_get_next_work_required_extreme_fast_blocks() {
1076 let header1 = BlockHeader {
1077 version: 1,
1078 prev_block_hash: [0; 32],
1079 merkle_root: [0; 32],
1080 timestamp: 1000000,
1081 bits: 0x1d00ffff,
1082 nonce: 0,
1083 };
1084
1085 let header2 = BlockHeader {
1087 version: 1,
1088 prev_block_hash: [0; 32],
1089 merkle_root: [0; 32],
1090 timestamp: 1000000 + (DIFFICULTY_ADJUSTMENT_INTERVAL * TARGET_TIME_PER_BLOCK / 14),
1091 bits: 0x1d00ffff,
1092 nonce: 0,
1093 };
1094
1095 let prev_headers = vec![header1, header2.clone()];
1096 let result = get_next_work_required(&header2, &prev_headers).unwrap();
1097
1098 assert!(result <= 0x1d00ffff);
1101 }
1102
1103 #[test]
1104 fn test_get_next_work_required_extreme_slow_blocks() {
1105 let header1 = BlockHeader {
1106 version: 1,
1107 prev_block_hash: [0; 32],
1108 merkle_root: [0; 32],
1109 timestamp: 1000000,
1110 bits: 0x1d00ffff,
1111 nonce: 0,
1112 };
1113
1114 let header2 = BlockHeader {
1116 version: 1,
1117 prev_block_hash: [0; 32],
1118 merkle_root: [0; 32],
1119 timestamp: 1000000 + (DIFFICULTY_ADJUSTMENT_INTERVAL * TARGET_TIME_PER_BLOCK * 4),
1120 bits: 0x1d00ffff,
1121 nonce: 0,
1122 };
1123
1124 let prev_headers = vec![header1, header2.clone()];
1125 let result = get_next_work_required(&header2, &prev_headers).unwrap();
1126
1127 assert!(result <= 0x1d00ffff);
1130 }
1131
1132 #[test]
1133 fn test_expand_target_zero_mantissa() {
1134 let result = expand_target(0x1d000000).unwrap();
1135 assert!(result.is_zero());
1136 }
1137
1138 #[test]
1139 fn test_expand_target_invalid_exponent_too_small() {
1140 let result = expand_target(0x0200ffff);
1141 assert!(result.is_err());
1142 }
1143
1144 #[test]
1145 fn test_expand_target_invalid_exponent_too_large() {
1146 let result = expand_target(0x2100ffff);
1147 assert!(result.is_err());
1148 }
1149
1150 #[test]
1151 fn test_expand_target_exponent_31() {
1152 let result = expand_target(0x1f00ffff).unwrap(); assert!(!result.is_zero());
1154 }
1155
1156 #[test]
1157 fn test_expand_target_exponent_32_regtest_bits() {
1158 let result = expand_target(0x2000ffff).unwrap();
1160 assert!(!result.is_zero());
1161 }
1162
1163 #[test]
1164 fn test_expand_target_exponent_3() {
1165 let result = expand_target(0x0300ffff).unwrap();
1166 assert!(!result.is_zero());
1167 }
1168
1169 #[test]
1170 fn test_expand_target_exponent_4() {
1171 let result = expand_target(0x0400ffff).unwrap();
1172 assert!(!result.is_zero());
1173 }
1174
1175 #[test]
1176 fn test_expand_target_exponent_29() {
1177 let result = expand_target(0x1d00ffff).unwrap();
1178 assert!(!result.is_zero());
1179 }
1180
1181 #[test]
1182 fn test_check_proof_of_work_invalid_target() {
1183 let header = BlockHeader {
1186 version: 1,
1187 prev_block_hash: [0; 32],
1188 merkle_root: [0; 32],
1189 timestamp: 1231006505,
1190 bits: 0x0200ffff, nonce: 0,
1192 };
1193
1194 let result = check_proof_of_work(&header);
1195 assert!(result.is_err());
1196 }
1197
1198 #[test]
1199 fn test_check_proof_of_work_valid_target() {
1200 let header = BlockHeader {
1201 version: 1,
1202 prev_block_hash: [0; 32],
1203 merkle_root: [0; 32],
1204 timestamp: 1231006505,
1205 bits: 0x1d00ffff, nonce: 0,
1207 };
1208
1209 let result = check_proof_of_work(&header).unwrap();
1210 let _ = result;
1212 }
1213
1214 #[test]
1215 fn test_u256_zero() {
1216 let zero = U256::zero();
1217 assert!(zero.is_zero());
1218 }
1219
1220 #[test]
1221 fn test_u256_from_u32() {
1222 let value = U256::from_u32(0x12345678);
1223 assert!(!value.is_zero());
1224 }
1225
1226 #[test]
1227 fn test_u256_from_u64() {
1228 let value = U256::from_u64(0x123456789abcdef0);
1229 assert!(!value.is_zero());
1230 }
1231
1232 #[test]
1233 fn test_u256_shl_zero_shift() {
1234 let value = U256::from_u32(0x12345678);
1235 let result = value.shl(0);
1236 assert_eq!(result, value);
1237 }
1238
1239 #[test]
1240 fn test_u256_shl_large_shift() {
1241 let value = U256::from_u32(0x12345678);
1242 let result = value.shl(300); assert!(result.is_zero());
1244 }
1245
1246 #[test]
1247 fn test_u256_shr_zero_shift() {
1248 let value = U256::from_u32(0x12345678);
1249 let result = value.shr(0);
1250 assert_eq!(result, value);
1251 }
1252
1253 #[test]
1254 fn test_u256_shr_large_shift() {
1255 let value = U256::from_u32(0x12345678);
1256 let result = value.shr(300); assert!(result.is_zero());
1258 }
1259
1260 #[test]
1261 fn test_u256_shl_small_shift() {
1262 let value = U256::from_u32(0x12345678);
1263 let result = value.shl(8);
1264 assert!(!result.is_zero());
1265 assert_ne!(result, value);
1266 }
1267
1268 #[test]
1269 fn test_u256_shr_small_shift() {
1270 let value = U256::from_u32(0x12345678);
1271 let result = value.shr(8);
1272 assert!(!result.is_zero());
1273 assert_ne!(result, value);
1274 }
1275
1276 #[test]
1277 fn test_u256_to_bytes() {
1278 let value = U256::from_u32(0x12345678);
1279 let bytes = value.to_bytes();
1280 assert_eq!(bytes.len(), 32);
1281 }
1282
1283 #[test]
1284 fn test_u256_from_bytes() {
1285 let mut bytes = [0u8; 32];
1286 bytes[0] = 0x78;
1287 bytes[1] = 0x56;
1288 bytes[2] = 0x34;
1289 bytes[3] = 0x12;
1290 let value = U256::from_bytes(&bytes);
1291 assert!(!value.is_zero());
1292 }
1293
1294 #[test]
1295 fn test_u256_ordering() {
1296 let small = U256::from_u32(0x12345678);
1297 let large = U256::from_u32(0x87654321);
1298
1299 assert!(small < large);
1300 assert!(large > small);
1301 assert_eq!(small.cmp(&small), std::cmp::Ordering::Equal);
1302 }
1303
1304 #[test]
1305 fn test_expand_compress_round_trip() {
1306 let test_bits = vec![
1308 0x1d00ffff, 0x1b0404cb, 0x0300ffff, ];
1315
1316 for &bits in &test_bits {
1317 let expanded = match expand_target(bits) {
1319 Ok(t) => t,
1320 Err(_) => continue, };
1322
1323 let compressed = match compress_target(&expanded) {
1325 Ok(b) => b,
1326 Err(_) => {
1327 continue;
1330 }
1331 };
1332
1333 let re_expanded = match expand_target(compressed) {
1335 Ok(t) => t,
1336 Err(_) => continue,
1337 };
1338
1339 if re_expanded > expanded {
1343 panic!(
1344 "Round-trip failed for bits 0x{bits:08x}: re-expanded > original (compression should truncate, not add)"
1345 );
1346 }
1347 #[allow(clippy::eq_op)]
1354 let significant_words_match =
1355 expanded.0[2] == re_expanded.0[2] && expanded.0[3] == re_expanded.0[3];
1356 if !significant_words_match {
1357 panic!(
1358 "Round-trip failed for bits 0x{:08x}: significant bits differ (expanded: {:?}, re-expanded: {:?})",
1359 bits, expanded.0, re_expanded.0
1360 );
1361 }
1362 }
1364 }
1365
1366 #[test]
1367 fn test_compress_target_genesis() {
1368 let genesis_bits = 0x1d00ffff;
1370 let expanded = expand_target(genesis_bits).unwrap();
1371 let compressed = compress_target(&expanded).unwrap();
1372
1373 assert!(compressed <= MAX_TARGET as u64);
1375 assert!(compressed > 0);
1376
1377 let re_expanded = expand_target(compressed).unwrap();
1379 assert_eq!(expanded, re_expanded);
1380 }
1381
1382 #[test]
1383 fn test_serialize_header() {
1384 let header = BlockHeader {
1385 version: 1,
1386 prev_block_hash: [1; 32],
1387 merkle_root: [2; 32],
1388 timestamp: 1234567890,
1389 bits: 0x1d00ffff,
1390 nonce: 0x12345678,
1391 };
1392
1393 let bytes = serialize_header(&header);
1394 assert_eq!(bytes.len(), 80); }
1396
1397 #[test]
1402 fn test_serialize_header_returns_fixed_80_bytes() {
1403 let header = BlockHeader {
1405 version: 1,
1406 prev_block_hash: [0; 32],
1407 merkle_root: [0; 32],
1408 timestamp: 0,
1409 bits: 0,
1410 nonce: 0,
1411 };
1412 let bytes: [u8; 80] = serialize_header(&header);
1413 assert_eq!(bytes.len(), 80);
1414 }
1415
1416 #[test]
1417 fn test_serialize_header_field_layout() {
1418 let header = BlockHeader {
1420 version: 0x01020304,
1421 prev_block_hash: {
1422 let mut h = [0u8; 32];
1423 h[0] = 0xAA;
1424 h[31] = 0xBB;
1425 h
1426 },
1427 merkle_root: {
1428 let mut h = [0u8; 32];
1429 h[0] = 0xCC;
1430 h[31] = 0xDD;
1431 h
1432 },
1433 timestamp: 0x05060708,
1434 bits: 0x090A0B0C,
1435 nonce: 0x0D0E0F10,
1436 };
1437
1438 let bytes = serialize_header(&header);
1439
1440 assert_eq!(bytes[0], 0x04); assert_eq!(bytes[1], 0x03);
1443 assert_eq!(bytes[2], 0x02);
1444 assert_eq!(bytes[3], 0x01);
1445
1446 assert_eq!(bytes[4], 0xAA);
1448 assert_eq!(bytes[35], 0xBB);
1449
1450 assert_eq!(bytes[36], 0xCC);
1452 assert_eq!(bytes[67], 0xDD);
1453
1454 assert_eq!(bytes[68], 0x08);
1456 assert_eq!(bytes[69], 0x07);
1457 assert_eq!(bytes[70], 0x06);
1458 assert_eq!(bytes[71], 0x05);
1459
1460 assert_eq!(bytes[72], 0x0C);
1462 assert_eq!(bytes[73], 0x0B);
1463 assert_eq!(bytes[74], 0x0A);
1464 assert_eq!(bytes[75], 0x09);
1465
1466 assert_eq!(bytes[76], 0x10);
1468 assert_eq!(bytes[77], 0x0F);
1469 assert_eq!(bytes[78], 0x0E);
1470 assert_eq!(bytes[79], 0x0D);
1471 }
1472
1473 #[test]
1474 fn test_serialize_header_deterministic() {
1475 let header = BlockHeader {
1476 version: 1,
1477 prev_block_hash: [0xFF; 32],
1478 merkle_root: [0xAA; 32],
1479 timestamp: 1231006505,
1480 bits: 0x1d00ffff,
1481 nonce: 2083236893,
1482 };
1483
1484 let bytes1 = serialize_header(&header);
1485 let bytes2 = serialize_header(&header);
1486 assert_eq!(bytes1, bytes2, "Header serialization must be deterministic");
1487 }
1488
1489 #[test]
1490 fn test_serialize_header_different_headers_different_bytes() {
1491 let header1 = BlockHeader {
1492 version: 1,
1493 prev_block_hash: [0; 32],
1494 merkle_root: [0; 32],
1495 timestamp: 1231006505,
1496 bits: 0x1d00ffff,
1497 nonce: 0,
1498 };
1499
1500 let mut header2 = header1.clone();
1501 header2.nonce = 1;
1502
1503 let bytes1 = serialize_header(&header1);
1504 let bytes2 = serialize_header(&header2);
1505 assert_ne!(
1506 bytes1, bytes2,
1507 "Different nonces must produce different serializations"
1508 );
1509
1510 assert_eq!(
1512 bytes1[..76],
1513 bytes2[..76],
1514 "Non-nonce bytes should be identical"
1515 );
1516 assert_ne!(bytes1[76..], bytes2[76..], "Nonce bytes should differ");
1517 }
1518
1519 #[test]
1520 fn test_u256_from_bytes_simple() {
1521 let bytes = [0u8; 32];
1522 let value = u256_from_bytes(&bytes);
1523 assert_eq!(value, 0);
1524 }
1525
1526 #[test]
1527 fn test_u256_from_bytes_with_data() {
1528 let mut bytes = [0u8; 32];
1529 bytes[0] = 0x78;
1530 bytes[1] = 0x56;
1531 bytes[2] = 0x34;
1532 bytes[3] = 0x12;
1533 let value = u256_from_bytes(&bytes);
1534 assert_eq!(value, 0x78563412000000000000000000000000);
1537 }
1538}