Skip to content
This repository has been archived by the owner on Nov 6, 2020. It is now read-only.

fixed parsing ethash seals and verify_block_undordered #8031

Merged
merged 1 commit into from
Mar 1, 2018
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 67 additions & 41 deletions ethcore/src/ethereum/ethash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use error::{BlockError, Error};
use header::{Header, BlockNumber};
use engines::{self, Engine};
use ethjson;
use rlp::{self, UntrustedRlp};
use rlp::UntrustedRlp;
use machine::EthereumMachine;

/// Number of blocks in an ethash snapshot.
Expand All @@ -38,6 +38,38 @@ const MAX_SNAPSHOT_BLOCKS: u64 = 30000;

const DEFAULT_EIP649_DELAY: u64 = 3_000_000;

/// Ethash specific seal
#[derive(Debug, PartialEq)]
pub struct Seal {
/// Ethash seal mix_hash
pub mix_hash: H256,
/// Ethash seal nonce
pub nonce: H64,
}

impl Seal {
/// Tries to parse rlp as ethash seal.
pub fn parse_seal<T: AsRef<[u8]>>(seal: &[T]) -> Result<Self, Error> {
if seal.len() != 2 {
return Err(BlockError::InvalidSealArity(
Mismatch {
expected: 2,
found: seal.len()
}
).into());
}

let mix_hash = UntrustedRlp::new(seal[0].as_ref()).as_val::<H256>()?;
let nonce = UntrustedRlp::new(seal[1].as_ref()).as_val::<H64>()?;
let seal = Seal {
mix_hash,
nonce,
};

Ok(seal)
}
}

/// Ethash params.
#[derive(Debug, PartialEq)]
pub struct EthashParams {
Expand Down Expand Up @@ -173,13 +205,12 @@ impl Engine<EthereumMachine> for Arc<Ethash> {

/// Additional engine-specific information for the user/developer concerning `header`.
fn extra_info(&self, header: &Header) -> BTreeMap<String, String> {
if header.seal().len() == self.seal_fields(header) {
map![
"nonce".to_owned() => format!("0x{:x}", header.nonce()),
"mixHash".to_owned() => format!("0x{:x}", header.mix_hash())
]
} else {
BTreeMap::default()
match Seal::parse_seal(header.seal()) {
Ok(seal) => map![
"nonce".to_owned() => format!("0x{:x}", seal.nonce),
"mixHash".to_owned() => format!("0x{:x}", seal.mix_hash)
],
_ => BTreeMap::default()
}
}

Expand Down Expand Up @@ -265,14 +296,7 @@ impl Engine<EthereumMachine> for Arc<Ethash> {

fn verify_block_basic(&self, header: &Header) -> Result<(), Error> {
// check the seal fields.
let expected_seal_fields = self.seal_fields(header);
if header.seal().len() != expected_seal_fields {
return Err(From::from(BlockError::InvalidSealArity(
Mismatch { expected: expected_seal_fields, found: header.seal().len() }
)));
}
UntrustedRlp::new(&header.seal()[0]).as_val::<H256>()?;
UntrustedRlp::new(&header.seal()[1]).as_val::<H64>()?;
let seal = Seal::parse_seal(header.seal())?;

// TODO: consider removing these lines.
let min_difficulty = self.ethash_params.minimum_difficulty;
Expand All @@ -282,9 +306,10 @@ impl Engine<EthereumMachine> for Arc<Ethash> {

let difficulty = Ethash::boundary_to_difficulty(&H256(quick_get_difficulty(
&header.bare_hash().0,
header.nonce().low_u64(),
&header.mix_hash().0
seal.nonce.low_u64(),
&seal.mix_hash.0
)));

if &difficulty < header.difficulty() {
return Err(From::from(BlockError::InvalidProofOfWork(OutOfBounds { min: Some(header.difficulty().clone()), max: None, found: difficulty })));
}
Expand All @@ -297,18 +322,20 @@ impl Engine<EthereumMachine> for Arc<Ethash> {
}

fn verify_block_unordered(&self, header: &Header) -> Result<(), Error> {
let expected_seal_fields = self.seal_fields(header);
if header.seal().len() != expected_seal_fields {
return Err(From::from(BlockError::InvalidSealArity(
Mismatch { expected: expected_seal_fields, found: header.seal().len() }
)));
}
let result = self.pow.compute_light(header.number() as u64, &header.bare_hash().0, header.nonce().low_u64());
let seal = Seal::parse_seal(header.seal())?;

let result = self.pow.compute_light(header.number() as u64, &header.bare_hash().0, seal.nonce.low_u64());
let mix = H256(result.mix_hash);
let difficulty = Ethash::boundary_to_difficulty(&H256(result.value));
trace!(target: "miner", "num: {}, seed: {}, h: {}, non: {}, mix: {}, res: {}" , header.number() as u64, H256(slow_hash_block_number(header.number() as u64)), header.bare_hash(), header.nonce().low_u64(), H256(result.mix_hash), H256(result.value));
if mix != header.mix_hash() {
return Err(From::from(BlockError::MismatchedH256SealElement(Mismatch { expected: mix, found: header.mix_hash() })));
trace!(target: "miner", "num: {num}, seed: {seed}, h: {h}, non: {non}, mix: {mix}, res: {res}",
num = header.number() as u64,
seed = H256(slow_hash_block_number(header.number() as u64)),
h = header.bare_hash(),
non = seal.nonce.low_u64(),
mix = H256(result.mix_hash),
res = H256(result.value));
if mix != seal.mix_hash {
return Err(From::from(BlockError::MismatchedH256SealElement(Mismatch { expected: mix, found: seal.mix_hash })));
}
if &difficulty < header.difficulty() {
return Err(From::from(BlockError::InvalidProofOfWork(OutOfBounds { min: Some(header.difficulty().clone()), max: None, found: difficulty })));
Expand Down Expand Up @@ -439,18 +466,6 @@ impl Ethash {
}
}

impl Header {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

glad we can kill these impls

/// Get the nonce field of the header.
pub fn nonce(&self) -> H64 {
rlp::decode(&self.seal()[1])
}

/// Get the mix hash field of the header.
pub fn mix_hash(&self) -> H256 {
rlp::decode(&self.seal()[0])
}
}

fn ecip1017_eras_block_reward(era_rounds: u64, mut reward: U256, block_number:u64) -> (u64, U256) {
let eras = if block_number != 0 && block_number % era_rounds == 0 {
block_number / era_rounds - 1
Expand Down Expand Up @@ -633,7 +648,7 @@ mod tests {
#[test]
fn can_do_seal_unordered_verification_fail() {
let engine = test_spec().engine;
let header: Header = Header::default();
let header = Header::default();

let verify_result = engine.verify_block_unordered(&header);

Expand All @@ -644,6 +659,17 @@ mod tests {
}
}

#[test]
fn can_do_seal_unordered_verification_fail2() {
let engine = test_spec().engine;
let mut header = Header::default();
header.set_seal(vec![vec![], vec![]]);

let verify_result = engine.verify_block_unordered(&header);
// rlp error, shouldn't panic
assert!(verify_result.is_err());
}

#[test]
fn can_do_seal256_verification_fail() {
let engine = test_spec().engine;
Expand Down