pow validation in progress
This commit is contained in:
parent
bcf09357c5
commit
961e4361cf
|
@ -493,6 +493,7 @@ dependencies = [
|
||||||
name = "primitives"
|
name = "primitives"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
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)",
|
"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-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)",
|
"rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
|
|
@ -5,6 +5,8 @@ use ser::{
|
||||||
};
|
};
|
||||||
use crypto::dhash256;
|
use crypto::dhash256;
|
||||||
use hash::H256;
|
use hash::H256;
|
||||||
|
use uint::U256;
|
||||||
|
use nbits::{NBits, MAX_NBITS_MAINNET, MAX_NBITS_REGTEST};
|
||||||
|
|
||||||
#[derive(PartialEq, Clone)]
|
#[derive(PartialEq, Clone)]
|
||||||
pub struct BlockHeader {
|
pub struct BlockHeader {
|
||||||
|
@ -20,6 +22,36 @@ impl BlockHeader {
|
||||||
pub fn hash(&self) -> H256 {
|
pub fn hash(&self) -> H256 {
|
||||||
dhash256(&serialize(self))
|
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 {
|
impl fmt::Debug for BlockHeader {
|
||||||
|
@ -66,6 +98,7 @@ impl Deserializable for BlockHeader {
|
||||||
mod tests {
|
mod tests {
|
||||||
use ser::{Reader, Error as ReaderError, Stream};
|
use ser::{Reader, Error as ReaderError, Stream};
|
||||||
use super::BlockHeader;
|
use super::BlockHeader;
|
||||||
|
use nbits::MAX_NBITS_REGTEST;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_block_header_stream() {
|
fn test_block_header_stream() {
|
||||||
|
@ -118,4 +151,11 @@ mod tests {
|
||||||
assert_eq!(expected, reader.read().unwrap());
|
assert_eq!(expected, reader.read().unwrap());
|
||||||
assert_eq!(ReaderError::UnexpectedEnd, reader.read::<BlockHeader>().unwrap_err());
|
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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ extern crate serialization as ser;
|
||||||
mod block;
|
mod block;
|
||||||
mod block_header;
|
mod block_header;
|
||||||
mod merkle_root;
|
mod merkle_root;
|
||||||
|
mod nbits;
|
||||||
mod transaction;
|
mod transaction;
|
||||||
|
|
||||||
pub trait RepresentH256 {
|
pub trait RepresentH256 {
|
||||||
|
@ -14,7 +15,7 @@ pub trait RepresentH256 {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub use rustc_serialize::hex;
|
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::Block;
|
||||||
pub use self::block_header::BlockHeader;
|
pub use self::block_header::BlockHeader;
|
||||||
|
|
|
@ -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()));
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,6 +6,7 @@ build = "build.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
heapsize = "0.3"
|
heapsize = "0.3"
|
||||||
|
byteorder = "0.5"
|
||||||
rustc-serialize = "0.3"
|
rustc-serialize = "0.3"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
|
|
|
@ -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 {
|
impl Hash for $name {
|
||||||
fn hash<H>(&self, state: &mut H) where H: Hasher {
|
fn hash<H>(&self, state: &mut H) where H: Hasher {
|
||||||
state.write(&self.0);
|
state.write(&self.0);
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
#![cfg_attr(asm_available, feature(asm))]
|
#![cfg_attr(asm_available, feature(asm))]
|
||||||
|
|
||||||
extern crate rustc_serialize;
|
extern crate byteorder;
|
||||||
#[macro_use] extern crate heapsize;
|
#[macro_use] extern crate heapsize;
|
||||||
|
extern crate rustc_serialize;
|
||||||
|
|
||||||
pub mod bytes;
|
pub mod bytes;
|
||||||
pub mod hash;
|
pub mod hash;
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
use std::{str, fmt};
|
use std::{str, fmt};
|
||||||
use std::ops::{Shr, Shl, BitAnd, BitOr, BitXor, Not, Div, Rem, Mul, Add, Sub};
|
use std::ops::{Shr, Shl, BitAnd, BitOr, BitXor, Not, Div, Rem, Mul, Add, Sub};
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
|
use byteorder::{WriteBytesExt, LittleEndian, BigEndian};
|
||||||
use hex::{FromHex, FromHexError};
|
use hex::{FromHex, FromHexError};
|
||||||
|
|
||||||
/// Conversion from decimal string error
|
/// Conversion from decimal string error
|
||||||
|
@ -393,6 +394,28 @@ macro_rules! construct_uint {
|
||||||
Ok(res)
|
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]
|
#[inline]
|
||||||
pub fn low_u32(&self) -> u32 {
|
pub fn low_u32(&self) -> u32 {
|
||||||
let &$name(ref arr) = self;
|
let &$name(ref arr) = self;
|
||||||
|
|
|
@ -194,7 +194,8 @@ impl ChainVerifier {
|
||||||
}
|
}
|
||||||
|
|
||||||
// target difficulty threshold
|
// 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);
|
return Err(Error::Pow);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue