fixed parsing ethash seals and verify_block_undordered (#8031)
This commit is contained in:
parent
4af156053f
commit
fc2111bc6f
@ -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.
|
||||
@ -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 {
|
||||
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
@ -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 })));
|
||||
}
|
||||
@ -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 })));
|
||||
@ -439,18 +466,6 @@ impl Ethash {
|
||||
}
|
||||
}
|
||||
|
||||
impl Header {
|
||||
/// 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
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user