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
704#[spec_locked("7.1", "CompressTarget")]
733pub(crate) fn compress_target(target: &U256) -> Result<Natural> {
734 if target.is_zero() {
736 return Ok(0x1d000000); }
738
739 let highest_bit = target
741 .highest_set_bit()
742 .ok_or_else(|| ConsensusError::InvalidProofOfWork("Cannot compress zero target".into()))?;
743
744 let n_size = (highest_bit + 1).div_ceil(8);
747
748 let mut n_compact: u64;
751
752 if n_size <= 3 {
753 let low_64 = target.get_low_64();
756 let shift_bytes = 3 - n_size;
757 n_compact = low_64 << (8 * shift_bytes);
758 } else {
759 let shift_bytes = n_size - 3;
762 let shifted = target.shr(shift_bytes * 8);
763 n_compact = shifted.get_low_64();
764 }
765
766 let mut n_size_final = n_size;
770 while (n_compact & 0x00800000) != 0 {
771 n_compact >>= 8;
772 n_size_final += 1;
773 }
774
775 let mantissa = (n_compact & 0x007fffff) as u32;
778
779 if n_size_final > 29 {
781 return Err(ConsensusError::InvalidProofOfWork(
782 format!("Target too large: exponent {n_size_final} exceeds maximum 29").into(),
783 ));
784 }
785
786 let bits = (n_size_final << 24) | mantissa;
788
789 Ok(bits as Natural)
790}
791
792fn serialize_header(header: &BlockHeader) -> [u8; 80] {
794 let mut bytes = [0u8; 80];
796
797 bytes[0..4].copy_from_slice(&(header.version as u32).to_le_bytes());
798 bytes[4..36].copy_from_slice(&header.prev_block_hash);
799 bytes[36..68].copy_from_slice(&header.merkle_root);
800 bytes[68..72].copy_from_slice(&(header.timestamp as u32).to_le_bytes());
801 bytes[72..76].copy_from_slice(&(header.bits as u32).to_le_bytes());
802 bytes[76..80].copy_from_slice(&(header.nonce as u32).to_le_bytes());
803
804 bytes
805}
806
807#[cfg(test)]
808fn u256_from_bytes(bytes: &[u8]) -> u128 {
810 let mut value = 0u128;
811 for (i, &byte) in bytes.iter().enumerate() {
812 if i < 16 {
813 value |= (byte as u128) << (8 * (15 - i));
815 }
816 }
817 value
818}
819
820#[cfg(test)]
834mod property_tests {
835 use super::*;
836 use proptest::prelude::*;
837
838 fn arb_block_header() -> impl Strategy<Value = BlockHeader> {
839 (
840 any::<i64>(),
841 any::<[u8; 32]>(),
842 any::<[u8; 32]>(),
843 any::<u64>(),
844 0x03000000u32..0x1d00ffffu32,
845 any::<u64>(),
846 )
847 .prop_map(
848 |(version, prev_block_hash, merkle_root, timestamp, bits, nonce)| BlockHeader {
849 version,
850 prev_block_hash,
851 merkle_root,
852 timestamp,
853 bits: bits as u64,
854 nonce,
855 },
856 )
857 }
858
859 proptest! {
861 #[test]
862 fn prop_expand_target_valid_range(
863 bits in 0x03000000u32..0x1d00ffffu32
864 ) {
865 let result = expand_target(bits as u64);
866 let mantissa = bits & 0x00ffffff;
867
868 match result {
869 Ok(target) => {
870 prop_assert!(target >= U256::zero(), "Target must be non-negative");
872
873 if mantissa == 0 {
878 prop_assert!(target.is_zero(), "Zero mantissa should produce zero target");
879 } else {
880 prop_assert!(!target.is_zero(), "Non-zero mantissa should produce non-zero target");
881 }
882 },
883 Err(_) => {
884 }
886 }
887 }
888 }
889
890 proptest! {
892 #[test]
893 fn prop_check_proof_of_work_deterministic(
894 header in arb_block_header()
895 ) {
896 let mut valid_header = header;
898 valid_header.bits = 0x1d00ffff; let result1 = check_proof_of_work(&valid_header).unwrap_or(false);
902 let result2 = check_proof_of_work(&valid_header).unwrap_or(false);
903
904 prop_assert_eq!(result1, result2, "Proof of work check must be deterministic");
906 }
907 }
908
909 proptest! {
911 #[test]
912 fn prop_get_next_work_required_bounds(
913 current_header in arb_block_header(),
914 prev_headers in proptest::collection::vec(arb_block_header(), 2..6)
915 ) {
916 let mut valid_headers = prev_headers;
918 if let Some(first_header) = valid_headers.first_mut() {
919 first_header.timestamp = current_header.timestamp - 86400 * 14; }
921
922 let result = get_next_work_required(¤t_header, &valid_headers);
923
924 match result {
925 Ok(work) => {
926 prop_assert!(work <= MAX_TARGET as Natural,
928 "Next work required must not exceed maximum target");
929 prop_assert!(work > 0, "Next work required must be positive");
930 },
931 Err(_) => {
932 }
934 }
935 }
936 }
937}
938
939#[cfg(test)]
940mod tests {
941 use super::*;
942 use crate::constants::MAX_TARGET;
943
944 #[test]
945 fn test_get_next_work_required_insufficient_headers() {
946 let header = BlockHeader {
947 version: 1,
948 prev_block_hash: [0; 32],
949 merkle_root: [0; 32],
950 timestamp: 1231006505,
951 bits: 0x1d00ffff,
952 nonce: 0,
953 };
954
955 let prev_headers = vec![header.clone()];
956 let result = get_next_work_required(&header, &prev_headers);
957
958 assert!(result.is_err());
960 }
961
962 #[test]
963 fn test_get_next_work_required_normal_adjustment() {
964 let header1 = BlockHeader {
965 version: 1,
966 prev_block_hash: [0; 32],
967 merkle_root: [0; 32],
968 timestamp: 1000000,
969 bits: 0x1d00ffff,
970 nonce: 0,
971 };
972
973 let header2 = BlockHeader {
974 version: 1,
975 prev_block_hash: [0; 32],
976 merkle_root: [0; 32],
977 timestamp: 1000000 + (DIFFICULTY_ADJUSTMENT_INTERVAL * TARGET_TIME_PER_BLOCK), bits: 0x1d00ffff,
979 nonce: 0,
980 };
981
982 let prev_headers = vec![header1, header2.clone()];
983 let result = get_next_work_required(&header2, &prev_headers).unwrap();
984
985 assert_eq!(result, 0x1d00ffff);
987 }
988
989 #[test]
990 fn test_difficulty_from_bits() {
991 let d = difficulty_from_bits(0x1d00ffff).unwrap();
993 assert!(
994 (d - 1.0).abs() < 0.01,
995 "Genesis difficulty should be ~1.0, got {d}"
996 );
997 let d_harder = difficulty_from_bits(0x1d000800).unwrap();
999 assert!(d_harder > d, "Harder target should have higher difficulty");
1000 }
1001
1002 #[test]
1003 fn test_expand_target() {
1004 let target = expand_target(0x0300ffff).unwrap(); assert!(!target.is_zero());
1008 }
1009
1010 #[test]
1011 fn test_check_proof_of_work_genesis() {
1012 let header = BlockHeader {
1014 version: 1,
1015 prev_block_hash: [0; 32],
1016 merkle_root: [0; 32],
1017 timestamp: 1231006505,
1018 bits: 0x0300ffff, nonce: 0,
1020 };
1021
1022 let result = check_proof_of_work(&header).unwrap();
1024 let _ = result;
1027 }
1028
1029 #[test]
1034 fn test_get_next_work_required_fast_blocks() {
1035 let header1 = BlockHeader {
1036 version: 1,
1037 prev_block_hash: [0; 32],
1038 merkle_root: [0; 32],
1039 timestamp: 1000000,
1040 bits: 0x1d00ffff,
1041 nonce: 0,
1042 };
1043
1044 let header2 = BlockHeader {
1046 version: 1,
1047 prev_block_hash: [0; 32],
1048 merkle_root: [0; 32],
1049 timestamp: 1000000 + (DIFFICULTY_ADJUSTMENT_INTERVAL * TARGET_TIME_PER_BLOCK / 2),
1050 bits: 0x1d00ffff,
1051 nonce: 0,
1052 };
1053
1054 let prev_headers = vec![header1, header2.clone()];
1055 let result = get_next_work_required(&header2, &prev_headers).unwrap();
1056
1057 assert!(result <= 0x1d00ffff);
1060 }
1061
1062 #[test]
1063 fn test_get_next_work_required_slow_blocks() {
1064 let header1 = BlockHeader {
1065 version: 1,
1066 prev_block_hash: [0; 32],
1067 merkle_root: [0; 32],
1068 timestamp: 1000000,
1069 bits: 0x1d00ffff,
1070 nonce: 0,
1071 };
1072
1073 let header2 = BlockHeader {
1075 version: 1,
1076 prev_block_hash: [0; 32],
1077 merkle_root: [0; 32],
1078 timestamp: 1000000 + (DIFFICULTY_ADJUSTMENT_INTERVAL * TARGET_TIME_PER_BLOCK * 2),
1079 bits: 0x1d00ffff,
1080 nonce: 0,
1081 };
1082
1083 let prev_headers = vec![header1, header2.clone()];
1084 let result = get_next_work_required(&header2, &prev_headers).unwrap();
1085
1086 assert!(result <= 0x1d00ffff);
1089 }
1090
1091 #[test]
1092 fn test_get_next_work_required_extreme_fast_blocks() {
1093 let header1 = BlockHeader {
1094 version: 1,
1095 prev_block_hash: [0; 32],
1096 merkle_root: [0; 32],
1097 timestamp: 1000000,
1098 bits: 0x1d00ffff,
1099 nonce: 0,
1100 };
1101
1102 let header2 = BlockHeader {
1104 version: 1,
1105 prev_block_hash: [0; 32],
1106 merkle_root: [0; 32],
1107 timestamp: 1000000 + (DIFFICULTY_ADJUSTMENT_INTERVAL * TARGET_TIME_PER_BLOCK / 14),
1108 bits: 0x1d00ffff,
1109 nonce: 0,
1110 };
1111
1112 let prev_headers = vec![header1, header2.clone()];
1113 let result = get_next_work_required(&header2, &prev_headers).unwrap();
1114
1115 assert!(result <= 0x1d00ffff);
1118 }
1119
1120 #[test]
1121 fn test_get_next_work_required_extreme_slow_blocks() {
1122 let header1 = BlockHeader {
1123 version: 1,
1124 prev_block_hash: [0; 32],
1125 merkle_root: [0; 32],
1126 timestamp: 1000000,
1127 bits: 0x1d00ffff,
1128 nonce: 0,
1129 };
1130
1131 let header2 = BlockHeader {
1133 version: 1,
1134 prev_block_hash: [0; 32],
1135 merkle_root: [0; 32],
1136 timestamp: 1000000 + (DIFFICULTY_ADJUSTMENT_INTERVAL * TARGET_TIME_PER_BLOCK * 4),
1137 bits: 0x1d00ffff,
1138 nonce: 0,
1139 };
1140
1141 let prev_headers = vec![header1, header2.clone()];
1142 let result = get_next_work_required(&header2, &prev_headers).unwrap();
1143
1144 assert!(result <= 0x1d00ffff);
1147 }
1148
1149 #[test]
1150 fn test_expand_target_zero_mantissa() {
1151 let result = expand_target(0x1d000000).unwrap();
1152 assert!(result.is_zero());
1153 }
1154
1155 #[test]
1156 fn test_expand_target_invalid_exponent_too_small() {
1157 let result = expand_target(0x0200ffff);
1158 assert!(result.is_err());
1159 }
1160
1161 #[test]
1162 fn test_expand_target_invalid_exponent_too_large() {
1163 let result = expand_target(0x2100ffff);
1164 assert!(result.is_err());
1165 }
1166
1167 #[test]
1168 fn test_expand_target_exponent_31() {
1169 let result = expand_target(0x1f00ffff).unwrap(); assert!(!result.is_zero());
1171 }
1172
1173 #[test]
1174 fn test_expand_target_exponent_32_regtest_bits() {
1175 let result = expand_target(0x2000ffff).unwrap();
1177 assert!(!result.is_zero());
1178 }
1179
1180 #[test]
1181 fn test_gbt_target_hex_regtest_minimum_difficulty() {
1182 let target = expand_target(0x207fffff).expect("regtest nBits");
1183 let hex = target.gbt_target_hex();
1184 assert_eq!(hex.len(), 64);
1185 assert_ne!(hex, "0".repeat(64));
1186 assert!(hex.starts_with("7fffff"));
1188 }
1189
1190 #[test]
1191 fn test_expand_target_exponent_3() {
1192 let result = expand_target(0x0300ffff).unwrap();
1193 assert!(!result.is_zero());
1194 }
1195
1196 #[test]
1197 fn test_expand_target_exponent_4() {
1198 let result = expand_target(0x0400ffff).unwrap();
1199 assert!(!result.is_zero());
1200 }
1201
1202 #[test]
1203 fn test_expand_target_exponent_29() {
1204 let result = expand_target(0x1d00ffff).unwrap();
1205 assert!(!result.is_zero());
1206 }
1207
1208 #[test]
1209 fn test_check_proof_of_work_invalid_target() {
1210 let header = BlockHeader {
1213 version: 1,
1214 prev_block_hash: [0; 32],
1215 merkle_root: [0; 32],
1216 timestamp: 1231006505,
1217 bits: 0x0200ffff, nonce: 0,
1219 };
1220
1221 let result = check_proof_of_work(&header);
1222 assert!(result.is_err());
1223 }
1224
1225 #[test]
1226 fn test_check_proof_of_work_valid_target() {
1227 let header = BlockHeader {
1228 version: 1,
1229 prev_block_hash: [0; 32],
1230 merkle_root: [0; 32],
1231 timestamp: 1231006505,
1232 bits: 0x1d00ffff, nonce: 0,
1234 };
1235
1236 let result = check_proof_of_work(&header).unwrap();
1237 let _ = result;
1239 }
1240
1241 #[test]
1242 fn test_u256_zero() {
1243 let zero = U256::zero();
1244 assert!(zero.is_zero());
1245 }
1246
1247 #[test]
1248 fn test_u256_from_u32() {
1249 let value = U256::from_u32(0x12345678);
1250 assert!(!value.is_zero());
1251 }
1252
1253 #[test]
1254 fn test_u256_from_u64() {
1255 let value = U256::from_u64(0x123456789abcdef0);
1256 assert!(!value.is_zero());
1257 }
1258
1259 #[test]
1260 fn test_u256_shl_zero_shift() {
1261 let value = U256::from_u32(0x12345678);
1262 let result = value.shl(0);
1263 assert_eq!(result, value);
1264 }
1265
1266 #[test]
1267 fn test_u256_shl_large_shift() {
1268 let value = U256::from_u32(0x12345678);
1269 let result = value.shl(300); assert!(result.is_zero());
1271 }
1272
1273 #[test]
1274 fn test_u256_shr_zero_shift() {
1275 let value = U256::from_u32(0x12345678);
1276 let result = value.shr(0);
1277 assert_eq!(result, value);
1278 }
1279
1280 #[test]
1281 fn test_u256_shr_large_shift() {
1282 let value = U256::from_u32(0x12345678);
1283 let result = value.shr(300); assert!(result.is_zero());
1285 }
1286
1287 #[test]
1288 fn test_u256_shl_small_shift() {
1289 let value = U256::from_u32(0x12345678);
1290 let result = value.shl(8);
1291 assert!(!result.is_zero());
1292 assert_ne!(result, value);
1293 }
1294
1295 #[test]
1296 fn test_u256_shr_small_shift() {
1297 let value = U256::from_u32(0x12345678);
1298 let result = value.shr(8);
1299 assert!(!result.is_zero());
1300 assert_ne!(result, value);
1301 }
1302
1303 #[test]
1304 fn test_u256_to_bytes() {
1305 let value = U256::from_u32(0x12345678);
1306 let bytes = value.to_bytes();
1307 assert_eq!(bytes.len(), 32);
1308 }
1309
1310 #[test]
1311 fn test_u256_from_bytes() {
1312 let mut bytes = [0u8; 32];
1313 bytes[0] = 0x78;
1314 bytes[1] = 0x56;
1315 bytes[2] = 0x34;
1316 bytes[3] = 0x12;
1317 let value = U256::from_bytes(&bytes);
1318 assert!(!value.is_zero());
1319 }
1320
1321 #[test]
1322 fn test_u256_ordering() {
1323 let small = U256::from_u32(0x12345678);
1324 let large = U256::from_u32(0x87654321);
1325
1326 assert!(small < large);
1327 assert!(large > small);
1328 assert_eq!(small.cmp(&small), std::cmp::Ordering::Equal);
1329 }
1330
1331 #[test]
1332 fn test_expand_compress_round_trip() {
1333 let test_bits = vec![
1335 0x1d00ffff, 0x1b0404cb, 0x0300ffff, ];
1342
1343 for &bits in &test_bits {
1344 let expanded = match expand_target(bits) {
1346 Ok(t) => t,
1347 Err(_) => continue, };
1349
1350 let compressed = match compress_target(&expanded) {
1352 Ok(b) => b,
1353 Err(_) => {
1354 continue;
1357 }
1358 };
1359
1360 let re_expanded = match expand_target(compressed) {
1362 Ok(t) => t,
1363 Err(_) => continue,
1364 };
1365
1366 if re_expanded > expanded {
1370 panic!(
1371 "Round-trip failed for bits 0x{bits:08x}: re-expanded > original (compression should truncate, not add)"
1372 );
1373 }
1374 #[allow(clippy::eq_op)]
1381 let significant_words_match =
1382 expanded.0[2] == re_expanded.0[2] && expanded.0[3] == re_expanded.0[3];
1383 if !significant_words_match {
1384 panic!(
1385 "Round-trip failed for bits 0x{:08x}: significant bits differ (expanded: {:?}, re-expanded: {:?})",
1386 bits, expanded.0, re_expanded.0
1387 );
1388 }
1389 }
1391 }
1392
1393 #[test]
1394 fn test_compress_target_genesis() {
1395 let genesis_bits = 0x1d00ffff;
1397 let expanded = expand_target(genesis_bits).unwrap();
1398 let compressed = compress_target(&expanded).unwrap();
1399
1400 assert!(compressed <= MAX_TARGET as u64);
1402 assert!(compressed > 0);
1403
1404 let re_expanded = expand_target(compressed).unwrap();
1406 assert_eq!(expanded, re_expanded);
1407 }
1408
1409 #[test]
1410 fn test_serialize_header() {
1411 let header = BlockHeader {
1412 version: 1,
1413 prev_block_hash: [1; 32],
1414 merkle_root: [2; 32],
1415 timestamp: 1234567890,
1416 bits: 0x1d00ffff,
1417 nonce: 0x12345678,
1418 };
1419
1420 let bytes = serialize_header(&header);
1421 assert_eq!(bytes.len(), 80); }
1423
1424 #[test]
1429 fn test_serialize_header_returns_fixed_80_bytes() {
1430 let header = BlockHeader {
1432 version: 1,
1433 prev_block_hash: [0; 32],
1434 merkle_root: [0; 32],
1435 timestamp: 0,
1436 bits: 0,
1437 nonce: 0,
1438 };
1439 let bytes: [u8; 80] = serialize_header(&header);
1440 assert_eq!(bytes.len(), 80);
1441 }
1442
1443 #[test]
1444 fn test_serialize_header_field_layout() {
1445 let header = BlockHeader {
1447 version: 0x01020304,
1448 prev_block_hash: {
1449 let mut h = [0u8; 32];
1450 h[0] = 0xAA;
1451 h[31] = 0xBB;
1452 h
1453 },
1454 merkle_root: {
1455 let mut h = [0u8; 32];
1456 h[0] = 0xCC;
1457 h[31] = 0xDD;
1458 h
1459 },
1460 timestamp: 0x05060708,
1461 bits: 0x090A0B0C,
1462 nonce: 0x0D0E0F10,
1463 };
1464
1465 let bytes = serialize_header(&header);
1466
1467 assert_eq!(bytes[0], 0x04); assert_eq!(bytes[1], 0x03);
1470 assert_eq!(bytes[2], 0x02);
1471 assert_eq!(bytes[3], 0x01);
1472
1473 assert_eq!(bytes[4], 0xAA);
1475 assert_eq!(bytes[35], 0xBB);
1476
1477 assert_eq!(bytes[36], 0xCC);
1479 assert_eq!(bytes[67], 0xDD);
1480
1481 assert_eq!(bytes[68], 0x08);
1483 assert_eq!(bytes[69], 0x07);
1484 assert_eq!(bytes[70], 0x06);
1485 assert_eq!(bytes[71], 0x05);
1486
1487 assert_eq!(bytes[72], 0x0C);
1489 assert_eq!(bytes[73], 0x0B);
1490 assert_eq!(bytes[74], 0x0A);
1491 assert_eq!(bytes[75], 0x09);
1492
1493 assert_eq!(bytes[76], 0x10);
1495 assert_eq!(bytes[77], 0x0F);
1496 assert_eq!(bytes[78], 0x0E);
1497 assert_eq!(bytes[79], 0x0D);
1498 }
1499
1500 #[test]
1501 fn test_serialize_header_deterministic() {
1502 let header = BlockHeader {
1503 version: 1,
1504 prev_block_hash: [0xFF; 32],
1505 merkle_root: [0xAA; 32],
1506 timestamp: 1231006505,
1507 bits: 0x1d00ffff,
1508 nonce: 2083236893,
1509 };
1510
1511 let bytes1 = serialize_header(&header);
1512 let bytes2 = serialize_header(&header);
1513 assert_eq!(bytes1, bytes2, "Header serialization must be deterministic");
1514 }
1515
1516 #[test]
1517 fn test_serialize_header_different_headers_different_bytes() {
1518 let header1 = BlockHeader {
1519 version: 1,
1520 prev_block_hash: [0; 32],
1521 merkle_root: [0; 32],
1522 timestamp: 1231006505,
1523 bits: 0x1d00ffff,
1524 nonce: 0,
1525 };
1526
1527 let mut header2 = header1.clone();
1528 header2.nonce = 1;
1529
1530 let bytes1 = serialize_header(&header1);
1531 let bytes2 = serialize_header(&header2);
1532 assert_ne!(
1533 bytes1, bytes2,
1534 "Different nonces must produce different serializations"
1535 );
1536
1537 assert_eq!(
1539 bytes1[..76],
1540 bytes2[..76],
1541 "Non-nonce bytes should be identical"
1542 );
1543 assert_ne!(bytes1[76..], bytes2[76..], "Nonce bytes should differ");
1544 }
1545
1546 #[test]
1547 fn test_u256_from_bytes_simple() {
1548 let bytes = [0u8; 32];
1549 let value = u256_from_bytes(&bytes);
1550 assert_eq!(value, 0);
1551 }
1552
1553 #[test]
1554 fn test_u256_from_bytes_with_data() {
1555 let mut bytes = [0u8; 32];
1556 bytes[0] = 0x78;
1557 bytes[1] = 0x56;
1558 bytes[2] = 0x34;
1559 bytes[3] = 0x12;
1560 let value = u256_from_bytes(&bytes);
1561 assert_eq!(value, 0x78563412000000000000000000000000);
1564 }
1565}