pow validation in progress

This commit is contained in:
debris 2016-11-23 04:10:11 +01:00
parent bcf09357c5
commit 961e4361cf
9 changed files with 135 additions and 3 deletions

1
Cargo.lock generated
View File

@ -493,6 +493,7 @@ dependencies = [
name = "primitives"
version = "0.1.0"
dependencies = [
"byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
"heapsize 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",

View File

@ -5,6 +5,8 @@ use ser::{
};
use crypto::dhash256;
use hash::H256;
use uint::U256;
use nbits::{NBits, MAX_NBITS_MAINNET, MAX_NBITS_REGTEST};
#[derive(PartialEq, Clone)]
pub struct BlockHeader {
@ -20,6 +22,36 @@ impl BlockHeader {
pub fn hash(&self) -> H256 {
dhash256(&serialize(self))
}
/// Returns the total work of the block
//pub fn work(&self) -> U256 {
//// 2**256 / (target + 1) == ~target / (target+1) + 1 (eqn shamelessly stolen from bitcoind)
//let mut ret = !self.target();
//let mut ret1 = self.target();
//ret1 = ret1 + 1.into();
//ret = ret / ret1;
//ret = ret + 1.into();
//ret
//}
pub fn is_valid_proof_of_work(&self) -> bool {
let max = match NBits::new(MAX_NBITS_REGTEST).target() {
Some(max) => max,
None => return false,
};
let target = match NBits::new(self.nbits).target() {
Some(target) => target,
None => return false,
};
if target > max {
return false;
}
let target = H256::from(target.to_little_endian());
self.hash() <= target
}
}
impl fmt::Debug for BlockHeader {
@ -66,6 +98,7 @@ impl Deserializable for BlockHeader {
mod tests {
use ser::{Reader, Error as ReaderError, Stream};
use super::BlockHeader;
use nbits::MAX_NBITS_REGTEST;
#[test]
fn test_block_header_stream() {
@ -118,4 +151,11 @@ mod tests {
assert_eq!(expected, reader.read().unwrap());
assert_eq!(ReaderError::UnexpectedEnd, reader.read::<BlockHeader>().unwrap_err());
}
#[test]
fn test_is_valid_proof_of_work() {
let mut header = BlockHeader::default();
header.nbits = MAX_NBITS_REGTEST;
assert!(header.is_valid_proof_of_work());
}
}

View File

@ -7,6 +7,7 @@ extern crate serialization as ser;
mod block;
mod block_header;
mod merkle_root;
mod nbits;
mod transaction;
pub trait RepresentH256 {
@ -14,7 +15,7 @@ pub trait RepresentH256 {
}
pub use rustc_serialize::hex;
pub use primitives::{hash, bytes};
pub use primitives::{hash, bytes, uint};
pub use self::block::Block;
pub use self::block_header::BlockHeader;

55
chain/src/nbits.rs Normal file
View File

@ -0,0 +1,55 @@
use uint::U256;
pub const MAX_NBITS_MAINNET: u32 = 0x1d00ffff;
pub const MAX_NBITS_TESTNET: u32 = 0x1d00ffff;
pub const MAX_NBITS_REGTEST: u32 = 0x207fffff;
#[derive(Debug, PartialEq, Clone, Copy)]
pub struct NBits(u32);
impl NBits {
pub fn new(u: u32) -> Self {
NBits(u)
}
/// Computes the target [0, T] that a blockhash must land in to be valid
/// Returns None, if there is an overflow or its negative value
pub fn target(&self) -> Option<U256> {
let size = self.0 >> 24;
let mut word = self.0 & 0x007fffff;
let result = if size <= 3 {
word = word >> (8 * (3 - size as usize));
word.into()
} else {
U256::from(word) << (8 * (size as usize - 3))
};
let is_negative = word != 0 && (self.0 & 0x00800000) != 0;
let is_overflow = (word != 0 && size > 34) ||
(word > 0xff && size > 33) ||
(word > 0xffff && size > 32);
if is_negative || is_overflow {
None
} else {
Some(result)
}
}
}
#[cfg(test)]
mod tests {
use super::NBits;
#[test]
fn test_basic_nbits_target() {
assert_eq!(NBits::new(0x01003456).target(), Some(0.into()));
assert_eq!(NBits::new(0x01123456).target(), Some(0x12.into()));
assert_eq!(NBits::new(0x02008000).target(), Some(0x80.into()));
assert_eq!(NBits::new(0x05009234).target(), Some(0x92340000u64.into()));
// negative -0x12345600
assert_eq!(NBits::new(0x04923456).target(), None);
assert_eq!(NBits::new(0x04123456).target(), Some(0x12345600u64.into()));
}
}

View File

@ -6,6 +6,7 @@ build = "build.rs"
[dependencies]
heapsize = "0.3"
byteorder = "0.5"
rustc-serialize = "0.3"
[build-dependencies]

View File

@ -105,6 +105,15 @@ macro_rules! impl_hash {
}
}
impl cmp::PartialOrd for $name {
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
let self_ref: &[u8] = &self.0;
let other_ref: &[u8] = &other.0;
self_ref.partial_cmp(other_ref)
}
}
impl Hash for $name {
fn hash<H>(&self, state: &mut H) where H: Hasher {
state.write(&self.0);

View File

@ -1,7 +1,8 @@
#![cfg_attr(asm_available, feature(asm))]
extern crate rustc_serialize;
extern crate byteorder;
#[macro_use] extern crate heapsize;
extern crate rustc_serialize;
pub mod bytes;
pub mod hash;

View File

@ -8,6 +8,7 @@
use std::{str, fmt};
use std::ops::{Shr, Shl, BitAnd, BitOr, BitXor, Not, Div, Rem, Mul, Add, Sub};
use std::cmp::Ordering;
use byteorder::{WriteBytesExt, LittleEndian, BigEndian};
use hex::{FromHex, FromHexError};
/// Conversion from decimal string error
@ -393,6 +394,28 @@ macro_rules! construct_uint {
Ok(res)
}
pub fn to_little_endian(&self) -> [u8; $n_words * 8] {
let mut result = [0u8; $n_words * 8];
{
let mut result_ref: &mut [u8] = &mut result;
for word in self.0.into_iter() {
result_ref.write_u64::<LittleEndian>(*word).expect("sizeof($n_words * u8 * 8) == sizeof($n_words * u64); qed");
}
}
result
}
pub fn to_big_endian(&self) -> [u8; $n_words * 8] {
let mut result = [0u8; $n_words * 8];
{
let mut result_ref: &mut [u8] = &mut result;
for word in self.0.into_iter().rev() {
result_ref.write_u64::<BigEndian>(*word).expect("sizeof($n_words * u8 * 8) == sizeof($n_words * u64); qed");
}
}
result
}
#[inline]
pub fn low_u32(&self) -> u32 {
let &$name(ref arr) = self;

View File

@ -194,7 +194,8 @@ impl ChainVerifier {
}
// target difficulty threshold
if !self.skip_pow && !utils::check_nbits(&hash, block.header().nbits) {
//if !self.skip_pow && !utils::check_nbits(&hash, block.header().nbits) {
if !self.skip_pow && !block.header().is_valid_proof_of_work() {
return Err(Error::Pow);
}