From a5fb6e757f53e5d7c81c754d4afb694ef5322c26 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Sun, 23 Oct 2016 19:10:25 +0300 Subject: [PATCH] nbits check --- Cargo.lock | 1 + verification/Cargo.toml | 1 + verification/src/chain_verifier.rs | 76 ++++++++++++++++++++++++++++-- verification/src/lib.rs | 1 + 4 files changed, 76 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 816d6e93..6ef24d0b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -602,6 +602,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "verification" version = "0.1.0" dependencies = [ + "byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "chain 0.1.0", "db 0.1.0", "ethcore-devtools 1.3.0", diff --git a/verification/Cargo.toml b/verification/Cargo.toml index 1bf4b4b1..6ec29c98 100644 --- a/verification/Cargo.toml +++ b/verification/Cargo.toml @@ -12,3 +12,4 @@ serialization = { path = "../serialization" } parking_lot = "0.3" linked-hash-map = "0.3" test-data = { path = "../test-data" } +byteorder = "0.5" diff --git a/verification/src/chain_verifier.rs b/verification/src/chain_verifier.rs index 50180024..7a2ac06e 100644 --- a/verification/src/chain_verifier.rs +++ b/verification/src/chain_verifier.rs @@ -5,6 +5,8 @@ use std::sync::Arc; use db::{self, BlockRef}; use chain; use super::{Verify, VerificationResult, Chain, Error}; +use primitives::hash::H256; +use byteorder::{LittleEndian, BigEndian, ByteOrder}; pub struct ChainVerifier { store: Arc, @@ -16,16 +18,56 @@ 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; +} + impl Verify for ChainVerifier { fn verify(&self, block: &chain::Block) -> VerificationResult { + let hash = block.hash(); // There should be at least 1 transaction if block.transactions().is_empty() { return Err(Error::Empty); } - // - + // target difficulty threshold + if !check_nbits(&hash, block.header().nbits) { + return Err(Error::Pow); + } let parent = match self.store.block(BlockRef::Hash(block.header().previous_header_hash.clone())) { Some(b) => b, @@ -39,7 +81,7 @@ impl Verify for ChainVerifier { #[cfg(test)] mod tests { - use super::ChainVerifier; + use super::{check_nbits, ChainVerifier}; use super::super::{Verify, Chain}; use primitives::hash::H256; use chain; @@ -138,4 +180,32 @@ 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 964c94a8..20d2fc05 100644 --- a/verification/src/lib.rs +++ b/verification/src/lib.rs @@ -6,6 +6,7 @@ extern crate chain; extern crate serialization; extern crate parking_lot; extern crate linked_hash_map; +extern crate byteorder; #[cfg(test)] extern crate ethcore_devtools as devtools;