diff --git a/ethash/src/compute.rs b/ethash/src/compute.rs index a99a0e3b5..6fcf17cf1 100644 --- a/ethash/src/compute.rs +++ b/ethash/src/compute.rs @@ -202,6 +202,9 @@ impl SeedHashCompute { } } +pub fn slow_get_seedhash(block_number: u64) -> H256 { + SeedHashCompute::resume_compute_seedhash([0u8; 32], 0, block_number / ETHASH_EPOCH_LENGTH) +} #[inline] fn fnv_hash(x: u32, y: u32) -> u32 { diff --git a/ethash/src/lib.rs b/ethash/src/lib.rs index 8fb2c43f6..130882318 100644 --- a/ethash/src/lib.rs +++ b/ethash/src/lib.rs @@ -26,7 +26,7 @@ mod compute; use std::mem; use compute::Light; -pub use compute::{ETHASH_EPOCH_LENGTH, H256, ProofOfWork, SeedHashCompute, quick_get_difficulty}; +pub use compute::{ETHASH_EPOCH_LENGTH, H256, ProofOfWork, SeedHashCompute, quick_get_difficulty, slow_get_seedhash}; use std::sync::Arc; use parking_lot::Mutex; diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index b297f178b..f69570a8e 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -70,7 +70,7 @@ impl Decodable for Block { } } -/// Internal type for a block's common elements. +/// An internal type for a block's common elements. #[derive(Clone)] pub struct ExecutedBlock { base: Block, @@ -206,6 +206,7 @@ pub struct ClosedBlock { block: ExecutedBlock, uncle_bytes: Bytes, last_hashes: Arc, + unclosed_state: State, } /// Just like `ClosedBlock` except that we can't reopen it and it's faster. @@ -347,8 +348,7 @@ impl<'x> OpenBlock<'x> { pub fn close(self) -> ClosedBlock { let mut s = self; - // take a snapshot so the engine's changes can be rolled back. - s.block.state.snapshot(); + let unclosed_state = s.block.state.clone(); s.engine.on_close_block(&mut s.block); s.block.base.header.set_transactions_root(ordered_trie_root(s.block.base.transactions.iter().map(|e| e.rlp_bytes().to_vec()))); @@ -363,6 +363,7 @@ impl<'x> OpenBlock<'x> { block: s.block, uncle_bytes: uncle_bytes, last_hashes: s.last_hashes, + unclosed_state: unclosed_state, } } @@ -370,9 +371,6 @@ impl<'x> OpenBlock<'x> { pub fn close_and_lock(self) -> LockedBlock { let mut s = self; - // take a snapshot so the engine's changes can be rolled back. - s.block.state.snapshot(); - s.engine.on_close_block(&mut s.block); if s.block.base.header.transactions_root().is_zero() || s.block.base.header.transactions_root() == &SHA3_NULL_RLP { s.block.base.header.set_transactions_root(ordered_trie_root(s.block.base.transactions.iter().map(|e| e.rlp_bytes().to_vec()))); @@ -389,11 +387,10 @@ impl<'x> OpenBlock<'x> { s.block.base.header.set_log_bloom(s.block.receipts.iter().fold(LogBloom::zero(), |mut b, r| {b = &b | &r.log_bloom; b})); //TODO: use |= operator s.block.base.header.set_gas_used(s.block.receipts.last().map_or(U256::zero(), |r| r.gas_used)); - ClosedBlock { + LockedBlock { block: s.block, uncle_bytes: uncle_bytes, - last_hashes: s.last_hashes, - }.lock() + } } } @@ -415,16 +412,6 @@ impl ClosedBlock { /// Turn this into a `LockedBlock`, unable to be reopened again. pub fn lock(mut self) -> LockedBlock { - // finalize the changes made by the engine. - self.block.state.clear_snapshot(); - if let Err(e) = self.block.state.commit() { - warn!("Error committing closed block's state: {:?}", e); - } - - // set the state root here, after commit recalculates with the block - // rewards. - self.block.base.header.set_state_root(self.block.state.root().clone()); - LockedBlock { block: self.block, uncle_bytes: self.uncle_bytes, @@ -432,12 +419,12 @@ impl ClosedBlock { } /// Given an engine reference, reopen the `ClosedBlock` into an `OpenBlock`. - pub fn reopen(mut self, engine: &Engine) -> OpenBlock { + pub fn reopen(self, engine: &Engine) -> OpenBlock { // revert rewards (i.e. set state back at last transaction's state). - self.block.state.revert_snapshot(); - + let mut block = self.block; + block.state = self.unclosed_state; OpenBlock { - block: self.block, + block: block, engine: engine, last_hashes: self.last_hashes, } @@ -463,11 +450,11 @@ impl LockedBlock { /// Provide a valid seal in order to turn this into a `SealedBlock`. /// This does check the validity of `seal` with the engine. /// Returns the `ClosedBlock` back again if the seal is no good. - pub fn try_seal(self, engine: &Engine, seal: Vec) -> Result { + pub fn try_seal(self, engine: &Engine, seal: Vec) -> Result { let mut s = self; s.block.base.header.set_seal(seal); match engine.verify_block_seal(&s.block.base.header) { - Err(_) => Err(s), + Err(e) => Err((e, s)), _ => Ok(SealedBlock { block: s.block, uncle_bytes: s.uncle_bytes }), } } diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index acfba3634..982698a50 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use ethash::{quick_get_difficulty, EthashManager, H256 as EH256}; +use ethash::{quick_get_difficulty, slow_get_seedhash, EthashManager, H256 as EH256}; use common::*; use block::*; use spec::CommonParams; @@ -180,6 +180,10 @@ impl Engine for Ethash { fields.state.add_balance(u.author(), &(reward * U256::from(8 + u.number() - current_number) / U256::from(8))); } + // Commit state so that we can actually figure out the state root. + if let Err(e) = fields.state.commit() { + warn!("Encountered error on state commit: {}", e); + } } fn verify_block_basic(&self, header: &Header, _block: Option<&[u8]>) -> result::Result<(), Error> { @@ -229,6 +233,7 @@ impl Engine for Ethash { let result = self.pow.compute_light(header.number() as u64, &Ethash::to_ethash(header.bare_hash()), header.nonce().low_u64()); let mix = Ethash::from_ethash(result.mix_hash); let difficulty = Ethash::boundary_to_difficulty(&Ethash::from_ethash(result.value)); + trace!(target: "miner", "num: {}, seed: {}, h: {}, non: {}, mix: {}, res: {}" , header.number() as u64, Ethash::from_ethash(slow_get_seedhash(header.number() as u64)), header.bare_hash(), header.nonce().low_u64(), Ethash::from_ethash(result.mix_hash), Ethash::from_ethash(result.value)); if mix != header.mix_hash() { return Err(From::from(BlockError::MismatchedH256SealElement(Mismatch { expected: mix, found: header.mix_hash() }))); } diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs index 182234280..a3d35d87e 100644 --- a/ethcore/src/miner/miner.rs +++ b/ethcore/src/miner/miner.rs @@ -864,15 +864,24 @@ impl MinerService for Miner { } fn submit_seal(&self, chain: &MiningBlockChainClient, pow_hash: H256, seal: Vec) -> Result<(), Error> { - let result = if let Some(b) = self.sealing_work.lock().queue.get_used_if(if self.options.enable_resubmission { GetAction::Clone } else { GetAction::Take }, |b| &b.hash() == &pow_hash) { - b.lock().try_seal(&*self.engine, seal).or_else(|_| { - warn!(target: "miner", "Mined solution rejected: Invalid."); - Err(Error::PowInvalid) - }) - } else { - warn!(target: "miner", "Mined solution rejected: Block unknown or out of date."); - Err(Error::PowHashInvalid) - }; + let result = + if let Some(b) = self.sealing_work.lock().queue.get_used_if( + if self.options.enable_resubmission { + GetAction::Clone + } else { + GetAction::Take + }, + |b| &b.hash() == &pow_hash + ) { + trace!(target: "miner", "Sealing block {}={}={} with seal {:?}", pow_hash, b.hash(), b.header().bare_hash(), seal); + b.lock().try_seal(&*self.engine, seal).or_else(|(e, _)| { + warn!(target: "miner", "Mined solution rejected: {}", e); + Err(Error::PowInvalid) + }) + } else { + warn!(target: "miner", "Mined solution rejected: Block unknown or out of date."); + Err(Error::PowHashInvalid) + }; result.and_then(|sealed| { let n = sealed.header().number(); let h = sealed.header().hash(); diff --git a/parity/cli/usage.txt b/parity/cli/usage.txt index a94f55a8d..4c5d3b94b 100644 --- a/parity/cli/usage.txt +++ b/parity/cli/usage.txt @@ -31,8 +31,8 @@ Operating Options: (default: {flag_mode_alarm}). --chain CHAIN Specify the blockchain type. CHAIN may be either a JSON chain specification file or olympic, frontier, - homestead, mainnet, morden, classic or testnet - (default: {flag_chain}). + homestead, mainnet, morden, classic, expanse or + testnet (default: {flag_chain}). -d --db-path PATH Specify the database & configuration directory path (default: {flag_db_path}). --keys-path PATH Specify the path for JSON key files to be found