utils mod

This commit is contained in:
NikVolf 2016-10-23 21:28:00 +03:00
parent 903d2b8878
commit 567facbe29
3 changed files with 84 additions and 73 deletions

View File

@ -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));
}
}

View File

@ -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;

79
verification/src/utils.rs Normal file
View File

@ -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));
}
}