diff --git a/verification/src/chain_verifier.rs b/verification/src/chain_verifier.rs index e420acd3..2b6f9264 100644 --- a/verification/src/chain_verifier.rs +++ b/verification/src/chain_verifier.rs @@ -6,7 +6,7 @@ use db::{self, BlockRef}; use chain; use super::{Verify, VerificationResult, Chain, Error}; use primitives::hash::H256; -use byteorder::{LittleEndian, BigEndian, ByteOrder}; +use utils; const BLOCK_MAX_FUTURE: i64 = 2 * 60 * 60; // 2 hours @@ -20,47 +20,6 @@ impl ChainVerifier { } } -fn check_nbits(hash: &H256, n_bits: u32) -> bool { - let hash_bytes: &[u8] = &**hash; - - let mut nb = [0u8; 4]; - BigEndian::write_u32(&mut nb, n_bits); - let shift = (nb[0] - 3) as usize; // total shift for mantissa - - if shift >= 30 { return false; } // invalid shift - - let should_be_zero = shift + 3..32; - let should_be_le = shift..shift + 3; - - for z_check in should_be_zero { - if hash_bytes[z_check as usize] != 0 { return false; } - } - - // making u32 from 3 bytes - let mut order = 0; - let hash_val: u32 = hash_bytes[should_be_le].iter().fold(0u32, |s, a| { let r = s + ((*a as u32) << order); order = order + 8; r }); - - // using 3 bytes leftover of nbits - nb[0] = 0; - let threshold = BigEndian::read_u32(&nb); - if hash_val < threshold { - return true; - } - else if hash_val > threshold { - return false; - } - - // the case when hash effective bits are equal to nbits - // then the rest of the hash must be zero - for byte in hash_bytes[0..shift].iter() { if *byte != 0 { return false; } } - - return true; -} - -fn age(protocol_time: u32) -> i64 { - ::time::get_time().sec - protocol_time as i64 -} - impl Verify for ChainVerifier { fn verify(&self, block: &chain::Block) -> VerificationResult { let hash = block.hash(); @@ -71,12 +30,12 @@ impl Verify for ChainVerifier { } // target difficulty threshold - if !check_nbits(&hash, block.header().nbits) { + if !utils::check_nbits(&hash, block.header().nbits) { return Err(Error::Pow); } // check if block timestamp is not far in the future - if age(block.header().time) < -BLOCK_MAX_FUTURE { + if utils::age(block.header().time) < -BLOCK_MAX_FUTURE { return Err(Error::Timestamp); } @@ -97,7 +56,7 @@ impl Verify for ChainVerifier { #[cfg(test)] mod tests { - use super::{check_nbits, ChainVerifier}; + use super::ChainVerifier; use super::super::{Verify, Chain}; use primitives::hash::H256; use chain; @@ -196,32 +155,4 @@ mod tests { assert_eq!(Chain::Main, verifier.verify(&b1).unwrap()); } - #[test] - fn nbits() { - // strictly equal - let hash = H256::from_reversed_str("00000000000000001bc330000000000000000000000000000000000000000000"); - let nbits = 0x181bc330u32; - assert!(check_nbits(&hash, nbits)); - - // nbits match but not equal (greater) - let hash = H256::from_reversed_str("00000000000000001bc330000000000000000000000000000000000000000001"); - let nbits = 0x181bc330u32; - assert!(!check_nbits(&hash, nbits)); - - // greater - let hash = H256::from_reversed_str("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); - let nbits = 0x181bc330u32; - assert!(!check_nbits(&hash, nbits)); - - - // some real examples - let hash = H256::from_reversed_str("000000000000000001f942eb4bfa0aeccb6a14c268f4c72d5fff17270da771b9"); - let nbits = 404129525; - assert!(check_nbits(&hash, nbits)); - - // some real examples - let hash = H256::from_reversed_str("00000000000000000e753ef636075711efd2cbf5a8473c7c5b67755a3701e0c2"); - let nbits = 404129525; - assert!(check_nbits(&hash, nbits)); - } } diff --git a/verification/src/lib.rs b/verification/src/lib.rs index eecded87..1570de61 100644 --- a/verification/src/lib.rs +++ b/verification/src/lib.rs @@ -15,6 +15,7 @@ extern crate ethcore_devtools as devtools; extern crate test_data; mod queue; +mod utils; mod chain_verifier; pub use queue::Queue; diff --git a/verification/src/utils.rs b/verification/src/utils.rs new file mode 100644 index 00000000..f2718e60 --- /dev/null +++ b/verification/src/utils.rs @@ -0,0 +1,79 @@ +//! Verification utilities +use primitives::hash::H256; +use byteorder::{LittleEndian, BigEndian, ByteOrder}; + +pub fn check_nbits(hash: &H256, n_bits: u32) -> bool { + let hash_bytes: &[u8] = &**hash; + + let mut nb = [0u8; 4]; + BigEndian::write_u32(&mut nb, n_bits); + let shift = (nb[0] - 3) as usize; // total shift for mantissa + + if shift >= 30 { return false; } // invalid shift + + let should_be_zero = shift + 3..32; + let should_be_le = shift..shift + 3; + + for z_check in should_be_zero { + if hash_bytes[z_check as usize] != 0 { return false; } + } + + // making u32 from 3 bytes + let mut order = 0; + let hash_val: u32 = hash_bytes[should_be_le].iter().fold(0u32, |s, a| { let r = s + ((*a as u32) << order); order = order + 8; r }); + + // using 3 bytes leftover of nbits + nb[0] = 0; + let threshold = BigEndian::read_u32(&nb); + if hash_val < threshold { + return true; + } + else if hash_val > threshold { + return false; + } + + // the case when hash effective bits are equal to nbits + // then the rest of the hash must be zero + for byte in hash_bytes[0..shift].iter() { if *byte != 0 { return false; } } + + return true; +} + +pub fn age(protocol_time: u32) -> i64 { + ::time::get_time().sec - protocol_time as i64 +} + +#[cfg(test)] +mod tests { + + use super::check_nbits; + use primitives::hash::H256; + + #[test] + fn nbits() { + // strictly equal + let hash = H256::from_reversed_str("00000000000000001bc330000000000000000000000000000000000000000000"); + let nbits = 0x181bc330u32; + assert!(check_nbits(&hash, nbits)); + + // nbits match but not equal (greater) + let hash = H256::from_reversed_str("00000000000000001bc330000000000000000000000000000000000000000001"); + let nbits = 0x181bc330u32; + assert!(!check_nbits(&hash, nbits)); + + // greater + let hash = H256::from_reversed_str("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); + let nbits = 0x181bc330u32; + assert!(!check_nbits(&hash, nbits)); + + + // some real examples + let hash = H256::from_reversed_str("000000000000000001f942eb4bfa0aeccb6a14c268f4c72d5fff17270da771b9"); + let nbits = 404129525; + assert!(check_nbits(&hash, nbits)); + + let hash = H256::from_reversed_str("00000000000000000e753ef636075711efd2cbf5a8473c7c5b67755a3701e0c2"); + let nbits = 404129525; + assert!(check_nbits(&hash, nbits)); + } +}