Make InstantSeal Instant again (#11186)
* Make InstantSeal Instant again * update_sealing if there are transactions in pool after impoerting a block, some line formatting * Apply suggestions from code review Co-Authored-By: Tomasz Drwięga <tomusdrw@users.noreply.github.com> * InstantSeal specific behaviour * introduce engine.should_reseal_on_update, remove InstantSealService * remove unused code * add force param to update_sealing * better docc * even better docs * revert code changes, doc corrections, sort dep * code optimization * fix test * fix bench
This commit is contained in:
		
							parent
							
								
									8adde605e9
								
							
						
					
					
						commit
						887aa62fdb
					
				
							
								
								
									
										1
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										1
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							@ -2156,6 +2156,7 @@ dependencies = [
 | 
			
		||||
name = "instant-seal"
 | 
			
		||||
version = "0.1.0"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "client-traits 0.1.0",
 | 
			
		||||
 "common-types 0.1.0",
 | 
			
		||||
 "engine 0.1.0",
 | 
			
		||||
 "ethcore 1.12.0",
 | 
			
		||||
 | 
			
		||||
@ -146,10 +146,18 @@ pub trait TransactionInfo {
 | 
			
		||||
/// Provides various blockchain information, like block header, chain state etc.
 | 
			
		||||
pub trait BlockChain: ChainInfo + BlockInfo + TransactionInfo {}
 | 
			
		||||
 | 
			
		||||
/// Do we want to force update sealing?
 | 
			
		||||
#[derive(Debug, Copy, Clone, PartialEq)]
 | 
			
		||||
pub enum ForceUpdateSealing {
 | 
			
		||||
	/// Ideally you want to use `No` at all times as `Yes` skips `reseal_required` checks.
 | 
			
		||||
	Yes,
 | 
			
		||||
	/// Don't skip `reseal_required` checks
 | 
			
		||||
	No
 | 
			
		||||
}
 | 
			
		||||
/// Client facilities used by internally sealing Engines.
 | 
			
		||||
pub trait EngineClient: Sync + Send + ChainInfo {
 | 
			
		||||
	/// Make a new block and seal it.
 | 
			
		||||
	fn update_sealing(&self);
 | 
			
		||||
	fn update_sealing(&self, force: ForceUpdateSealing);
 | 
			
		||||
 | 
			
		||||
	/// Submit a seal for a block in the mining queue.
 | 
			
		||||
	fn submit_seal(&self, block_hash: H256, seal: Vec<Bytes>);
 | 
			
		||||
 | 
			
		||||
@ -188,6 +188,14 @@ pub trait Engine: Sync + Send {
 | 
			
		||||
	/// Returns the engine's current sealing state.
 | 
			
		||||
	fn sealing_state(&self) -> SealingState { SealingState::External }
 | 
			
		||||
 | 
			
		||||
	/// Called in `miner.chain_new_blocks` if the engine wishes to `update_sealing`
 | 
			
		||||
	/// after a block was recently sealed.
 | 
			
		||||
	///
 | 
			
		||||
	/// returns false by default
 | 
			
		||||
	fn should_reseal_on_update(&self) -> bool {
 | 
			
		||||
		false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/// Attempt to seal the block internally.
 | 
			
		||||
	///
 | 
			
		||||
	/// If `Some` is returned, then you get a valid seal.
 | 
			
		||||
 | 
			
		||||
@ -40,7 +40,7 @@ use std::sync::{Weak, Arc};
 | 
			
		||||
use std::time::{UNIX_EPOCH, Duration};
 | 
			
		||||
use std::u64;
 | 
			
		||||
 | 
			
		||||
use client_traits::EngineClient;
 | 
			
		||||
use client_traits::{EngineClient, ForceUpdateSealing};
 | 
			
		||||
use engine::{Engine, ConstructedVerifier};
 | 
			
		||||
use block_reward::{self, BlockRewardContract, RewardKind};
 | 
			
		||||
use ethjson;
 | 
			
		||||
@ -1075,7 +1075,7 @@ impl IoHandler<()> for TransitionHandler {
 | 
			
		||||
				self.step.can_propose.store(true, AtomicOrdering::SeqCst);
 | 
			
		||||
				if let Some(ref weak) = *self.client.read() {
 | 
			
		||||
					if let Some(c) = weak.upgrade() {
 | 
			
		||||
						c.update_sealing();
 | 
			
		||||
						c.update_sealing(ForceUpdateSealing::No);
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
@ -1105,7 +1105,7 @@ impl Engine for AuthorityRound {
 | 
			
		||||
		self.step.can_propose.store(true, AtomicOrdering::SeqCst);
 | 
			
		||||
		if let Some(ref weak) = *self.client.read() {
 | 
			
		||||
			if let Some(c) = weak.upgrade() {
 | 
			
		||||
				c.update_sealing();
 | 
			
		||||
				c.update_sealing(ForceUpdateSealing::No);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@ -66,7 +66,7 @@ use std::{
 | 
			
		||||
	time::{self, Instant, Duration, SystemTime, UNIX_EPOCH},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
use client_traits::EngineClient;
 | 
			
		||||
use client_traits::{EngineClient, ForceUpdateSealing};
 | 
			
		||||
use engine::{
 | 
			
		||||
	Engine,
 | 
			
		||||
	signer::EngineSigner,
 | 
			
		||||
@ -780,7 +780,7 @@ impl Engine for Clique {
 | 
			
		||||
		if self.signer.read().is_some() {
 | 
			
		||||
			if let Some(ref weak) = *self.client.read() {
 | 
			
		||||
				if let Some(c) = weak.upgrade() {
 | 
			
		||||
					c.update_sealing();
 | 
			
		||||
					c.update_sealing(ForceUpdateSealing::No);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@ -7,6 +7,7 @@ edition = "2018"
 | 
			
		||||
license = "GPL-3.0"
 | 
			
		||||
 | 
			
		||||
[dependencies]
 | 
			
		||||
client-traits = { path = "../../client-traits" }
 | 
			
		||||
common-types = { path = "../../types" }
 | 
			
		||||
engine = { path = "../../engine" }
 | 
			
		||||
ethjson = { path = "../../../json" }
 | 
			
		||||
 | 
			
		||||
@ -74,6 +74,13 @@ impl Engine for InstantSeal {
 | 
			
		||||
 | 
			
		||||
	fn sealing_state(&self) -> SealingState { SealingState::Ready }
 | 
			
		||||
 | 
			
		||||
	fn should_reseal_on_update(&self) -> bool {
 | 
			
		||||
		// We would like for the miner to `update_sealing` if there are local_pending_transactions
 | 
			
		||||
		// in the pool to prevent transactions sent in parallel from stalling in the transaction
 | 
			
		||||
		// pool. (see #9660)
 | 
			
		||||
		true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn generate_seal(&self, block: &ExecutedBlock, _parent: &Header) -> Seal {
 | 
			
		||||
		if !block.transactions.is_empty() {
 | 
			
		||||
			let block_number = block.header.number();
 | 
			
		||||
 | 
			
		||||
@ -161,7 +161,7 @@ mod tests {
 | 
			
		||||
		ids::BlockId,
 | 
			
		||||
		verification::Unverified,
 | 
			
		||||
	};
 | 
			
		||||
	use client_traits::{BlockChainClient, BlockInfo, ChainInfo, ImportBlock, EngineClient};
 | 
			
		||||
	use client_traits::{BlockChainClient, BlockInfo, ChainInfo, ImportBlock, EngineClient, ForceUpdateSealing};
 | 
			
		||||
	use engine::EpochChange;
 | 
			
		||||
	use ethcore::{
 | 
			
		||||
		miner::{self, MinerService},
 | 
			
		||||
@ -191,24 +191,24 @@ mod tests {
 | 
			
		||||
		let signer = Box::new((tap.clone(), v1, "".into()));
 | 
			
		||||
		client.miner().set_author(miner::Author::Sealer(signer));
 | 
			
		||||
		client.transact_contract(Default::default(), Default::default()).unwrap();
 | 
			
		||||
		EngineClient::update_sealing(&*client);
 | 
			
		||||
		EngineClient::update_sealing(&*client, ForceUpdateSealing::No);
 | 
			
		||||
		assert_eq!(client.chain_info().best_block_number, 0);
 | 
			
		||||
		// Right signer for the first block.
 | 
			
		||||
		let signer = Box::new((tap.clone(), v0, "".into()));
 | 
			
		||||
		client.miner().set_author(miner::Author::Sealer(signer));
 | 
			
		||||
		EngineClient::update_sealing(&*client);
 | 
			
		||||
		EngineClient::update_sealing(&*client, ForceUpdateSealing::No);
 | 
			
		||||
		assert_eq!(client.chain_info().best_block_number, 1);
 | 
			
		||||
		// This time v0 is wrong.
 | 
			
		||||
		client.transact_contract(Default::default(), Default::default()).unwrap();
 | 
			
		||||
		EngineClient::update_sealing(&*client);
 | 
			
		||||
		EngineClient::update_sealing(&*client, ForceUpdateSealing::No);
 | 
			
		||||
		assert_eq!(client.chain_info().best_block_number, 1);
 | 
			
		||||
		let signer = Box::new((tap.clone(), v1, "".into()));
 | 
			
		||||
		client.miner().set_author(miner::Author::Sealer(signer));
 | 
			
		||||
		EngineClient::update_sealing(&*client);
 | 
			
		||||
		EngineClient::update_sealing(&*client, ForceUpdateSealing::No);
 | 
			
		||||
		assert_eq!(client.chain_info().best_block_number, 2);
 | 
			
		||||
		// v1 is still good.
 | 
			
		||||
		client.transact_contract(Default::default(), Default::default()).unwrap();
 | 
			
		||||
		EngineClient::update_sealing(&*client);
 | 
			
		||||
		EngineClient::update_sealing(&*client, ForceUpdateSealing::No);
 | 
			
		||||
		assert_eq!(client.chain_info().best_block_number, 3);
 | 
			
		||||
 | 
			
		||||
		// Check syncing.
 | 
			
		||||
 | 
			
		||||
@ -464,7 +464,7 @@ mod tests {
 | 
			
		||||
		transaction::{Transaction, Action},
 | 
			
		||||
		verification::Unverified,
 | 
			
		||||
	};
 | 
			
		||||
	use client_traits::{BlockInfo, ChainInfo, ImportBlock, EngineClient};
 | 
			
		||||
	use client_traits::{BlockInfo, ChainInfo, ImportBlock, EngineClient, ForceUpdateSealing};
 | 
			
		||||
	use engine::{EpochChange, Proof};
 | 
			
		||||
	use ethcore::{
 | 
			
		||||
		miner::{self, MinerService},
 | 
			
		||||
@ -513,7 +513,7 @@ mod tests {
 | 
			
		||||
			data: "bfc708a000000000000000000000000082a978b3f5962a5b0957d9ee9eef472ee55b42f1".from_hex().unwrap(),
 | 
			
		||||
		}.sign(&s0, Some(chain_id));
 | 
			
		||||
		client.miner().import_own_transaction(client.as_ref(), tx.into()).unwrap();
 | 
			
		||||
		EngineClient::update_sealing(&*client);
 | 
			
		||||
		EngineClient::update_sealing(&*client, ForceUpdateSealing::No);
 | 
			
		||||
		assert_eq!(client.chain_info().best_block_number, 1);
 | 
			
		||||
		// Add "1" validator back in.
 | 
			
		||||
		let tx = Transaction {
 | 
			
		||||
@ -525,14 +525,14 @@ mod tests {
 | 
			
		||||
			data: "4d238c8e00000000000000000000000082a978b3f5962a5b0957d9ee9eef472ee55b42f1".from_hex().unwrap(),
 | 
			
		||||
		}.sign(&s0, Some(chain_id));
 | 
			
		||||
		client.miner().import_own_transaction(client.as_ref(), tx.into()).unwrap();
 | 
			
		||||
		EngineClient::update_sealing(&*client);
 | 
			
		||||
		EngineClient::update_sealing(&*client, ForceUpdateSealing::No);
 | 
			
		||||
		// The transaction is not yet included so still unable to seal.
 | 
			
		||||
		assert_eq!(client.chain_info().best_block_number, 1);
 | 
			
		||||
 | 
			
		||||
		// Switch to the validator that is still there.
 | 
			
		||||
		let signer = Box::new((tap.clone(), v0, "".into()));
 | 
			
		||||
		client.miner().set_author(miner::Author::Sealer(signer));
 | 
			
		||||
		EngineClient::update_sealing(&*client);
 | 
			
		||||
		EngineClient::update_sealing(&*client, ForceUpdateSealing::No);
 | 
			
		||||
		assert_eq!(client.chain_info().best_block_number, 2);
 | 
			
		||||
		// Switch back to the added validator, since the state is updated.
 | 
			
		||||
		let signer = Box::new((tap.clone(), v1, "".into()));
 | 
			
		||||
@ -546,7 +546,7 @@ mod tests {
 | 
			
		||||
			data: Vec::new(),
 | 
			
		||||
		}.sign(&s0, Some(chain_id));
 | 
			
		||||
		client.miner().import_own_transaction(client.as_ref(), tx.into()).unwrap();
 | 
			
		||||
		EngineClient::update_sealing(&*client);
 | 
			
		||||
		EngineClient::update_sealing(&*client, ForceUpdateSealing::No);
 | 
			
		||||
		// Able to seal again.
 | 
			
		||||
		assert_eq!(client.chain_info().best_block_number, 3);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -48,6 +48,7 @@ use self::header_chain::{AncestryIter, HeaderChain, HardcodedSync};
 | 
			
		||||
use cache::Cache;
 | 
			
		||||
 | 
			
		||||
pub use self::service::Service;
 | 
			
		||||
use client_traits::ForceUpdateSealing;
 | 
			
		||||
 | 
			
		||||
mod header_chain;
 | 
			
		||||
mod service;
 | 
			
		||||
@ -626,7 +627,7 @@ impl<T: ChainDataFetcher> client_traits::ChainInfo for Client<T> {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<T: ChainDataFetcher> client_traits::EngineClient for Client<T> {
 | 
			
		||||
	fn update_sealing(&self) { }
 | 
			
		||||
	fn update_sealing(&self, _force: ForceUpdateSealing) {}
 | 
			
		||||
	fn submit_seal(&self, _block_hash: H256, _seal: Vec<Vec<u8>>) { }
 | 
			
		||||
	fn broadcast_consensus_message(&self, _message: Vec<u8>) { }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -78,7 +78,8 @@ use client_traits::{
 | 
			
		||||
	StateClient,
 | 
			
		||||
	StateOrBlock,
 | 
			
		||||
	Tick,
 | 
			
		||||
	TransactionInfo
 | 
			
		||||
	TransactionInfo,
 | 
			
		||||
	ForceUpdateSealing
 | 
			
		||||
};
 | 
			
		||||
use db::{keys::BlockDetails, Readable, Writable};
 | 
			
		||||
use engine::Engine;
 | 
			
		||||
@ -2383,7 +2384,9 @@ impl ImportSealedBlock for Client {
 | 
			
		||||
		let raw = block.rlp_bytes();
 | 
			
		||||
		let header = block.header.clone();
 | 
			
		||||
		let hash = header.hash();
 | 
			
		||||
		self.notify(|n| n.block_pre_import(&raw, &hash, header.difficulty()));
 | 
			
		||||
		self.notify(|n| {
 | 
			
		||||
			n.block_pre_import(&raw, &hash, header.difficulty())
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
		let route = {
 | 
			
		||||
			// Do a super duper basic verification to detect potential bugs
 | 
			
		||||
@ -2471,19 +2474,22 @@ impl ::miner::TransactionVerifierClient for Client {}
 | 
			
		||||
impl ::miner::BlockChainClient for Client {}
 | 
			
		||||
 | 
			
		||||
impl client_traits::EngineClient for Client {
 | 
			
		||||
	fn update_sealing(&self) {
 | 
			
		||||
		self.importer.miner.update_sealing(self)
 | 
			
		||||
	fn update_sealing(&self, force: ForceUpdateSealing) {
 | 
			
		||||
		self.importer.miner.update_sealing(self, force)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn submit_seal(&self, block_hash: H256, seal: Vec<Bytes>) {
 | 
			
		||||
		let import = self.importer.miner.submit_seal(block_hash, seal).and_then(|block| self.import_sealed_block(block));
 | 
			
		||||
		let import = self.importer.miner.submit_seal(block_hash, seal)
 | 
			
		||||
			.and_then(|block| self.import_sealed_block(block));
 | 
			
		||||
		if let Err(err) = import {
 | 
			
		||||
			warn!(target: "poa", "Wrong internal seal submission! {:?}", err);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn broadcast_consensus_message(&self, message: Bytes) {
 | 
			
		||||
		self.notify(|notify| notify.broadcast(ChainMessageType::Consensus(message.clone())));
 | 
			
		||||
		self.notify(|notify| {
 | 
			
		||||
			notify.broadcast(ChainMessageType::Consensus(message.clone()))
 | 
			
		||||
		});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn epoch_transition_for(&self, parent_hash: H256) -> Option<EpochTransition> {
 | 
			
		||||
@ -2622,13 +2628,21 @@ impl ImportExportBlocks for Client {
 | 
			
		||||
			if i % 10000 == 0 {
 | 
			
		||||
				info!("#{}", i);
 | 
			
		||||
			}
 | 
			
		||||
			let b = self.block(BlockId::Number(i)).ok_or("Error exporting incomplete chain")?.into_inner();
 | 
			
		||||
			let b = self.block(BlockId::Number(i))
 | 
			
		||||
				.ok_or("Error exporting incomplete chain")?
 | 
			
		||||
				.into_inner();
 | 
			
		||||
			match format {
 | 
			
		||||
				DataFormat::Binary => {
 | 
			
		||||
					out.write(&b).map_err(|e| format!("Couldn't write to stream. Cause: {}", e))?;
 | 
			
		||||
					out.write(&b)
 | 
			
		||||
						.map_err(|e| {
 | 
			
		||||
							format!("Couldn't write to stream. Cause: {}", e)
 | 
			
		||||
						})?;
 | 
			
		||||
				}
 | 
			
		||||
				DataFormat::Hex => {
 | 
			
		||||
					out.write_fmt(format_args!("{}\n", b.pretty())).map_err(|e| format!("Couldn't write to stream. Cause: {}", e))?;
 | 
			
		||||
					out.write_fmt(format_args!("{}\n", b.pretty()))
 | 
			
		||||
						.map_err(|e| {
 | 
			
		||||
							format!("Couldn't write to stream. Cause: {}", e)
 | 
			
		||||
						})?;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
@ -2648,7 +2662,10 @@ impl ImportExportBlocks for Client {
 | 
			
		||||
		let format = match format {
 | 
			
		||||
			Some(format) => format,
 | 
			
		||||
			None => {
 | 
			
		||||
				first_read = source.read(&mut first_bytes).map_err(|_| "Error reading from the file/stream.")?;
 | 
			
		||||
				first_read = source.read(&mut first_bytes)
 | 
			
		||||
					.map_err(|_| {
 | 
			
		||||
						"Error reading from the file/stream."
 | 
			
		||||
					})?;
 | 
			
		||||
				match first_bytes[0] {
 | 
			
		||||
					0xf9 => DataFormat::Binary,
 | 
			
		||||
					_ => DataFormat::Hex,
 | 
			
		||||
@ -2659,7 +2676,9 @@ impl ImportExportBlocks for Client {
 | 
			
		||||
		let do_import = |bytes: Vec<u8>| {
 | 
			
		||||
			let block = Unverified::from_rlp(bytes).map_err(|_| "Invalid block rlp")?;
 | 
			
		||||
			let number = block.header.number();
 | 
			
		||||
			while self.queue_info().is_full() { std::thread::sleep(Duration::from_secs(1)); }
 | 
			
		||||
			while self.queue_info().is_full() {
 | 
			
		||||
				std::thread::sleep(Duration::from_secs(1));
 | 
			
		||||
			}
 | 
			
		||||
			match self.import_block(block) {
 | 
			
		||||
				Err(EthcoreError::Import(ImportError::AlreadyInChain)) => {
 | 
			
		||||
					trace!("Skipping block #{}: already in chain.", number);
 | 
			
		||||
@ -2680,33 +2699,45 @@ impl ImportExportBlocks for Client {
 | 
			
		||||
					} else {
 | 
			
		||||
						let mut bytes = vec![0; READAHEAD_BYTES];
 | 
			
		||||
						let n = source.read(&mut bytes)
 | 
			
		||||
							.map_err(|err| format!("Error reading from the file/stream: {:?}", err))?;
 | 
			
		||||
							.map_err(|err| {
 | 
			
		||||
								format!("Error reading from the file/stream: {:?}", err)
 | 
			
		||||
							})?;
 | 
			
		||||
						(bytes, n)
 | 
			
		||||
					};
 | 
			
		||||
					if n == 0 { break; }
 | 
			
		||||
					first_read = 0;
 | 
			
		||||
					let s = PayloadInfo::from(&bytes)
 | 
			
		||||
						.map_err(|e| format!("Invalid RLP in the file/stream: {:?}", e))?.total();
 | 
			
		||||
						.map_err(|e| {
 | 
			
		||||
							format!("Invalid RLP in the file/stream: {:?}", e)
 | 
			
		||||
						})?.total();
 | 
			
		||||
					bytes.resize(s, 0);
 | 
			
		||||
					source.read_exact(&mut bytes[n..])
 | 
			
		||||
						.map_err(|err| format!("Error reading from the file/stream: {:?}", err))?;
 | 
			
		||||
						.map_err(|err| {
 | 
			
		||||
							format!("Error reading from the file/stream: {:?}", err)
 | 
			
		||||
						})?;
 | 
			
		||||
					do_import(bytes)?;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			DataFormat::Hex => {
 | 
			
		||||
				for line in BufReader::new(source).lines() {
 | 
			
		||||
					let s = line
 | 
			
		||||
						.map_err(|err| format!("Error reading from the file/stream: {:?}", err))?;
 | 
			
		||||
						.map_err(|err| {
 | 
			
		||||
							format!("Error reading from the file/stream: {:?}", err)
 | 
			
		||||
						})?;
 | 
			
		||||
					let s = if first_read > 0 {
 | 
			
		||||
						from_utf8(&first_bytes)
 | 
			
		||||
							.map_err(|err| format!("Invalid UTF-8: {:?}", err))?
 | 
			
		||||
							.map_err(|err| {
 | 
			
		||||
								format!("Invalid UTF-8: {:?}", err)
 | 
			
		||||
							})?
 | 
			
		||||
							.to_owned() + &(s[..])
 | 
			
		||||
					} else {
 | 
			
		||||
						s
 | 
			
		||||
					};
 | 
			
		||||
					first_read = 0;
 | 
			
		||||
					let bytes = s.from_hex()
 | 
			
		||||
						.map_err(|err| format!("Invalid hex in file/stream: {:?}", err))?;
 | 
			
		||||
						.map_err(|err| {
 | 
			
		||||
							format!("Invalid hex in file/stream: {:?}", err)
 | 
			
		||||
						})?;
 | 
			
		||||
					do_import(bytes)?;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
@ -58,7 +58,7 @@ use using_queue::{UsingQueue, GetAction};
 | 
			
		||||
 | 
			
		||||
use block::{ClosedBlock, SealedBlock};
 | 
			
		||||
use client::{BlockProducer, SealedBlockImporter, Client};
 | 
			
		||||
use client_traits::{BlockChain, ChainInfo, EngineClient, Nonce, TransactionInfo};
 | 
			
		||||
use client_traits::{BlockChain, ChainInfo, Nonce, TransactionInfo, EngineClient, ForceUpdateSealing};
 | 
			
		||||
use engine::{Engine, signer::EngineSigner};
 | 
			
		||||
use machine::executive::contract_address;
 | 
			
		||||
use spec::Spec;
 | 
			
		||||
@ -294,6 +294,7 @@ impl Miner {
 | 
			
		||||
		let tx_queue_strategy = options.tx_queue_strategy;
 | 
			
		||||
		let nonce_cache_size = cmp::max(4096, limits.max_count / 4);
 | 
			
		||||
		let refuse_service_transactions = options.refuse_service_transactions;
 | 
			
		||||
		let engine = spec.engine.clone();
 | 
			
		||||
 | 
			
		||||
		Miner {
 | 
			
		||||
			sealing: Mutex::new(SealingWork {
 | 
			
		||||
@ -312,7 +313,7 @@ impl Miner {
 | 
			
		||||
			options,
 | 
			
		||||
			transaction_queue: Arc::new(TransactionQueue::new(limits, verifier_options, tx_queue_strategy)),
 | 
			
		||||
			accounts: Arc::new(accounts),
 | 
			
		||||
			engine: spec.engine.clone(),
 | 
			
		||||
			engine,
 | 
			
		||||
			io_channel: RwLock::new(None),
 | 
			
		||||
			service_transaction_checker: if refuse_service_transactions {
 | 
			
		||||
				None
 | 
			
		||||
@ -865,12 +866,12 @@ impl Miner {
 | 
			
		||||
		match self.engine.sealing_state() {
 | 
			
		||||
			SealingState::Ready => {
 | 
			
		||||
				self.maybe_enable_sealing();
 | 
			
		||||
				self.update_sealing(chain)
 | 
			
		||||
				self.update_sealing(chain, ForceUpdateSealing::No);
 | 
			
		||||
			}
 | 
			
		||||
			SealingState::External => {
 | 
			
		||||
				// this calls `maybe_enable_sealing()`
 | 
			
		||||
				if self.prepare_pending_block(chain) == BlockPreparationStatus::NotPrepared {
 | 
			
		||||
					self.update_sealing(chain)
 | 
			
		||||
					self.update_sealing(chain, ForceUpdateSealing::No);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			SealingState::NotReady => { self.maybe_enable_sealing(); },
 | 
			
		||||
@ -1263,14 +1264,16 @@ impl miner::MinerService for Miner {
 | 
			
		||||
 | 
			
		||||
	/// Update sealing if required.
 | 
			
		||||
	/// Prepare the block and work if the Engine does not seal internally.
 | 
			
		||||
	fn update_sealing<C>(&self, chain: &C) where
 | 
			
		||||
	fn update_sealing<C>(&self, chain: &C, force: ForceUpdateSealing) where
 | 
			
		||||
		C: BlockChain + CallContract + BlockProducer + SealedBlockImporter + Nonce + Sync,
 | 
			
		||||
	{
 | 
			
		||||
		trace!(target: "miner", "update_sealing");
 | 
			
		||||
 | 
			
		||||
		// Do nothing if reseal is not required,
 | 
			
		||||
		// Do nothing if we don't want to force update_sealing and reseal is not required.
 | 
			
		||||
		// but note that `requires_reseal` updates internal state.
 | 
			
		||||
		if !self.requires_reseal(chain.chain_info().best_block_number) {
 | 
			
		||||
		if force == ForceUpdateSealing::No &&
 | 
			
		||||
			!self.requires_reseal(chain.chain_info().best_block_number)
 | 
			
		||||
		{
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@ -1305,13 +1308,14 @@ impl miner::MinerService for Miner {
 | 
			
		||||
				if self.seal_and_import_block_internally(chain, block) {
 | 
			
		||||
					trace!(target: "miner", "update_sealing: imported internally sealed block");
 | 
			
		||||
				}
 | 
			
		||||
				return
 | 
			
		||||
			},
 | 
			
		||||
			SealingState::NotReady => unreachable!("We returned right after sealing_state was computed. qed."),
 | 
			
		||||
			SealingState::External => {
 | 
			
		||||
				trace!(target: "miner", "update_sealing: engine does not seal internally, preparing work");
 | 
			
		||||
				self.prepare_work(block, original_work_hash)
 | 
			
		||||
				self.prepare_work(block, original_work_hash);
 | 
			
		||||
			},
 | 
			
		||||
		}
 | 
			
		||||
		};
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn is_currently_sealing(&self) -> bool {
 | 
			
		||||
@ -1423,7 +1427,7 @@ impl miner::MinerService for Miner {
 | 
			
		||||
				// | NOTE Code below requires sealing locks.                                |
 | 
			
		||||
				// | Make sure to release the locks before calling that method.             |
 | 
			
		||||
				// --------------------------------------------------------------------------
 | 
			
		||||
				self.update_sealing(chain);
 | 
			
		||||
				self.update_sealing(chain, ForceUpdateSealing::No);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@ -1441,7 +1445,6 @@ impl miner::MinerService for Miner {
 | 
			
		||||
				let engine = self.engine.clone();
 | 
			
		||||
				let accounts = self.accounts.clone();
 | 
			
		||||
				let service_transaction_checker = self.service_transaction_checker.clone();
 | 
			
		||||
 | 
			
		||||
				let cull = move |chain: &Client| {
 | 
			
		||||
					let client = PoolClient::new(
 | 
			
		||||
						chain,
 | 
			
		||||
@ -1451,8 +1454,9 @@ impl miner::MinerService for Miner {
 | 
			
		||||
						service_transaction_checker.as_ref(),
 | 
			
		||||
					);
 | 
			
		||||
					queue.cull(client);
 | 
			
		||||
					if is_internal_import {
 | 
			
		||||
						chain.update_sealing();
 | 
			
		||||
					if engine.should_reseal_on_update() {
 | 
			
		||||
						// force update_sealing here to skip `reseal_required` checks
 | 
			
		||||
						chain.update_sealing(ForceUpdateSealing::Yes);
 | 
			
		||||
					}
 | 
			
		||||
				};
 | 
			
		||||
 | 
			
		||||
@ -1461,8 +1465,9 @@ impl miner::MinerService for Miner {
 | 
			
		||||
				}
 | 
			
		||||
			} else {
 | 
			
		||||
				self.transaction_queue.cull(client);
 | 
			
		||||
				if is_internal_import {
 | 
			
		||||
					self.update_sealing(chain);
 | 
			
		||||
				if self.engine.should_reseal_on_update() {
 | 
			
		||||
					// force update_sealing here to skip `reseal_required` checks
 | 
			
		||||
					self.update_sealing(chain, ForceUpdateSealing::Yes);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
@ -1793,7 +1798,7 @@ mod tests {
 | 
			
		||||
		).pop().unwrap();
 | 
			
		||||
		assert_eq!(import.unwrap(), ());
 | 
			
		||||
 | 
			
		||||
		miner.update_sealing(&*client);
 | 
			
		||||
		miner.update_sealing(&*client, ForceUpdateSealing::No);
 | 
			
		||||
		client.flush_queue();
 | 
			
		||||
		assert!(miner.pending_block(0).is_none());
 | 
			
		||||
		assert_eq!(client.chain_info().best_block_number, 3 as BlockNumber);
 | 
			
		||||
@ -1803,7 +1808,7 @@ mod tests {
 | 
			
		||||
			PendingTransaction::new(transaction_with_chain_id(spec.chain_id()).into(), None)
 | 
			
		||||
		).is_ok());
 | 
			
		||||
 | 
			
		||||
		miner.update_sealing(&*client);
 | 
			
		||||
		miner.update_sealing(&*client, ForceUpdateSealing::No);
 | 
			
		||||
		client.flush_queue();
 | 
			
		||||
		assert!(miner.pending_block(0).is_none());
 | 
			
		||||
		assert_eq!(client.chain_info().best_block_number, 4 as BlockNumber);
 | 
			
		||||
@ -1831,7 +1836,7 @@ mod tests {
 | 
			
		||||
		let miner = Miner::new_for_tests(&spec, None);
 | 
			
		||||
 | 
			
		||||
		let client = generate_dummy_client(2);
 | 
			
		||||
		miner.update_sealing(&*client);
 | 
			
		||||
		miner.update_sealing(&*client, ForceUpdateSealing::No);
 | 
			
		||||
 | 
			
		||||
		assert!(miner.is_currently_sealing());
 | 
			
		||||
	}
 | 
			
		||||
@ -1842,7 +1847,7 @@ mod tests {
 | 
			
		||||
		let miner = Miner::new_for_tests(&spec, None);
 | 
			
		||||
 | 
			
		||||
		let client = generate_dummy_client(2);
 | 
			
		||||
		miner.update_sealing(&*client);
 | 
			
		||||
		miner.update_sealing(&*client, ForceUpdateSealing::No);
 | 
			
		||||
 | 
			
		||||
		assert!(!miner.is_currently_sealing());
 | 
			
		||||
	}
 | 
			
		||||
@ -1853,7 +1858,7 @@ mod tests {
 | 
			
		||||
		let miner = Miner::new_for_tests(&spec, None);
 | 
			
		||||
 | 
			
		||||
		let client = generate_dummy_client(2);
 | 
			
		||||
		miner.update_sealing(&*client);
 | 
			
		||||
		miner.update_sealing(&*client, ForceUpdateSealing::No);
 | 
			
		||||
 | 
			
		||||
		assert!(!miner.is_currently_sealing());
 | 
			
		||||
	}
 | 
			
		||||
@ -1872,7 +1877,7 @@ mod tests {
 | 
			
		||||
		miner.add_work_listener(Box::new(DummyNotifyWork));
 | 
			
		||||
 | 
			
		||||
		let client = generate_dummy_client(2);
 | 
			
		||||
		miner.update_sealing(&*client);
 | 
			
		||||
		miner.update_sealing(&*client, ForceUpdateSealing::No);
 | 
			
		||||
 | 
			
		||||
		assert!(miner.is_currently_sealing());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@ -47,7 +47,7 @@ use types::{
 | 
			
		||||
 | 
			
		||||
use call_contract::CallContract;
 | 
			
		||||
use registrar::RegistrarClient;
 | 
			
		||||
use client_traits::{BlockChain, ChainInfo, AccountData, Nonce, ScheduleInfo};
 | 
			
		||||
use client_traits::{BlockChain, ChainInfo, AccountData, Nonce, ScheduleInfo, ForceUpdateSealing};
 | 
			
		||||
use account_state::state::StateInfo;
 | 
			
		||||
 | 
			
		||||
use crate::{
 | 
			
		||||
@ -87,7 +87,7 @@ pub trait MinerService : Send + Sync {
 | 
			
		||||
		where C: BlockChain + CallContract + BlockProducer + SealedBlockImporter + Nonce + Sync;
 | 
			
		||||
 | 
			
		||||
	/// Update current pending block
 | 
			
		||||
	fn update_sealing<C>(&self, chain: &C)
 | 
			
		||||
	fn update_sealing<C>(&self, chain: &C, force: ForceUpdateSealing)
 | 
			
		||||
		where C: BlockChain + CallContract + BlockProducer + SealedBlockImporter + Nonce + Sync;
 | 
			
		||||
 | 
			
		||||
	// Notifications
 | 
			
		||||
 | 
			
		||||
@ -72,7 +72,7 @@ use client::{
 | 
			
		||||
use client_traits::{
 | 
			
		||||
	BlockInfo, Nonce, Balance, ChainInfo, TransactionInfo, BlockChainClient, ImportBlock,
 | 
			
		||||
	AccountData, BlockChain, IoClient, BadBlocks, ScheduleInfo, StateClient, ProvingBlockChainClient,
 | 
			
		||||
	StateOrBlock
 | 
			
		||||
	StateOrBlock, ForceUpdateSealing
 | 
			
		||||
};
 | 
			
		||||
use engine::Engine;
 | 
			
		||||
use machine::executed::Executed;
 | 
			
		||||
@ -963,8 +963,8 @@ impl ProvingBlockChainClient for TestBlockChainClient {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl client_traits::EngineClient for TestBlockChainClient {
 | 
			
		||||
	fn update_sealing(&self) {
 | 
			
		||||
		self.miner.update_sealing(self)
 | 
			
		||||
	fn update_sealing(&self, force: ForceUpdateSealing)  {
 | 
			
		||||
		self.miner.update_sealing(self, force)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn submit_seal(&self, block_hash: H256, seal: Vec<Bytes>) {
 | 
			
		||||
 | 
			
		||||
@ -105,11 +105,17 @@ impl TransactionsPoolNotifier {
 | 
			
		||||
				.map(|(hash, _)| hash)
 | 
			
		||||
				.collect()
 | 
			
		||||
		);
 | 
			
		||||
		self.pending_listeners.retain(|listener| listener.unbounded_send(to_pending_send.clone()).is_ok());
 | 
			
		||||
		self.pending_listeners.retain(|listener| {
 | 
			
		||||
			listener.unbounded_send(to_pending_send.clone()).is_ok()
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
		let to_full_send = Arc::new(std::mem::replace(&mut self.tx_statuses, Vec::new()));
 | 
			
		||||
		let to_full_send = Arc::new(
 | 
			
		||||
			std::mem::replace(&mut self.tx_statuses, Vec::new())
 | 
			
		||||
		);
 | 
			
		||||
		self.full_listeners
 | 
			
		||||
			.retain(|listener| listener.unbounded_send(to_full_send.clone()).is_ok());
 | 
			
		||||
			.retain(|listener| {
 | 
			
		||||
				listener.unbounded_send(to_full_send.clone()).is_ok()
 | 
			
		||||
			});
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -20,7 +20,7 @@ use std::sync::Arc;
 | 
			
		||||
use std::collections::{BTreeMap, BTreeSet, HashMap};
 | 
			
		||||
 | 
			
		||||
use bytes::Bytes;
 | 
			
		||||
use client_traits::{Nonce, StateClient};
 | 
			
		||||
use client_traits::{Nonce, StateClient, ForceUpdateSealing};
 | 
			
		||||
use engine::{Engine, signer::EngineSigner};
 | 
			
		||||
use ethcore::block::SealedBlock;
 | 
			
		||||
use ethcore::client::{PrepareOpenBlock, EngineInfo};
 | 
			
		||||
@ -192,7 +192,7 @@ impl MinerService for TestMinerService {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/// New chain head event. Restart mining operation.
 | 
			
		||||
	fn update_sealing<C>(&self, _chain: &C) {
 | 
			
		||||
	fn update_sealing<C>(&self, _chain: &C, _force: ForceUpdateSealing) {
 | 
			
		||||
		unimplemented!();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user