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, Copy, 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 from_u128(value: u128) -> Self {
331 U256([value as u64, (value >> 64) as u64, 0, 0])
332 }
333
334 pub fn one() -> Self {
335 U256([1, 0, 0, 0])
336 }
337
338 pub fn is_zero(&self) -> bool {
339 self.0.iter().all(|&w| w == 0)
340 }
341
342 #[allow(clippy::should_implement_trait)]
343 pub fn not(self) -> Self {
344 U256([!self.0[0], !self.0[1], !self.0[2], !self.0[3]])
345 }
346
347 pub fn checked_add(self, other: Self) -> Option<Self> {
348 let mut result = [0u64; 4];
349 let mut carry = 0u128;
350 for (i, word) in result.iter_mut().enumerate() {
351 let sum = self.0[i] as u128 + other.0[i] as u128 + carry;
352 *word = sum as u64;
353 carry = sum >> 64;
354 }
355 if carry != 0 { None } else { Some(U256(result)) }
356 }
357
358 pub fn saturating_add(self, other: Self) -> Self {
359 self.checked_add(other).unwrap_or(U256([u64::MAX; 4]))
360 }
361
362 fn sub(self, other: Self) -> Self {
363 let mut result = [0u64; 4];
364 let mut borrow = 0u8;
365 for (i, word) in result.iter_mut().enumerate() {
366 let mut minuend = self.0[i] as u128;
367 if borrow != 0 {
368 minuend += 1u128 << 64;
369 borrow = 0;
370 }
371 if minuend >= other.0[i] as u128 {
372 *word = (minuend - other.0[i] as u128) as u64;
373 } else {
374 *word = (minuend + (1u128 << 64) - other.0[i] as u128) as u64;
375 borrow = 1;
376 }
377 }
378 U256(result)
379 }
380
381 fn bit(self, bit: u32) -> bool {
382 (self.0[(bit / 64) as usize] >> (bit % 64)) & 1 == 1
383 }
384
385 fn with_bit_set(self, bit: u32) -> Self {
386 let mut result = self;
387 result.0[(bit / 64) as usize] |= 1u64 << (bit % 64);
388 result
389 }
390
391 #[allow(clippy::should_implement_trait)]
393 pub fn div(self, divisor: Self) -> Self {
394 if divisor.is_zero() {
395 return U256::zero();
396 }
397 if self < divisor {
398 return U256::zero();
399 }
400 let mut quotient = U256::zero();
401 let mut remainder = U256::zero();
402 for bit in (0..256).rev() {
403 remainder = remainder.shl(1);
404 if self.bit(bit) {
405 remainder = remainder
406 .checked_add(U256::one())
407 .unwrap_or(U256([u64::MAX; 4]));
408 }
409 if remainder >= divisor {
410 remainder = remainder.sub(divisor);
411 quotient = quotient.with_bit_set(bit);
412 }
413 }
414 quotient
415 }
416
417 pub fn to_be_bytes(self) -> [u8; 32] {
419 let mut bytes = self.to_le_bytes();
420 bytes.reverse();
421 bytes
422 }
423
424 pub fn from_be_bytes(bytes: &[u8; 32]) -> Self {
426 let mut le = *bytes;
427 le.reverse();
428 Self::from_bytes(&le)
429 }
430
431 #[cfg(test)]
432 fn to_bytes(&self) -> [u8; 32] {
433 self.to_le_bytes()
434 }
435
436 fn shl(&self, shift: u32) -> Self {
437 if shift >= 256 {
438 return U256::zero();
439 }
440
441 let mut result = U256::zero();
442 let word_shift = (shift / 64) as usize;
443 let bit_shift = shift % 64;
444
445 for i in 0..4 {
446 if i + word_shift < 4 {
447 result.0[i + word_shift] |= self.0[i] << bit_shift;
448 if bit_shift > 0 && i + word_shift + 1 < 4 {
449 result.0[i + word_shift + 1] |= self.0[i] >> (64 - bit_shift);
450 }
451 }
452 }
453
454 result
455 }
456
457 fn shr(&self, shift: u32) -> Self {
458 if shift >= 256 {
459 return U256::zero();
460 }
461
462 let mut result = U256::zero();
463 let word_shift = (shift / 64) as usize;
464 let bit_shift = shift % 64;
465
466 debug_assert!(
468 word_shift < 4,
469 "Word shift ({word_shift}) must be < 4 (shift: {shift})"
470 );
471
472 debug_assert!(
474 bit_shift < 64,
475 "Bit shift ({bit_shift}) must be < 64 (shift: {shift})"
476 );
477
478 if bit_shift == 0 {
479 for i in word_shift..4 {
480 result.0[i - word_shift] = self.0[i];
481 }
482 } else {
483 for i in word_shift..4 {
486 let mut word = self.0[i] >> bit_shift;
487 if i + 1 < 4 {
488 word |= self.0[i + 1] << (64 - bit_shift);
489 }
490 result.0[i - word_shift] = word;
491 }
492 }
493
494 result
495 }
496
497 fn from_bytes(bytes: &[u8; 32]) -> Self {
498 let mut words = [0u64; 4];
499 for (i, word) in words.iter_mut().enumerate() {
500 let start = i * 8;
501 let _end = start + 8;
502 *word = u64::from_le_bytes([
503 bytes[start],
504 bytes[start + 1],
505 bytes[start + 2],
506 bytes[start + 3],
507 bytes[start + 4],
508 bytes[start + 5],
509 bytes[start + 6],
510 bytes[start + 7],
511 ]);
512 }
513 U256(words)
514 }
515
516 fn checked_mul_u64(&self, rhs: u64) -> Option<Self> {
519 let mut carry = 0u128;
521 let mut result = U256::zero();
522
523 #[cfg(feature = "production")]
526 {
527 let product = (self.0[0] as u128) * (rhs as u128) + carry;
530 result.0[0] = product as u64;
531 carry = product >> 64;
532
533 let product = (self.0[1] as u128) * (rhs as u128) + carry;
535 result.0[1] = product as u64;
536 carry = product >> 64;
537
538 let product = (self.0[2] as u128) * (rhs as u128) + carry;
540 result.0[2] = product as u64;
541 carry = product >> 64;
542
543 let product = (self.0[3] as u128) * (rhs as u128) + carry;
545 result.0[3] = product as u64;
546 carry = product >> 64;
547
548 if carry > 0 {
550 return None; }
552 }
553
554 #[cfg(not(feature = "production"))]
555 {
556 for i in 0..4 {
557 let product = (self.0[i] as u128) * (rhs as u128) + carry;
558 result.0[i] = product as u64;
559 carry = product >> 64;
560
561 if i == 3 && carry > 0 {
563 return None; }
565 }
566 }
567
568 Some(result)
569 }
570
571 fn div_u64(&self, rhs: u64) -> Self {
578 if rhs == 0 {
579 return U256([u64::MAX; 4]);
582 }
583
584 let mut remainder = 0u128;
585 let mut result = U256::zero();
586
587 #[cfg(feature = "production")]
591 {
592 let dividend = (remainder << 64) | (self.0[3] as u128);
595 let quotient = dividend / (rhs as u128);
596 remainder = dividend % (rhs as u128);
597 debug_assert!(quotient <= u64::MAX as u128, "Quotient must fit in u64");
598 result.0[3] = quotient as u64;
599
600 let dividend = (remainder << 64) | (self.0[2] as u128);
602 let quotient = dividend / (rhs as u128);
603 remainder = dividend % (rhs as u128);
604 debug_assert!(quotient <= u64::MAX as u128, "Quotient must fit in u64");
605 result.0[2] = quotient as u64;
606
607 let dividend = (remainder << 64) | (self.0[1] as u128);
609 let quotient = dividend / (rhs as u128);
610 remainder = dividend % (rhs as u128);
611 debug_assert!(quotient <= u64::MAX as u128, "Quotient must fit in u64");
612 result.0[1] = quotient as u64;
613
614 let dividend = (remainder << 64) | (self.0[0] as u128);
616 let quotient = dividend / (rhs as u128);
617 remainder = dividend % (rhs as u128);
618 debug_assert!(quotient <= u64::MAX as u128, "Quotient must fit in u64");
619 result.0[0] = quotient as u64;
620 }
621
622 #[cfg(not(feature = "production"))]
623 {
624 for i in (0..4).rev() {
626 let dividend = (remainder << 64) | (self.0[i] as u128);
627 let quotient = dividend / (rhs as u128);
628 remainder = dividend % (rhs as u128);
629 debug_assert!(
630 quotient <= u64::MAX as u128,
631 "Quotient ({quotient}) must fit in u64"
632 );
633 result.0[i] = quotient as u64;
634 }
635 }
636
637 debug_assert!(
639 result <= *self,
640 "Division result ({result:?}) must be <= dividend ({self:?})"
641 );
642
643 debug_assert!(
645 remainder < rhs as u128,
646 "Remainder ({remainder}) must be < divisor ({rhs})"
647 );
648
649 result
650 }
651
652 fn highest_set_bit(&self) -> Option<u32> {
655 for (i, &word) in self.0.iter().rev().enumerate() {
656 if word != 0 {
657 let word_index = (3 - i) as u32;
658 let bit_pos = word_index * 64 + (63 - word.leading_zeros());
659 return Some(bit_pos);
660 }
661 }
662 None
663 }
664
665 fn to_f64(self) -> f64 {
668 if self.is_zero() {
669 return 0.0;
670 }
671 let mut result = 0.0_f64;
672 result += self.0[0] as f64;
673 result += (self.0[1] as f64) * 2.0_f64.powi(64);
674 result += (self.0[2] as f64) * 2.0_f64.powi(128);
675 result += (self.0[3] as f64) * 2.0_f64.powi(192);
676 result
677 }
678}
679
680impl PartialOrd for U256 {
681 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
682 Some(self.cmp(other))
683 }
684}
685
686impl Ord for U256 {
687 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
688 for (a, b) in self.0.iter().rev().zip(other.0.iter().rev()) {
689 match a.cmp(b) {
690 std::cmp::Ordering::Equal => continue,
691 other => return other,
692 }
693 }
694 std::cmp::Ordering::Equal
695 }
696}
697
698pub fn difficulty_from_bits(bits: Natural) -> Result<f64> {
703 let target = expand_target(bits)?;
704 if target.is_zero() {
705 return Ok(1.0);
706 }
707 let max_target = U256::from_bytes(&[
709 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,
710 0xFF, 0x00, 0x00, 0x00, 0x00,
711 ]);
712 let max_f64 = max_target.to_f64();
713 let target_f64 = target.to_f64();
714 if target_f64 == 0.0 {
715 return Ok(1.0);
716 }
717 Ok((max_f64 / target_f64).max(1.0))
718}
719
720#[spec_locked("7.1", "ExpandTarget")]
750pub fn expand_target(bits: Natural) -> Result<U256> {
751 let exponent = (bits >> 24) as u8;
763 let mantissa = bits & 0x007fffff;
765
766 if !(3..=32).contains(&exponent) {
769 return Err(ConsensusError::InvalidProofOfWork(
770 "Invalid target exponent".into(),
771 ));
772 }
773
774 if mantissa == 0 {
775 return Ok(U256::zero());
776 }
777
778 if exponent <= 3 {
780 let shift = 8 * (3 - exponent);
785 let mantissa_u256 = U256::from_u32(mantissa as u32);
786 Ok(mantissa_u256.shr(shift as u32))
787 } else {
788 let shift = 8u32 * (exponent as u32 - 3);
792 if shift >= 256 {
793 return Err(crate::error::ConsensusError::InvalidProofOfWork(
794 "Target too large".into(),
795 ));
796 }
797 let mantissa_u256 = U256::from_u32(mantissa as u32);
798 Ok(mantissa_u256.shl(shift))
799 }
800}
801
802#[spec_locked("11.3", "GetBlockProof")]
807pub fn get_block_proof(bits: Natural) -> Result<U256> {
808 let target = expand_target(bits)?;
809 if target.is_zero() {
810 return Ok(U256::zero());
811 }
812 let target_plus_one = target
813 .checked_add(U256::one())
814 .ok_or_else(|| ConsensusError::InvalidProofOfWork("Target overflow".into()))?;
815 let quotient = target.not().div(target_plus_one);
816 Ok(quotient
817 .checked_add(U256::one())
818 .unwrap_or(U256([u64::MAX; 4])))
819}
820
821#[spec_locked("7.1", "CompressTarget")]
850pub(crate) fn compress_target(target: &U256) -> Result<Natural> {
851 if target.is_zero() {
853 return Ok(0x1d000000); }
855
856 let highest_bit = target
858 .highest_set_bit()
859 .ok_or_else(|| ConsensusError::InvalidProofOfWork("Cannot compress zero target".into()))?;
860
861 let n_size = (highest_bit + 1).div_ceil(8);
864
865 let mut n_compact: u64;
868
869 if n_size <= 3 {
870 let low_64 = target.get_low_64();
873 let shift_bytes = 3 - n_size;
874 n_compact = low_64 << (8 * shift_bytes);
875 } else {
876 let shift_bytes = n_size - 3;
879 let shifted = target.shr(shift_bytes * 8);
880 n_compact = shifted.get_low_64();
881 }
882
883 let mut n_size_final = n_size;
887 while (n_compact & 0x00800000) != 0 {
888 n_compact >>= 8;
889 n_size_final += 1;
890 }
891
892 let mantissa = (n_compact & 0x007fffff) as u32;
895
896 if n_size_final > 29 {
898 return Err(ConsensusError::InvalidProofOfWork(
899 format!("Target too large: exponent {n_size_final} exceeds maximum 29").into(),
900 ));
901 }
902
903 let bits = (n_size_final << 24) | mantissa;
905
906 Ok(bits as Natural)
907}
908
909fn serialize_header(header: &BlockHeader) -> [u8; 80] {
911 let mut bytes = [0u8; 80];
913
914 bytes[0..4].copy_from_slice(&(header.version as u32).to_le_bytes());
915 bytes[4..36].copy_from_slice(&header.prev_block_hash);
916 bytes[36..68].copy_from_slice(&header.merkle_root);
917 bytes[68..72].copy_from_slice(&(header.timestamp as u32).to_le_bytes());
918 bytes[72..76].copy_from_slice(&(header.bits as u32).to_le_bytes());
919 bytes[76..80].copy_from_slice(&(header.nonce as u32).to_le_bytes());
920
921 bytes
922}
923
924#[cfg(test)]
925fn u256_from_bytes(bytes: &[u8]) -> u128 {
927 let mut value = 0u128;
928 for (i, &byte) in bytes.iter().enumerate() {
929 if i < 16 {
930 value |= (byte as u128) << (8 * (15 - i));
932 }
933 }
934 value
935}
936
937#[cfg(test)]
951mod property_tests {
952 use super::*;
953 use proptest::prelude::*;
954
955 fn arb_block_header() -> impl Strategy<Value = BlockHeader> {
956 (
957 any::<i64>(),
958 any::<[u8; 32]>(),
959 any::<[u8; 32]>(),
960 any::<u64>(),
961 0x03000000u32..0x1d00ffffu32,
962 any::<u64>(),
963 )
964 .prop_map(
965 |(version, prev_block_hash, merkle_root, timestamp, bits, nonce)| BlockHeader {
966 version,
967 prev_block_hash,
968 merkle_root,
969 timestamp,
970 bits: bits as u64,
971 nonce,
972 },
973 )
974 }
975
976 proptest! {
978 #[test]
979 fn prop_expand_target_valid_range(
980 bits in 0x03000000u32..0x1d00ffffu32
981 ) {
982 let result = expand_target(bits as u64);
983 let mantissa = bits & 0x00ffffff;
984
985 match result {
986 Ok(target) => {
987 prop_assert!(target >= U256::zero(), "Target must be non-negative");
989
990 if mantissa == 0 {
995 prop_assert!(target.is_zero(), "Zero mantissa should produce zero target");
996 } else {
997 prop_assert!(!target.is_zero(), "Non-zero mantissa should produce non-zero target");
998 }
999 },
1000 Err(_) => {
1001 }
1003 }
1004 }
1005 }
1006
1007 proptest! {
1009 #[test]
1010 fn prop_check_proof_of_work_deterministic(
1011 header in arb_block_header()
1012 ) {
1013 let mut valid_header = header;
1015 valid_header.bits = 0x1d00ffff; let result1 = check_proof_of_work(&valid_header).unwrap_or(false);
1019 let result2 = check_proof_of_work(&valid_header).unwrap_or(false);
1020
1021 prop_assert_eq!(result1, result2, "Proof of work check must be deterministic");
1023 }
1024 }
1025
1026 proptest! {
1028 #[test]
1029 fn prop_get_next_work_required_bounds(
1030 current_header in arb_block_header(),
1031 prev_headers in proptest::collection::vec(arb_block_header(), 2..6)
1032 ) {
1033 let mut valid_headers = prev_headers;
1035 if let Some(first_header) = valid_headers.first_mut() {
1036 first_header.timestamp = current_header.timestamp - 86400 * 14; }
1038
1039 let result = get_next_work_required(¤t_header, &valid_headers);
1040
1041 match result {
1042 Ok(work) => {
1043 prop_assert!(work <= MAX_TARGET as Natural,
1045 "Next work required must not exceed maximum target");
1046 prop_assert!(work > 0, "Next work required must be positive");
1047 },
1048 Err(_) => {
1049 }
1051 }
1052 }
1053 }
1054}
1055
1056#[cfg(test)]
1057mod tests {
1058 use super::*;
1059 use crate::constants::MAX_TARGET;
1060
1061 #[test]
1062 fn test_get_next_work_required_insufficient_headers() {
1063 let header = BlockHeader {
1064 version: 1,
1065 prev_block_hash: [0; 32],
1066 merkle_root: [0; 32],
1067 timestamp: 1231006505,
1068 bits: 0x1d00ffff,
1069 nonce: 0,
1070 };
1071
1072 let prev_headers = vec![header.clone()];
1073 let result = get_next_work_required(&header, &prev_headers);
1074
1075 assert!(result.is_err());
1077 }
1078
1079 #[test]
1080 fn test_get_next_work_required_normal_adjustment() {
1081 let header1 = BlockHeader {
1082 version: 1,
1083 prev_block_hash: [0; 32],
1084 merkle_root: [0; 32],
1085 timestamp: 1000000,
1086 bits: 0x1d00ffff,
1087 nonce: 0,
1088 };
1089
1090 let header2 = BlockHeader {
1091 version: 1,
1092 prev_block_hash: [0; 32],
1093 merkle_root: [0; 32],
1094 timestamp: 1000000 + (DIFFICULTY_ADJUSTMENT_INTERVAL * TARGET_TIME_PER_BLOCK), bits: 0x1d00ffff,
1096 nonce: 0,
1097 };
1098
1099 let prev_headers = vec![header1, header2.clone()];
1100 let result = get_next_work_required(&header2, &prev_headers).unwrap();
1101
1102 assert_eq!(result, 0x1d00ffff);
1104 }
1105
1106 #[test]
1107 fn test_difficulty_from_bits() {
1108 let d = difficulty_from_bits(0x1d00ffff).unwrap();
1110 assert!(
1111 (d - 1.0).abs() < 0.01,
1112 "Genesis difficulty should be ~1.0, got {d}"
1113 );
1114 let d_harder = difficulty_from_bits(0x1d000800).unwrap();
1116 assert!(d_harder > d, "Harder target should have higher difficulty");
1117 }
1118
1119 #[test]
1120 fn test_expand_target() {
1121 let target = expand_target(0x0300ffff).unwrap(); assert!(!target.is_zero());
1125 }
1126
1127 #[test]
1128 fn test_check_proof_of_work_genesis() {
1129 let header = BlockHeader {
1131 version: 1,
1132 prev_block_hash: [0; 32],
1133 merkle_root: [0; 32],
1134 timestamp: 1231006505,
1135 bits: 0x0300ffff, nonce: 0,
1137 };
1138
1139 let result = check_proof_of_work(&header).unwrap();
1141 let _ = result;
1144 }
1145
1146 #[test]
1151 fn test_get_next_work_required_fast_blocks() {
1152 let header1 = BlockHeader {
1153 version: 1,
1154 prev_block_hash: [0; 32],
1155 merkle_root: [0; 32],
1156 timestamp: 1000000,
1157 bits: 0x1d00ffff,
1158 nonce: 0,
1159 };
1160
1161 let header2 = BlockHeader {
1163 version: 1,
1164 prev_block_hash: [0; 32],
1165 merkle_root: [0; 32],
1166 timestamp: 1000000 + (DIFFICULTY_ADJUSTMENT_INTERVAL * TARGET_TIME_PER_BLOCK / 2),
1167 bits: 0x1d00ffff,
1168 nonce: 0,
1169 };
1170
1171 let prev_headers = vec![header1, header2.clone()];
1172 let result = get_next_work_required(&header2, &prev_headers).unwrap();
1173
1174 assert!(result <= 0x1d00ffff);
1177 }
1178
1179 #[test]
1180 fn test_get_next_work_required_slow_blocks() {
1181 let header1 = BlockHeader {
1182 version: 1,
1183 prev_block_hash: [0; 32],
1184 merkle_root: [0; 32],
1185 timestamp: 1000000,
1186 bits: 0x1d00ffff,
1187 nonce: 0,
1188 };
1189
1190 let header2 = BlockHeader {
1192 version: 1,
1193 prev_block_hash: [0; 32],
1194 merkle_root: [0; 32],
1195 timestamp: 1000000 + (DIFFICULTY_ADJUSTMENT_INTERVAL * TARGET_TIME_PER_BLOCK * 2),
1196 bits: 0x1d00ffff,
1197 nonce: 0,
1198 };
1199
1200 let prev_headers = vec![header1, header2.clone()];
1201 let result = get_next_work_required(&header2, &prev_headers).unwrap();
1202
1203 assert!(result <= 0x1d00ffff);
1206 }
1207
1208 #[test]
1209 fn test_get_next_work_required_extreme_fast_blocks() {
1210 let header1 = BlockHeader {
1211 version: 1,
1212 prev_block_hash: [0; 32],
1213 merkle_root: [0; 32],
1214 timestamp: 1000000,
1215 bits: 0x1d00ffff,
1216 nonce: 0,
1217 };
1218
1219 let header2 = BlockHeader {
1221 version: 1,
1222 prev_block_hash: [0; 32],
1223 merkle_root: [0; 32],
1224 timestamp: 1000000 + (DIFFICULTY_ADJUSTMENT_INTERVAL * TARGET_TIME_PER_BLOCK / 14),
1225 bits: 0x1d00ffff,
1226 nonce: 0,
1227 };
1228
1229 let prev_headers = vec![header1, header2.clone()];
1230 let result = get_next_work_required(&header2, &prev_headers).unwrap();
1231
1232 assert!(result <= 0x1d00ffff);
1235 }
1236
1237 #[test]
1238 fn test_get_next_work_required_extreme_slow_blocks() {
1239 let header1 = BlockHeader {
1240 version: 1,
1241 prev_block_hash: [0; 32],
1242 merkle_root: [0; 32],
1243 timestamp: 1000000,
1244 bits: 0x1d00ffff,
1245 nonce: 0,
1246 };
1247
1248 let header2 = BlockHeader {
1250 version: 1,
1251 prev_block_hash: [0; 32],
1252 merkle_root: [0; 32],
1253 timestamp: 1000000 + (DIFFICULTY_ADJUSTMENT_INTERVAL * TARGET_TIME_PER_BLOCK * 4),
1254 bits: 0x1d00ffff,
1255 nonce: 0,
1256 };
1257
1258 let prev_headers = vec![header1, header2.clone()];
1259 let result = get_next_work_required(&header2, &prev_headers).unwrap();
1260
1261 assert!(result <= 0x1d00ffff);
1264 }
1265
1266 #[test]
1267 fn test_expand_target_zero_mantissa() {
1268 let result = expand_target(0x1d000000).unwrap();
1269 assert!(result.is_zero());
1270 }
1271
1272 #[test]
1273 fn test_expand_target_invalid_exponent_too_small() {
1274 let result = expand_target(0x0200ffff);
1275 assert!(result.is_err());
1276 }
1277
1278 #[test]
1279 fn test_expand_target_invalid_exponent_too_large() {
1280 let result = expand_target(0x2100ffff);
1281 assert!(result.is_err());
1282 }
1283
1284 #[test]
1285 fn test_expand_target_exponent_31() {
1286 let result = expand_target(0x1f00ffff).unwrap(); assert!(!result.is_zero());
1288 }
1289
1290 #[test]
1291 fn test_expand_target_exponent_32_regtest_bits() {
1292 let result = expand_target(0x2000ffff).unwrap();
1294 assert!(!result.is_zero());
1295 }
1296
1297 #[test]
1298 fn test_gbt_target_hex_regtest_minimum_difficulty() {
1299 let target = expand_target(0x207fffff).expect("regtest nBits");
1300 let hex = target.gbt_target_hex();
1301 assert_eq!(hex.len(), 64);
1302 assert_ne!(hex, "0".repeat(64));
1303 assert!(hex.starts_with("7fffff"));
1305 }
1306
1307 #[test]
1308 fn test_expand_target_exponent_3() {
1309 let result = expand_target(0x0300ffff).unwrap();
1310 assert!(!result.is_zero());
1311 }
1312
1313 #[test]
1314 fn test_expand_target_exponent_4() {
1315 let result = expand_target(0x0400ffff).unwrap();
1316 assert!(!result.is_zero());
1317 }
1318
1319 #[test]
1320 fn test_expand_target_exponent_29() {
1321 let result = expand_target(0x1d00ffff).unwrap();
1322 assert!(!result.is_zero());
1323 }
1324
1325 #[test]
1326 fn test_check_proof_of_work_invalid_target() {
1327 let header = BlockHeader {
1330 version: 1,
1331 prev_block_hash: [0; 32],
1332 merkle_root: [0; 32],
1333 timestamp: 1231006505,
1334 bits: 0x0200ffff, nonce: 0,
1336 };
1337
1338 let result = check_proof_of_work(&header);
1339 assert!(result.is_err());
1340 }
1341
1342 #[test]
1343 fn test_check_proof_of_work_valid_target() {
1344 let header = BlockHeader {
1345 version: 1,
1346 prev_block_hash: [0; 32],
1347 merkle_root: [0; 32],
1348 timestamp: 1231006505,
1349 bits: 0x1d00ffff, nonce: 0,
1351 };
1352
1353 let result = check_proof_of_work(&header).unwrap();
1354 let _ = result;
1356 }
1357
1358 #[test]
1359 fn test_get_block_proof_genesis_mainnet() {
1360 let work = get_block_proof(0x1d00ffff).unwrap();
1361 assert_eq!(
1362 work.gbt_target_hex(),
1363 "0000000000000000000000000000000000000000000000000000000100010001"
1364 );
1365 assert!(work > U256::zero());
1366 }
1367
1368 #[test]
1369 fn test_get_block_proof_regtest_minimum_difficulty() {
1370 let work = get_block_proof(0x207fffff).unwrap();
1371 assert!(work > U256::zero());
1372 assert!(work < U256::from_u128(10));
1373 }
1374
1375 #[test]
1376 fn test_u256_zero() {
1377 let zero = U256::zero();
1378 assert!(zero.is_zero());
1379 }
1380
1381 #[test]
1382 fn test_u256_from_u32() {
1383 let value = U256::from_u32(0x12345678);
1384 assert!(!value.is_zero());
1385 }
1386
1387 #[test]
1388 fn test_u256_from_u64() {
1389 let value = U256::from_u64(0x123456789abcdef0);
1390 assert!(!value.is_zero());
1391 }
1392
1393 #[test]
1394 fn test_u256_shl_zero_shift() {
1395 let value = U256::from_u32(0x12345678);
1396 let result = value.shl(0);
1397 assert_eq!(result, value);
1398 }
1399
1400 #[test]
1401 fn test_u256_shl_large_shift() {
1402 let value = U256::from_u32(0x12345678);
1403 let result = value.shl(300); assert!(result.is_zero());
1405 }
1406
1407 #[test]
1408 fn test_u256_shr_zero_shift() {
1409 let value = U256::from_u32(0x12345678);
1410 let result = value.shr(0);
1411 assert_eq!(result, value);
1412 }
1413
1414 #[test]
1415 fn test_u256_shr_large_shift() {
1416 let value = U256::from_u32(0x12345678);
1417 let result = value.shr(300); assert!(result.is_zero());
1419 }
1420
1421 #[test]
1422 fn test_u256_shl_small_shift() {
1423 let value = U256::from_u32(0x12345678);
1424 let result = value.shl(8);
1425 assert!(!result.is_zero());
1426 assert_ne!(result, value);
1427 }
1428
1429 #[test]
1430 fn test_u256_shr_small_shift() {
1431 let value = U256::from_u32(0x12345678);
1432 let result = value.shr(8);
1433 assert!(!result.is_zero());
1434 assert_ne!(result, value);
1435 }
1436
1437 #[test]
1438 fn test_u256_to_bytes() {
1439 let value = U256::from_u32(0x12345678);
1440 let bytes = value.to_bytes();
1441 assert_eq!(bytes.len(), 32);
1442 }
1443
1444 #[test]
1445 fn test_u256_from_bytes() {
1446 let mut bytes = [0u8; 32];
1447 bytes[0] = 0x78;
1448 bytes[1] = 0x56;
1449 bytes[2] = 0x34;
1450 bytes[3] = 0x12;
1451 let value = U256::from_bytes(&bytes);
1452 assert!(!value.is_zero());
1453 }
1454
1455 #[test]
1456 fn test_u256_ordering() {
1457 let small = U256::from_u32(0x12345678);
1458 let large = U256::from_u32(0x87654321);
1459
1460 assert!(small < large);
1461 assert!(large > small);
1462 assert_eq!(small.cmp(&small), std::cmp::Ordering::Equal);
1463 }
1464
1465 #[test]
1466 fn test_expand_compress_round_trip() {
1467 let test_bits = vec![
1469 0x1d00ffff, 0x1b0404cb, 0x0300ffff, ];
1476
1477 for &bits in &test_bits {
1478 let expanded = match expand_target(bits) {
1480 Ok(t) => t,
1481 Err(_) => continue, };
1483
1484 let compressed = match compress_target(&expanded) {
1486 Ok(b) => b,
1487 Err(_) => {
1488 continue;
1491 }
1492 };
1493
1494 let re_expanded = match expand_target(compressed) {
1496 Ok(t) => t,
1497 Err(_) => continue,
1498 };
1499
1500 if re_expanded > expanded {
1504 panic!(
1505 "Round-trip failed for bits 0x{bits:08x}: re-expanded > original (compression should truncate, not add)"
1506 );
1507 }
1508 #[allow(clippy::eq_op)]
1515 let significant_words_match =
1516 expanded.0[2] == re_expanded.0[2] && expanded.0[3] == re_expanded.0[3];
1517 if !significant_words_match {
1518 panic!(
1519 "Round-trip failed for bits 0x{:08x}: significant bits differ (expanded: {:?}, re-expanded: {:?})",
1520 bits, expanded.0, re_expanded.0
1521 );
1522 }
1523 }
1525 }
1526
1527 #[test]
1528 fn test_compress_target_genesis() {
1529 let genesis_bits = 0x1d00ffff;
1531 let expanded = expand_target(genesis_bits).unwrap();
1532 let compressed = compress_target(&expanded).unwrap();
1533
1534 assert!(compressed <= MAX_TARGET as u64);
1536 assert!(compressed > 0);
1537
1538 let re_expanded = expand_target(compressed).unwrap();
1540 assert_eq!(expanded, re_expanded);
1541 }
1542
1543 #[test]
1544 fn test_serialize_header() {
1545 let header = BlockHeader {
1546 version: 1,
1547 prev_block_hash: [1; 32],
1548 merkle_root: [2; 32],
1549 timestamp: 1234567890,
1550 bits: 0x1d00ffff,
1551 nonce: 0x12345678,
1552 };
1553
1554 let bytes = serialize_header(&header);
1555 assert_eq!(bytes.len(), 80); }
1557
1558 #[test]
1563 fn test_serialize_header_returns_fixed_80_bytes() {
1564 let header = BlockHeader {
1566 version: 1,
1567 prev_block_hash: [0; 32],
1568 merkle_root: [0; 32],
1569 timestamp: 0,
1570 bits: 0,
1571 nonce: 0,
1572 };
1573 let bytes: [u8; 80] = serialize_header(&header);
1574 assert_eq!(bytes.len(), 80);
1575 }
1576
1577 #[test]
1578 fn test_serialize_header_field_layout() {
1579 let header = BlockHeader {
1581 version: 0x01020304,
1582 prev_block_hash: {
1583 let mut h = [0u8; 32];
1584 h[0] = 0xAA;
1585 h[31] = 0xBB;
1586 h
1587 },
1588 merkle_root: {
1589 let mut h = [0u8; 32];
1590 h[0] = 0xCC;
1591 h[31] = 0xDD;
1592 h
1593 },
1594 timestamp: 0x05060708,
1595 bits: 0x090A0B0C,
1596 nonce: 0x0D0E0F10,
1597 };
1598
1599 let bytes = serialize_header(&header);
1600
1601 assert_eq!(bytes[0], 0x04); assert_eq!(bytes[1], 0x03);
1604 assert_eq!(bytes[2], 0x02);
1605 assert_eq!(bytes[3], 0x01);
1606
1607 assert_eq!(bytes[4], 0xAA);
1609 assert_eq!(bytes[35], 0xBB);
1610
1611 assert_eq!(bytes[36], 0xCC);
1613 assert_eq!(bytes[67], 0xDD);
1614
1615 assert_eq!(bytes[68], 0x08);
1617 assert_eq!(bytes[69], 0x07);
1618 assert_eq!(bytes[70], 0x06);
1619 assert_eq!(bytes[71], 0x05);
1620
1621 assert_eq!(bytes[72], 0x0C);
1623 assert_eq!(bytes[73], 0x0B);
1624 assert_eq!(bytes[74], 0x0A);
1625 assert_eq!(bytes[75], 0x09);
1626
1627 assert_eq!(bytes[76], 0x10);
1629 assert_eq!(bytes[77], 0x0F);
1630 assert_eq!(bytes[78], 0x0E);
1631 assert_eq!(bytes[79], 0x0D);
1632 }
1633
1634 #[test]
1635 fn test_serialize_header_deterministic() {
1636 let header = BlockHeader {
1637 version: 1,
1638 prev_block_hash: [0xFF; 32],
1639 merkle_root: [0xAA; 32],
1640 timestamp: 1231006505,
1641 bits: 0x1d00ffff,
1642 nonce: 2083236893,
1643 };
1644
1645 let bytes1 = serialize_header(&header);
1646 let bytes2 = serialize_header(&header);
1647 assert_eq!(bytes1, bytes2, "Header serialization must be deterministic");
1648 }
1649
1650 #[test]
1651 fn test_serialize_header_different_headers_different_bytes() {
1652 let header1 = BlockHeader {
1653 version: 1,
1654 prev_block_hash: [0; 32],
1655 merkle_root: [0; 32],
1656 timestamp: 1231006505,
1657 bits: 0x1d00ffff,
1658 nonce: 0,
1659 };
1660
1661 let mut header2 = header1.clone();
1662 header2.nonce = 1;
1663
1664 let bytes1 = serialize_header(&header1);
1665 let bytes2 = serialize_header(&header2);
1666 assert_ne!(
1667 bytes1, bytes2,
1668 "Different nonces must produce different serializations"
1669 );
1670
1671 assert_eq!(
1673 bytes1[..76],
1674 bytes2[..76],
1675 "Non-nonce bytes should be identical"
1676 );
1677 assert_ne!(bytes1[76..], bytes2[76..], "Nonce bytes should differ");
1678 }
1679
1680 #[test]
1681 fn test_u256_from_bytes_simple() {
1682 let bytes = [0u8; 32];
1683 let value = u256_from_bytes(&bytes);
1684 assert_eq!(value, 0);
1685 }
1686
1687 #[test]
1688 fn test_u256_from_bytes_with_data() {
1689 let mut bytes = [0u8; 32];
1690 bytes[0] = 0x78;
1691 bytes[1] = 0x56;
1692 bytes[2] = 0x34;
1693 bytes[3] = 0x12;
1694 let value = u256_from_bytes(&bytes);
1695 assert_eq!(value, 0x78563412000000000000000000000000);
1698 }
1699}