Use ethash for verification
This commit is contained in:
@@ -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>),
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user