Use ethash for verification

This commit is contained in:
arkpar
2016-01-17 12:00:34 +01:00
parent d07934ffee
commit e39e7491b8
9 changed files with 1183 additions and 7 deletions

View File

@@ -62,6 +62,7 @@ pub enum BlockError {
InvalidReceiptsStateRoot(Mismatch<H256>),
InvalidTimestamp(OutOfBounds<u64>),
InvalidLogBloom(Mismatch<LogBloom>),
InvalidEthashDifficulty(Mismatch<U256>),
InvalidBlockNonce(Mismatch<H256>),
InvalidParentHash(Mismatch<H256>),
InvalidNumber(OutOfBounds<BlockNumber>),

View File

@@ -1,3 +1,6 @@
extern crate ethash;
use self::ethash::{quick_get_difficulty, EthashManager, H256 as EH256};
use common::*;
use block::*;
use spec::*;
@@ -8,11 +11,15 @@ use evm::Schedule;
/// mainnet chains in the Olympic, Frontier and Homestead eras.
pub struct Ethash {
spec: Spec,
pow: EthashManager,
}
impl Ethash {
pub fn new_boxed(spec: Spec) -> Box<Engine> {
Box::new(Ethash{spec: spec})
Box::new(Ethash {
spec: spec,
pow: EthashManager::new(),
})
}
fn u256_param(&self, name: &str) -> U256 { self.spec().engine_params.get(name).map(|a| decode(&a)).unwrap_or(U256::from(0u64)) }
@@ -69,12 +76,26 @@ impl Engine for Ethash {
if header.difficulty < min_difficulty {
return Err(From::from(BlockError::InvalidDifficulty(Mismatch { expected: min_difficulty, found: header.difficulty })))
}
// TODO: Verify seal (quick)
let difficulty = Ethash::boundary_to_difficulty(&Ethash::from_ethash(quick_get_difficulty(
&Ethash::to_ethash(header.bare_hash()),
header.nonce(),
&Ethash::to_ethash(header.mix_hash()))));
if difficulty < header.difficulty {
return Err(From::from(BlockError::InvalidEthashDifficulty(Mismatch { expected: header.difficulty, found: difficulty })));
}
Ok(())
}
fn verify_block_unordered(&self, _header: &Header, _block: Option<&[u8]>) -> result::Result<(), Error> {
// TODO: Verify seal (full)
fn verify_block_unordered(&self, header: &Header, _block: Option<&[u8]>) -> result::Result<(), Error> {
let result = self.pow.compute_light(header.number as u64, &Ethash::to_ethash(header.bare_hash()), header.nonce());
let mix = Ethash::from_ethash(result.mix_hash);
let difficulty = Ethash::boundary_to_difficulty(&Ethash::from_ethash(result.value));
if mix != header.mix_hash() {
return Err(From::from(BlockError::InvalidBlockNonce(Mismatch { expected: mix, found: header.mix_hash() })));
}
if difficulty < header.difficulty {
return Err(From::from(BlockError::InvalidEthashDifficulty(Mismatch { expected: header.difficulty, found: difficulty })));
}
Ok(())
}
@@ -131,6 +152,27 @@ impl Ethash {
}
target
}
fn boundary_to_difficulty(boundary: &H256) -> U256 {
U256::from((U512::one() << 256) / x!(U256::from(boundary.as_slice())))
}
fn to_ethash(hash: H256) -> EH256 {
unsafe { mem::transmute(hash) }
}
fn from_ethash(hash: EH256) -> H256 {
unsafe { mem::transmute(hash) }
}
}
impl Header {
fn nonce(&self) -> u64 {
decode(&self.seal()[1])
}
fn mix_hash(&self) -> H256 {
decode(&self.seal()[0])
}
}
#[test]

View File

@@ -32,6 +32,7 @@ pub struct Header {
pub seal: Vec<Bytes>,
pub hash: RefCell<Option<H256>>,
pub bare_hash: RefCell<Option<H256>>,
}
impl Header {
@@ -56,6 +57,7 @@ impl Header {
difficulty: ZERO_U256,
seal: vec![],
hash: RefCell::new(None),
bare_hash: RefCell::new(None),
}
}
@@ -99,13 +101,24 @@ impl Header {
}
}
/// Get the hash of the header excluding the seal
pub fn bare_hash(&self) -> H256 {
let mut hash = self.bare_hash.borrow_mut();
match &mut *hash {
&mut Some(ref h) => h.clone(),
hash @ &mut None => {
*hash = Some(self.rlp_sha3(Seal::Without));
hash.as_ref().unwrap().clone()
}
}
}
/// Note that some fields have changed. Resets the memoised hash.
pub fn note_dirty(&self) {
*self.hash.borrow_mut() = None;
*self.bare_hash.borrow_mut() = None;
}
// TODO: get hash without seal.
// TODO: make these functions traity
pub fn stream_rlp(&self, s: &mut RlpStream, with_seal: Seal) {
s.append_list(13 + match with_seal { Seal::With => self.seal.len(), _ => 0 });
@@ -156,7 +169,8 @@ impl Decodable for Header {
timestamp: try!(r.val_at(11)),
extra_data: try!(r.val_at(12)),
seal: vec![],
hash: RefCell::new(Some(r.as_raw().sha3()))
hash: RefCell::new(Some(r.as_raw().sha3())),
bare_hash: RefCell::new(None),
};
for i in 13..r.item_count() {

View File

@@ -137,6 +137,7 @@ impl Spec {
(0..self.seal_fields).map(|i| r.at(i).as_raw().to_vec()).collect()
},
hash: RefCell::new(None),
bare_hash: RefCell::new(None),
}
}