From 4a95a09b32f7a97e4804b9e3a95e2bc839a644d5 Mon Sep 17 00:00:00 2001 From: Seun Date: Mon, 21 Oct 2019 20:08:58 +0100 Subject: [PATCH 01/13] Make InstantSeal Instant again --- ethcore/src/miner/miner.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs index 3d55f88eea1..095062e8352 100644 --- a/ethcore/src/miner/miner.rs +++ b/ethcore/src/miner/miner.rs @@ -284,7 +284,7 @@ impl Miner { /// Creates new instance of miner Arc. pub fn new( - options: MinerOptions, + mut options: MinerOptions, gas_pricer: GasPricer, spec: &Spec, accounts: A, @@ -294,6 +294,14 @@ 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(); + + // For the InstantSeal engine, set the reseal_{max & min}_period to zero + // This allows blocks to be sealed Instantly ;) + if engine.name() == "InstantSeal" { + options.reseal_max_period = Duration::from_secs(0); + options.reseal_min_period = Duration::from_secs(0); + } Miner { sealing: Mutex::new(SealingWork { @@ -312,7 +320,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 From 078de7efce0d9a9dbc2fccb937ec021e164e185c Mon Sep 17 00:00:00 2001 From: Seun Date: Fri, 25 Oct 2019 00:13:24 +0100 Subject: [PATCH 02/13] update_sealing if there are transactions in pool after impoerting a block, some line formatting --- Cargo.lock | 1 + ethcore/client-traits/src/lib.rs | 2 +- ethcore/engines/instant-seal/Cargo.toml | 1 + ethcore/engines/instant-seal/src/lib.rs | 6 +++ ethcore/light/src/client/mod.rs | 2 +- ethcore/src/client/client.rs | 60 ++++++++++++++++++------- ethcore/src/miner/miner.rs | 49 ++++++++++---------- ethcore/src/miner/mod.rs | 2 +- ethcore/src/test_helpers/test_client.rs | 2 +- miner/src/pool/listener.rs | 12 +++-- 10 files changed, 92 insertions(+), 45 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b00c3553702..2c66ebf0cc4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2128,6 +2128,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" 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", diff --git a/ethcore/client-traits/src/lib.rs b/ethcore/client-traits/src/lib.rs index f592ef6cfe9..353f96453e8 100644 --- a/ethcore/client-traits/src/lib.rs +++ b/ethcore/client-traits/src/lib.rs @@ -149,7 +149,7 @@ pub trait BlockChain: ChainInfo + BlockInfo + TransactionInfo {} /// 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) -> bool; /// Submit a seal for a block in the mining queue. fn submit_seal(&self, block_hash: H256, seal: Vec); diff --git a/ethcore/engines/instant-seal/Cargo.toml b/ethcore/engines/instant-seal/Cargo.toml index afb56ea524f..cc59f1793b1 100644 --- a/ethcore/engines/instant-seal/Cargo.toml +++ b/ethcore/engines/instant-seal/Cargo.toml @@ -10,6 +10,7 @@ license = "GPL-3.0" common-types = { path = "../../types" } engine = { path = "../../engine" } ethjson = { path = "../../../json" } +client-traits = { path = "../../client-traits" } ethereum-types = "0.8.0" keccak-hash = "0.4.0" machine = { path = "../../machine" } diff --git a/ethcore/engines/instant-seal/src/lib.rs b/ethcore/engines/instant-seal/src/lib.rs index 9626be86b30..b90859d110a 100644 --- a/ethcore/engines/instant-seal/src/lib.rs +++ b/ethcore/engines/instant-seal/src/lib.rs @@ -27,6 +27,8 @@ use common_types::{ }; use engine::Engine; use ethjson; +use std::sync::Weak; +use client_traits::EngineClient; use machine::{ ExecutedBlock, Machine @@ -74,6 +76,10 @@ impl Engine for InstantSeal { fn sealing_state(&self) -> SealingState { SealingState::Ready } + fn register_client(&self, _client: Weak) { + + } + fn generate_seal(&self, block: &ExecutedBlock, _parent: &Header) -> Seal { if !block.transactions.is_empty() { let block_number = block.header.number(); diff --git a/ethcore/light/src/client/mod.rs b/ethcore/light/src/client/mod.rs index 0339cfe1b10..8df5c8e03a6 100644 --- a/ethcore/light/src/client/mod.rs +++ b/ethcore/light/src/client/mod.rs @@ -626,7 +626,7 @@ impl client_traits::ChainInfo for Client { } impl client_traits::EngineClient for Client { - fn update_sealing(&self) { } + fn update_sealing(&self) -> bool { false } fn submit_seal(&self, _block_hash: H256, _seal: Vec>) { } fn broadcast_consensus_message(&self, _message: Vec) { } diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 795a0e6deaf..a23fe050329 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -2367,7 +2367,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 @@ -2455,19 +2457,22 @@ impl ::miner::TransactionVerifierClient for Client {} impl ::miner::BlockChainClient for Client {} impl client_traits::EngineClient for Client { - fn update_sealing(&self) { + fn update_sealing(&self) -> bool { self.importer.miner.update_sealing(self) } fn submit_seal(&self, block_hash: H256, seal: Vec) { - 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 { @@ -2593,13 +2598,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) + })?; } } } @@ -2619,7 +2632,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, @@ -2630,7 +2646,9 @@ impl ImportExportBlocks for Client { let do_import = |bytes: Vec| { 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); @@ -2651,33 +2669,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)?; } } diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs index 095062e8352..abac053390d 100644 --- a/ethcore/src/miner/miner.rs +++ b/ethcore/src/miner/miner.rs @@ -284,7 +284,7 @@ impl Miner { /// Creates new instance of miner Arc. pub fn new( - mut options: MinerOptions, + options: MinerOptions, gas_pricer: GasPricer, spec: &Spec, accounts: A, @@ -296,13 +296,6 @@ impl Miner { let refuse_service_transactions = options.refuse_service_transactions; let engine = spec.engine.clone(); - // For the InstantSeal engine, set the reseal_{max & min}_period to zero - // This allows blocks to be sealed Instantly ;) - if engine.name() == "InstantSeal" { - options.reseal_max_period = Duration::from_secs(0); - options.reseal_min_period = Duration::from_secs(0); - } - Miner { sealing: Mutex::new(SealingWork { queue: UsingQueue::new(options.work_queue_size), @@ -873,12 +866,12 @@ impl Miner { match self.engine.sealing_state() { SealingState::Ready => { self.maybe_enable_sealing(); - self.update_sealing(chain) + self.update_sealing(chain); } SealingState::External => { // this calls `maybe_enable_sealing()` if self.prepare_pending_block(chain) == BlockPreparationStatus::NotPrepared { - self.update_sealing(chain) + self.update_sealing(chain); } } SealingState::NotReady => { self.maybe_enable_sealing(); }, @@ -1271,7 +1264,7 @@ impl miner::MinerService for Miner { /// Update sealing if required. /// Prepare the block and work if the Engine does not seal internally. - fn update_sealing(&self, chain: &C) where + fn update_sealing(&self, chain: &C) -> bool where C: BlockChain + CallContract + BlockProducer + SealedBlockImporter + Nonce + Sync, { trace!(target: "miner", "update_sealing"); @@ -1279,12 +1272,12 @@ impl miner::MinerService for Miner { // Do nothing if reseal is not required, // but note that `requires_reseal` updates internal state. if !self.requires_reseal(chain.chain_info().best_block_number) { - return; + return false; } let sealing_state = self.engine.sealing_state(); if sealing_state == SealingState::NotReady { - return; + return false; } // -------------------------------------------------------------------------- @@ -1294,7 +1287,7 @@ impl miner::MinerService for Miner { trace!(target: "miner", "update_sealing: preparing a block"); let (block, original_work_hash) = match self.prepare_block(chain) { Some((block, original_work_hash)) => (block, original_work_hash), - None => return, + None => return false, }; // refuse to seal the first block of the chain if it contains hard forks @@ -1303,23 +1296,27 @@ impl miner::MinerService for Miner { if let Some(name) = self.engine.params().nonzero_bugfix_hard_fork() { warn!("Your chain specification contains one or more hard forks which are required to be \ on by default. Please remove these forks and start your chain again: {}.", name); - return; + return false; } } match sealing_state { SealingState::Ready => { trace!(target: "miner", "update_sealing: engine indicates internal sealing"); - if self.seal_and_import_block_internally(chain, block) { + let seal_and_import_block_internally = self.seal_and_import_block_internally(chain, block); + if seal_and_import_block_internally { trace!(target: "miner", "update_sealing: imported internally sealed block"); } + return seal_and_import_block_internally }, 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); }, - } + }; + + false } fn is_currently_sealing(&self) -> bool { @@ -1449,7 +1446,7 @@ 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 cloned_tx_queue = self.transaction_queue.clone(); let cull = move |chain: &Client| { let client = PoolClient::new( chain, @@ -1459,8 +1456,11 @@ impl miner::MinerService for Miner { service_transaction_checker.as_ref(), ); queue.cull(client); - if is_internal_import { - chain.update_sealing(); + if cloned_tx_queue.all_transaction_hashes().len() > 0 { + if !chain.update_sealing() { + // TODO: call some method that waits `reseal_min_period` and re-tries + // `update_sealing` again + } } }; @@ -1469,8 +1469,11 @@ impl miner::MinerService for Miner { } } else { self.transaction_queue.cull(client); - if is_internal_import { - self.update_sealing(chain); + if self.transaction_queue.all_transaction_hashes().len() > 0 { + if !self.update_sealing(chain) { + // TODO: call some method that waits `reseal_min_period` and tries + // `update_sealing` again + } } } } diff --git a/ethcore/src/miner/mod.rs b/ethcore/src/miner/mod.rs index 04cfd00cab3..2d658d10550 100644 --- a/ethcore/src/miner/mod.rs +++ b/ethcore/src/miner/mod.rs @@ -87,7 +87,7 @@ pub trait MinerService : Send + Sync { where C: BlockChain + CallContract + BlockProducer + SealedBlockImporter + Nonce + Sync; /// Update current pending block - fn update_sealing(&self, chain: &C) + fn update_sealing(&self, chain: &C) -> bool where C: BlockChain + CallContract + BlockProducer + SealedBlockImporter + Nonce + Sync; // Notifications diff --git a/ethcore/src/test_helpers/test_client.rs b/ethcore/src/test_helpers/test_client.rs index 0409e8249d4..4e248cbd6cc 100644 --- a/ethcore/src/test_helpers/test_client.rs +++ b/ethcore/src/test_helpers/test_client.rs @@ -963,7 +963,7 @@ impl ProvingBlockChainClient for TestBlockChainClient { } impl client_traits::EngineClient for TestBlockChainClient { - fn update_sealing(&self) { + fn update_sealing(&self) -> bool { self.miner.update_sealing(self) } diff --git a/miner/src/pool/listener.rs b/miner/src/pool/listener.rs index 9983059048c..aa3b10a7dae 100644 --- a/miner/src/pool/listener.rs +++ b/miner/src/pool/listener.rs @@ -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() + }); } } From 9f7241410ec8513a85865cf1af194823f708093a Mon Sep 17 00:00:00 2001 From: Seun LanLege Date: Tue, 29 Oct 2019 20:34:10 +0100 Subject: [PATCH 03/13] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Tomasz Drwięga --- ethcore/src/miner/miner.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs index abac053390d..9d331eeb80b 100644 --- a/ethcore/src/miner/miner.rs +++ b/ethcore/src/miner/miner.rs @@ -1446,7 +1446,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 cloned_tx_queue = self.transaction_queue.clone(); let cull = move |chain: &Client| { let client = PoolClient::new( chain, @@ -1456,7 +1455,7 @@ impl miner::MinerService for Miner { service_transaction_checker.as_ref(), ); queue.cull(client); - if cloned_tx_queue.all_transaction_hashes().len() > 0 { + if queue.has_local_pending_transactions() { if !chain.update_sealing() { // TODO: call some method that waits `reseal_min_period` and re-tries // `update_sealing` again @@ -1469,7 +1468,7 @@ impl miner::MinerService for Miner { } } else { self.transaction_queue.cull(client); - if self.transaction_queue.all_transaction_hashes().len() > 0 { + if self.transaction_queue.has_local_pending_transactions() { if !self.update_sealing(chain) { // TODO: call some method that waits `reseal_min_period` and tries // `update_sealing` again From 1224d2544dd33c6c54383092038ce6ccaa258fc2 Mon Sep 17 00:00:00 2001 From: Seun Date: Wed, 30 Oct 2019 13:53:42 +0100 Subject: [PATCH 04/13] InstantSeal specific behaviour --- Cargo.lock | 11 +++++++ ethcore/client-traits/src/lib.rs | 1 + ethcore/engine/src/engine.rs | 5 +++ ethcore/engines/instant-seal/Cargo.toml | 2 ++ ethcore/engines/instant-seal/src/lib.rs | 43 +++++++++++++++++++++++-- ethcore/src/miner/miner.rs | 12 ++----- 6 files changed, 63 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2c66ebf0cc4..04a7aa55819 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -634,6 +634,14 @@ dependencies = [ "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "crossbeam-channel" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "crossbeam-deque" version = "0.6.3" @@ -2130,12 +2138,14 @@ version = "0.1.0" dependencies = [ "client-traits 0.1.0", "common-types 0.1.0", + "crossbeam-channel 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "engine 0.1.0", "ethcore 1.12.0", "ethereum-types 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethjson 0.1.0", "keccak-hash 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "machine 0.1.0", + "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "rlp 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "spec 0.1.0", "trace 0.1.0", @@ -5392,6 +5402,7 @@ dependencies = [ "checksum combine 3.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fc1d011beeed29187b8db2ac3925c8dd4d3e87db463dc9d2d2833985388fc5bc" "checksum criterion 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "938703e165481c8d612ea3479ac8342e5615185db37765162e762ec3523e2fc6" "checksum criterion-plot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "eccdc6ce8bbe352ca89025bee672aa6d24f4eb8c53e3a8b5d1bc58011da072a2" +"checksum crossbeam-channel 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c8ec7fcd21571dc78f96cc96243cab8d8f035247c3efd16c687be154c3fa9efa" "checksum crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "05e44b8cf3e1a625844d1750e1f7820da46044ff6d28f4d43e455ba3e5bb2c13" "checksum crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b18cd2e169ad86297e6bc0ad9aa679aee9daa4f19e8163860faf7c164e4f5a71" "checksum crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fedcd6772e37f3da2a9af9bf12ebe046c0dfe657992377b4df982a2b54cd37a9" diff --git a/ethcore/client-traits/src/lib.rs b/ethcore/client-traits/src/lib.rs index 353f96453e8..9fb7e2e6ffb 100644 --- a/ethcore/client-traits/src/lib.rs +++ b/ethcore/client-traits/src/lib.rs @@ -149,6 +149,7 @@ pub trait BlockChain: ChainInfo + BlockInfo + TransactionInfo {} /// Client facilities used by internally sealing Engines. pub trait EngineClient: Sync + Send + ChainInfo { /// Make a new block and seal it. + /// returns true if a block was imported and sealed. fn update_sealing(&self) -> bool; /// Submit a seal for a block in the mining queue. diff --git a/ethcore/engine/src/engine.rs b/ethcore/engine/src/engine.rs index 357a184c7af..dbd8d64c623 100644 --- a/ethcore/engine/src/engine.rs +++ b/ethcore/engine/src/engine.rs @@ -188,6 +188,11 @@ pub trait Engine: Sync + Send { /// Returns the engine's current sealing state. fn sealing_state(&self) -> SealingState { SealingState::External } + /// Called in `chain_new_blocks` if there are local pending txs + /// + /// Does nothing by default + fn maybe_update_sealing(&self) {} + /// Attempt to seal the block internally. /// /// If `Some` is returned, then you get a valid seal. diff --git a/ethcore/engines/instant-seal/Cargo.toml b/ethcore/engines/instant-seal/Cargo.toml index cc59f1793b1..8123b77717f 100644 --- a/ethcore/engines/instant-seal/Cargo.toml +++ b/ethcore/engines/instant-seal/Cargo.toml @@ -13,6 +13,8 @@ ethjson = { path = "../../../json" } client-traits = { path = "../../client-traits" } ethereum-types = "0.8.0" keccak-hash = "0.4.0" +parking_lot = "0.9" +crossbeam-channel = "0.3.9" machine = { path = "../../machine" } trace = { path = "../../trace" } diff --git a/ethcore/engines/instant-seal/src/lib.rs b/ethcore/engines/instant-seal/src/lib.rs index b90859d110a..ca2de937de4 100644 --- a/ethcore/engines/instant-seal/src/lib.rs +++ b/ethcore/engines/instant-seal/src/lib.rs @@ -15,6 +15,8 @@ // along with Parity Ethereum. If not, see . use std::sync::atomic::{AtomicU64, Ordering}; +use std::sync::{Weak, Arc}; +use std::thread; use common_types::{ header::Header, @@ -27,12 +29,14 @@ use common_types::{ }; use engine::Engine; use ethjson; -use std::sync::Weak; +use parking_lot::RwLock; use client_traits::EngineClient; use machine::{ ExecutedBlock, Machine }; +use std::time::Duration; +use crossbeam_channel::{bounded, Sender}; /// `InstantSeal` params. @@ -56,15 +60,40 @@ pub struct InstantSeal { params: InstantSealParams, machine: Machine, last_sealed_block: AtomicU64, + sender: Sender<()>, + client: Arc>>>, } impl InstantSeal { /// Returns new instance of InstantSeal over the given state machine. pub fn new(params: InstantSealParams, machine: Machine) -> Self { + let client: Arc>>> = Default::default(); + let (sender, receiver) = bounded::<()>(1); + let (moved_sender, moved_client) = (sender.clone(), client.clone()); + + thread::Builder::new().name("InstantSealService".into()) + .spawn(move || { + loop { + // block until a message is available. + let _ = receiver.recv().expect("Sender is never dropped; qed"); + // sleep for min_reseal_period + thread::sleep(Duration::from_secs(5)); + // attempt to update_sealing again + let client = moved_client.read().as_ref().and_then(Weak::upgrade); + if let Some(client) = client { + if !client.update_sealing() { + let _ = moved_sender.try_send(()); + } + } + } + }).expect("Failed to create thread!"); + InstantSeal { params, machine, last_sealed_block: AtomicU64::new(0), + sender, + client } } } @@ -76,8 +105,18 @@ impl Engine for InstantSeal { fn sealing_state(&self) -> SealingState { SealingState::Ready } - fn register_client(&self, _client: Weak) { + fn register_client(&self, client: Weak) { + *self.client.write() = Some(client) + } + fn maybe_update_sealing(&self) { + if let Some(client) = self.client.read().as_ref().and_then(Weak::upgrade) { + if !client.update_sealing() { + // disregarding result here because the channel can only hold one message, + // meaning a request to update_sealing is underway + let _ = self.sender.try_send(()); + } + } } fn generate_seal(&self, block: &ExecutedBlock, _parent: &Header) -> Seal { diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs index 9d331eeb80b..7281012c9f6 100644 --- a/ethcore/src/miner/miner.rs +++ b/ethcore/src/miner/miner.rs @@ -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}; use engine::{Engine, signer::EngineSigner}; use machine::executive::contract_address; use spec::Spec; @@ -1456,10 +1456,7 @@ impl miner::MinerService for Miner { ); queue.cull(client); if queue.has_local_pending_transactions() { - if !chain.update_sealing() { - // TODO: call some method that waits `reseal_min_period` and re-tries - // `update_sealing` again - } + engine.maybe_update_sealing(); } }; @@ -1469,10 +1466,7 @@ impl miner::MinerService for Miner { } else { self.transaction_queue.cull(client); if self.transaction_queue.has_local_pending_transactions() { - if !self.update_sealing(chain) { - // TODO: call some method that waits `reseal_min_period` and tries - // `update_sealing` again - } + self.engine.maybe_update_sealing() } } } From b4fd964e5951c6fe93c3991e87810ecb1108cbc8 Mon Sep 17 00:00:00 2001 From: Seun Lanlege Date: Sat, 9 Nov 2019 12:07:13 +0100 Subject: [PATCH 05/13] introduce engine.should_reseal_on_update, remove InstantSealService --- ethcore/engine/src/engine.rs | 10 ++++-- ethcore/engines/instant-seal/src/lib.rs | 42 +++---------------------- ethcore/src/miner/miner.rs | 15 ++++++--- 3 files changed, 22 insertions(+), 45 deletions(-) diff --git a/ethcore/engine/src/engine.rs b/ethcore/engine/src/engine.rs index dbd8d64c623..3aa488fda6f 100644 --- a/ethcore/engine/src/engine.rs +++ b/ethcore/engine/src/engine.rs @@ -45,6 +45,7 @@ use machine::{ use vm::{EnvInfo, Schedule, CallType, ActionValue}; use crate::signer::EngineSigner; +use std::time::Duration; /// A system-calling closure. Enacts calls on a block's state from the system address. pub type SystemCall<'a> = dyn FnMut(Address, Vec) -> Result, String> + 'a; @@ -188,10 +189,13 @@ pub trait Engine: Sync + Send { /// Returns the engine's current sealing state. fn sealing_state(&self) -> SealingState { SealingState::External } - /// Called in `chain_new_blocks` if there are local pending txs + /// Called in `miner.chain_new_blocks` if the engine wishes to `update_sealing` + /// after a block was recently sealed, and there are local pending tx in the pool. /// - /// Does nothing by default - fn maybe_update_sealing(&self) {} + /// returns false by default + fn should_reseal_on_update(&self) -> bool { + false + } /// Attempt to seal the block internally. /// diff --git a/ethcore/engines/instant-seal/src/lib.rs b/ethcore/engines/instant-seal/src/lib.rs index ca2de937de4..912ce4dfbe3 100644 --- a/ethcore/engines/instant-seal/src/lib.rs +++ b/ethcore/engines/instant-seal/src/lib.rs @@ -60,40 +60,15 @@ pub struct InstantSeal { params: InstantSealParams, machine: Machine, last_sealed_block: AtomicU64, - sender: Sender<()>, - client: Arc>>>, } impl InstantSeal { /// Returns new instance of InstantSeal over the given state machine. pub fn new(params: InstantSealParams, machine: Machine) -> Self { - let client: Arc>>> = Default::default(); - let (sender, receiver) = bounded::<()>(1); - let (moved_sender, moved_client) = (sender.clone(), client.clone()); - - thread::Builder::new().name("InstantSealService".into()) - .spawn(move || { - loop { - // block until a message is available. - let _ = receiver.recv().expect("Sender is never dropped; qed"); - // sleep for min_reseal_period - thread::sleep(Duration::from_secs(5)); - // attempt to update_sealing again - let client = moved_client.read().as_ref().and_then(Weak::upgrade); - if let Some(client) = client { - if !client.update_sealing() { - let _ = moved_sender.try_send(()); - } - } - } - }).expect("Failed to create thread!"); - InstantSeal { params, machine, last_sealed_block: AtomicU64::new(0), - sender, - client } } } @@ -105,18 +80,11 @@ impl Engine for InstantSeal { fn sealing_state(&self) -> SealingState { SealingState::Ready } - fn register_client(&self, client: Weak) { - *self.client.write() = Some(client) - } - - fn maybe_update_sealing(&self) { - if let Some(client) = self.client.read().as_ref().and_then(Weak::upgrade) { - if !client.update_sealing() { - // disregarding result here because the channel can only hold one message, - // meaning a request to update_sealing is underway - let _ = self.sender.try_send(()); - } - } + 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 { diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs index 7281012c9f6..99f09199321 100644 --- a/ethcore/src/miner/miner.rs +++ b/ethcore/src/miner/miner.rs @@ -58,7 +58,7 @@ use using_queue::{UsingQueue, GetAction}; use block::{ClosedBlock, SealedBlock}; use client::{BlockProducer, SealedBlockImporter, Client}; -use client_traits::{BlockChain, ChainInfo, Nonce, TransactionInfo}; +use client_traits::{BlockChain, ChainInfo, Nonce, TransactionInfo, EngineClient}; use engine::{Engine, signer::EngineSigner}; use machine::executive::contract_address; use spec::Spec; @@ -1440,6 +1440,7 @@ impl miner::MinerService for Miner { // uncle rate. // If the io_channel is available attempt to offload culling to a separate task // to avoid blocking chain_new_blocks + let reseal_min_period = self.options.reseal_min_period; if let Some(ref channel) = *self.io_channel.read() { let queue = self.transaction_queue.clone(); let nonce_cache = self.nonce_cache.clone(); @@ -1455,8 +1456,10 @@ impl miner::MinerService for Miner { service_transaction_checker.as_ref(), ); queue.cull(client); - if queue.has_local_pending_transactions() { - engine.maybe_update_sealing(); + if queue.has_local_pending_transactions() && + engine.should_reseal_on_update(reseal_min_period) + { + chain.update_sealing(); } }; @@ -1465,8 +1468,10 @@ impl miner::MinerService for Miner { } } else { self.transaction_queue.cull(client); - if self.transaction_queue.has_local_pending_transactions() { - self.engine.maybe_update_sealing() + if self.transaction_queue.has_local_pending_transactions() && + self.engine.should_reseal_on_update(reseal_min_period) + { + self.update_sealing(chain); } } } From 430d3a59e3cd1c842353ce34caa28238a325fcb1 Mon Sep 17 00:00:00 2001 From: Seun Lanlege Date: Sat, 9 Nov 2019 12:19:21 +0100 Subject: [PATCH 06/13] remove unused code --- ethcore/client-traits/src/lib.rs | 3 +-- ethcore/engine/src/engine.rs | 1 - ethcore/engines/instant-seal/src/lib.rs | 6 ------ ethcore/light/src/client/mod.rs | 2 +- ethcore/src/client/client.rs | 2 +- ethcore/src/miner/miner.rs | 22 +++++++++------------- ethcore/src/miner/mod.rs | 2 +- ethcore/src/test_helpers/test_client.rs | 2 +- 8 files changed, 14 insertions(+), 26 deletions(-) diff --git a/ethcore/client-traits/src/lib.rs b/ethcore/client-traits/src/lib.rs index 9fb7e2e6ffb..f592ef6cfe9 100644 --- a/ethcore/client-traits/src/lib.rs +++ b/ethcore/client-traits/src/lib.rs @@ -149,8 +149,7 @@ pub trait BlockChain: ChainInfo + BlockInfo + TransactionInfo {} /// Client facilities used by internally sealing Engines. pub trait EngineClient: Sync + Send + ChainInfo { /// Make a new block and seal it. - /// returns true if a block was imported and sealed. - fn update_sealing(&self) -> bool; + fn update_sealing(&self); /// Submit a seal for a block in the mining queue. fn submit_seal(&self, block_hash: H256, seal: Vec); diff --git a/ethcore/engine/src/engine.rs b/ethcore/engine/src/engine.rs index 3aa488fda6f..c6d882c31ba 100644 --- a/ethcore/engine/src/engine.rs +++ b/ethcore/engine/src/engine.rs @@ -45,7 +45,6 @@ use machine::{ use vm::{EnvInfo, Schedule, CallType, ActionValue}; use crate::signer::EngineSigner; -use std::time::Duration; /// A system-calling closure. Enacts calls on a block's state from the system address. pub type SystemCall<'a> = dyn FnMut(Address, Vec) -> Result, String> + 'a; diff --git a/ethcore/engines/instant-seal/src/lib.rs b/ethcore/engines/instant-seal/src/lib.rs index 912ce4dfbe3..368c2781917 100644 --- a/ethcore/engines/instant-seal/src/lib.rs +++ b/ethcore/engines/instant-seal/src/lib.rs @@ -15,8 +15,6 @@ // along with Parity Ethereum. If not, see . use std::sync::atomic::{AtomicU64, Ordering}; -use std::sync::{Weak, Arc}; -use std::thread; use common_types::{ header::Header, @@ -29,14 +27,10 @@ use common_types::{ }; use engine::Engine; use ethjson; -use parking_lot::RwLock; -use client_traits::EngineClient; use machine::{ ExecutedBlock, Machine }; -use std::time::Duration; -use crossbeam_channel::{bounded, Sender}; /// `InstantSeal` params. diff --git a/ethcore/light/src/client/mod.rs b/ethcore/light/src/client/mod.rs index 8df5c8e03a6..86697c66e82 100644 --- a/ethcore/light/src/client/mod.rs +++ b/ethcore/light/src/client/mod.rs @@ -626,7 +626,7 @@ impl client_traits::ChainInfo for Client { } impl client_traits::EngineClient for Client { - fn update_sealing(&self) -> bool { false } + fn update_sealing(&self) {} fn submit_seal(&self, _block_hash: H256, _seal: Vec>) { } fn broadcast_consensus_message(&self, _message: Vec) { } diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index a23fe050329..f517a057bb4 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -2457,7 +2457,7 @@ impl ::miner::TransactionVerifierClient for Client {} impl ::miner::BlockChainClient for Client {} impl client_traits::EngineClient for Client { - fn update_sealing(&self) -> bool { + fn update_sealing(&self) { self.importer.miner.update_sealing(self) } diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs index 99f09199321..70b0a5f4db7 100644 --- a/ethcore/src/miner/miner.rs +++ b/ethcore/src/miner/miner.rs @@ -1264,7 +1264,7 @@ impl miner::MinerService for Miner { /// Update sealing if required. /// Prepare the block and work if the Engine does not seal internally. - fn update_sealing(&self, chain: &C) -> bool where + fn update_sealing(&self, chain: &C) where C: BlockChain + CallContract + BlockProducer + SealedBlockImporter + Nonce + Sync, { trace!(target: "miner", "update_sealing"); @@ -1272,12 +1272,12 @@ impl miner::MinerService for Miner { // Do nothing if reseal is not required, // but note that `requires_reseal` updates internal state. if !self.requires_reseal(chain.chain_info().best_block_number) { - return false; + return; } let sealing_state = self.engine.sealing_state(); if sealing_state == SealingState::NotReady { - return false; + return; } // -------------------------------------------------------------------------- @@ -1287,7 +1287,7 @@ impl miner::MinerService for Miner { trace!(target: "miner", "update_sealing: preparing a block"); let (block, original_work_hash) = match self.prepare_block(chain) { Some((block, original_work_hash)) => (block, original_work_hash), - None => return false, + None => return, }; // refuse to seal the first block of the chain if it contains hard forks @@ -1296,18 +1296,17 @@ impl miner::MinerService for Miner { if let Some(name) = self.engine.params().nonzero_bugfix_hard_fork() { warn!("Your chain specification contains one or more hard forks which are required to be \ on by default. Please remove these forks and start your chain again: {}.", name); - return false; + return; } } match sealing_state { SealingState::Ready => { trace!(target: "miner", "update_sealing: engine indicates internal sealing"); - let seal_and_import_block_internally = self.seal_and_import_block_internally(chain, block); - if seal_and_import_block_internally { + if self.seal_and_import_block_internally(chain, block) { trace!(target: "miner", "update_sealing: imported internally sealed block"); } - return seal_and_import_block_internally + return }, SealingState::NotReady => unreachable!("We returned right after sealing_state was computed. qed."), SealingState::External => { @@ -1315,8 +1314,6 @@ impl miner::MinerService for Miner { self.prepare_work(block, original_work_hash); }, }; - - false } fn is_currently_sealing(&self) -> bool { @@ -1440,7 +1437,6 @@ impl miner::MinerService for Miner { // uncle rate. // If the io_channel is available attempt to offload culling to a separate task // to avoid blocking chain_new_blocks - let reseal_min_period = self.options.reseal_min_period; if let Some(ref channel) = *self.io_channel.read() { let queue = self.transaction_queue.clone(); let nonce_cache = self.nonce_cache.clone(); @@ -1457,7 +1453,7 @@ impl miner::MinerService for Miner { ); queue.cull(client); if queue.has_local_pending_transactions() && - engine.should_reseal_on_update(reseal_min_period) + engine.should_reseal_on_update() { chain.update_sealing(); } @@ -1469,7 +1465,7 @@ impl miner::MinerService for Miner { } else { self.transaction_queue.cull(client); if self.transaction_queue.has_local_pending_transactions() && - self.engine.should_reseal_on_update(reseal_min_period) + self.engine.should_reseal_on_update() { self.update_sealing(chain); } diff --git a/ethcore/src/miner/mod.rs b/ethcore/src/miner/mod.rs index 2d658d10550..04cfd00cab3 100644 --- a/ethcore/src/miner/mod.rs +++ b/ethcore/src/miner/mod.rs @@ -87,7 +87,7 @@ pub trait MinerService : Send + Sync { where C: BlockChain + CallContract + BlockProducer + SealedBlockImporter + Nonce + Sync; /// Update current pending block - fn update_sealing(&self, chain: &C) -> bool + fn update_sealing(&self, chain: &C) where C: BlockChain + CallContract + BlockProducer + SealedBlockImporter + Nonce + Sync; // Notifications diff --git a/ethcore/src/test_helpers/test_client.rs b/ethcore/src/test_helpers/test_client.rs index 4e248cbd6cc..d9b365c9237 100644 --- a/ethcore/src/test_helpers/test_client.rs +++ b/ethcore/src/test_helpers/test_client.rs @@ -963,7 +963,7 @@ impl ProvingBlockChainClient for TestBlockChainClient { } impl client_traits::EngineClient for TestBlockChainClient { - fn update_sealing(&self) -> bool { + fn update_sealing(&self) { self.miner.update_sealing(self) } From 6de0262cd1c02b1853fbffa89cf45e3f40573ee8 Mon Sep 17 00:00:00 2001 From: Seun Lanlege Date: Sat, 9 Nov 2019 16:07:22 +0100 Subject: [PATCH 07/13] add force param to update_sealing --- ethcore/client-traits/src/lib.rs | 10 +++- ethcore/engines/authority-round/src/lib.rs | 6 +-- ethcore/engines/clique/src/lib.rs | 4 +- ethcore/engines/validator-set/src/multi.rs | 11 +++-- .../validator-set/src/safe_contract.rs | 9 ++-- ethcore/light/src/client/mod.rs | 3 +- ethcore/src/client/client.rs | 7 +-- ethcore/src/miner/miner.rs | 46 +++++++++---------- ethcore/src/miner/mod.rs | 4 +- ethcore/src/test_helpers/test_client.rs | 6 +-- rpc/src/v1/tests/helpers/miner_service.rs | 4 +- 11 files changed, 59 insertions(+), 51 deletions(-) diff --git a/ethcore/client-traits/src/lib.rs b/ethcore/client-traits/src/lib.rs index f592ef6cfe9..10899a95017 100644 --- a/ethcore/client-traits/src/lib.rs +++ b/ethcore/client-traits/src/lib.rs @@ -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 + Yes, + /// yes + 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); diff --git a/ethcore/engines/authority-round/src/lib.rs b/ethcore/engines/authority-round/src/lib.rs index 2f4202f168e..098dff61860 100644 --- a/ethcore/engines/authority-round/src/lib.rs +++ b/ethcore/engines/authority-round/src/lib.rs @@ -39,7 +39,7 @@ use std::sync::atomic::{AtomicUsize, AtomicBool, Ordering as AtomicOrdering}; use std::sync::{Weak, Arc}; use std::time::{UNIX_EPOCH, Duration}; -use client_traits::EngineClient; +use client_traits::{EngineClient, ForceUpdateSealing}; use engine::{Engine, ConstructedVerifier}; use block_reward::{self, BlockRewardContract, RewardKind}; use ethjson; @@ -989,7 +989,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); } } } @@ -1017,7 +1017,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); } } } diff --git a/ethcore/engines/clique/src/lib.rs b/ethcore/engines/clique/src/lib.rs index ac8ed4b86d2..678126372f1 100644 --- a/ethcore/engines/clique/src/lib.rs +++ b/ethcore/engines/clique/src/lib.rs @@ -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); } } } diff --git a/ethcore/engines/validator-set/src/multi.rs b/ethcore/engines/validator-set/src/multi.rs index 72b653041c6..913299fb47e 100644 --- a/ethcore/engines/validator-set/src/multi.rs +++ b/ethcore/engines/validator-set/src/multi.rs @@ -174,6 +174,7 @@ mod tests { use crate::ValidatorSet; use super::Multi; + use ethcore::miner::ForceUpdateSealing; #[test] fn uses_current_set() { @@ -191,24 +192,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. diff --git a/ethcore/engines/validator-set/src/safe_contract.rs b/ethcore/engines/validator-set/src/safe_contract.rs index 666d43eac56..cc61837906c 100644 --- a/ethcore/engines/validator-set/src/safe_contract.rs +++ b/ethcore/engines/validator-set/src/safe_contract.rs @@ -478,6 +478,7 @@ mod tests { use super::super::ValidatorSet; use super::{ValidatorSafeContract, EVENT_NAME_HASH}; + use ethcore::miner::ForceUpdateSealing; #[test] fn fetches_validators() { @@ -513,7 +514,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 +526,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 +547,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); diff --git a/ethcore/light/src/client/mod.rs b/ethcore/light/src/client/mod.rs index 86697c66e82..ce5c50d75c7 100644 --- a/ethcore/light/src/client/mod.rs +++ b/ethcore/light/src/client/mod.rs @@ -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 client_traits::ChainInfo for Client { } impl client_traits::EngineClient for Client { - fn update_sealing(&self) {} + fn update_sealing(&self, _force: ForceUpdateSealing) {} fn submit_seal(&self, _block_hash: H256, _seal: Vec>) { } fn broadcast_consensus_message(&self, _message: Vec) { } diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index f517a057bb4..e47d96eb93d 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -78,7 +78,8 @@ use client_traits::{ StateClient, StateOrBlock, Tick, - TransactionInfo + TransactionInfo, + ForceUpdateSealing }; use db::{keys::BlockDetails, Readable, Writable}; use engine::Engine; @@ -2457,8 +2458,8 @@ 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) { diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs index 70b0a5f4db7..5e6dfcf5f5d 100644 --- a/ethcore/src/miner/miner.rs +++ b/ethcore/src/miner/miner.rs @@ -58,7 +58,7 @@ use using_queue::{UsingQueue, GetAction}; use block::{ClosedBlock, SealedBlock}; use client::{BlockProducer, SealedBlockImporter, Client}; -use client_traits::{BlockChain, ChainInfo, Nonce, TransactionInfo, EngineClient}; +use client_traits::{BlockChain, ChainInfo, Nonce, TransactionInfo, EngineClient, ForceUpdateSealing}; use engine::{Engine, signer::EngineSigner}; use machine::executive::contract_address; use spec::Spec; @@ -866,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(); }, @@ -1264,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(&self, chain: &C) where + fn update_sealing(&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; } @@ -1414,22 +1416,20 @@ impl miner::MinerService for Miner { }); } - if has_new_best_block || (imported.len() > 0 && self.options.reseal_on_uncle) { + if has_new_best_block { // Reset `next_allowed_reseal` in case a block is imported. // Even if min_period is high, we will always attempt to create // new pending block. self.sealing.lock().next_allowed_reseal = Instant::now(); - if !is_internal_import { + if !is_internal_import && imported.len() > 0 && self.options.reseal_on_uncle { // -------------------------------------------------------------------------- // | 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); } - } - if has_new_best_block { // Make sure to cull transactions after we update sealing. // Not culling won't lead to old transactions being added to the block // (thanks to Ready), but culling can take significant amount of time, @@ -1452,10 +1452,8 @@ impl miner::MinerService for Miner { service_transaction_checker.as_ref(), ); queue.cull(client); - if queue.has_local_pending_transactions() && - engine.should_reseal_on_update() - { - chain.update_sealing(); + if engine.should_reseal_on_update() { + chain.update_sealing(ForceUpdateSealing::Yes); } }; @@ -1464,10 +1462,8 @@ impl miner::MinerService for Miner { } } else { self.transaction_queue.cull(client); - if self.transaction_queue.has_local_pending_transactions() && - self.engine.should_reseal_on_update() - { - self.update_sealing(chain); + if self.engine.should_reseal_on_update() { + self.update_sealing(chain, ForceUpdateSealing::Yes); } } } @@ -1798,7 +1794,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); @@ -1808,7 +1804,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); @@ -1836,7 +1832,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()); } @@ -1847,7 +1843,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()); } @@ -1858,7 +1854,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()); } @@ -1877,7 +1873,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()); } diff --git a/ethcore/src/miner/mod.rs b/ethcore/src/miner/mod.rs index 04cfd00cab3..1fddab4a736 100644 --- a/ethcore/src/miner/mod.rs +++ b/ethcore/src/miner/mod.rs @@ -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(&self, chain: &C) + fn update_sealing(&self, chain: &C, force: ForceUpdateSealing) where C: BlockChain + CallContract + BlockProducer + SealedBlockImporter + Nonce + Sync; // Notifications diff --git a/ethcore/src/test_helpers/test_client.rs b/ethcore/src/test_helpers/test_client.rs index d9b365c9237..c0fd15aeb3c 100644 --- a/ethcore/src/test_helpers/test_client.rs +++ b/ethcore/src/test_helpers/test_client.rs @@ -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) { diff --git a/rpc/src/v1/tests/helpers/miner_service.rs b/rpc/src/v1/tests/helpers/miner_service.rs index 7d2edcbbf21..be7d83b57dc 100644 --- a/rpc/src/v1/tests/helpers/miner_service.rs +++ b/rpc/src/v1/tests/helpers/miner_service.rs @@ -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(&self, _chain: &C) { + fn update_sealing(&self, _chain: &C, _force: ForceUpdateSealing) { unimplemented!(); } From a83218b7c9ff7a91fd0f18fb9d35f12bc4257491 Mon Sep 17 00:00:00 2001 From: Seun Lanlege Date: Sat, 9 Nov 2019 16:10:48 +0100 Subject: [PATCH 08/13] better docc --- ethcore/client-traits/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ethcore/client-traits/src/lib.rs b/ethcore/client-traits/src/lib.rs index 10899a95017..3683730b07a 100644 --- a/ethcore/client-traits/src/lib.rs +++ b/ethcore/client-traits/src/lib.rs @@ -146,12 +146,12 @@ 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 +/// Do we want to force update sealing? #[derive(Debug, Copy, Clone, PartialEq)] pub enum ForceUpdateSealing { - /// Ideally + /// Ideally you want to use `No` at all times as `Yes` skips `reseal_required` checks. Yes, - /// yes + /// Don't skip `reseal_required` checks No } /// Client facilities used by internally sealing Engines. From 533a8b77cf02f521e95b658e756a0cfd9068819c Mon Sep 17 00:00:00 2001 From: Seun Lanlege Date: Sat, 9 Nov 2019 16:14:07 +0100 Subject: [PATCH 09/13] even better docs --- ethcore/src/miner/miner.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs index 5e6dfcf5f5d..11f67ab6831 100644 --- a/ethcore/src/miner/miner.rs +++ b/ethcore/src/miner/miner.rs @@ -1453,6 +1453,7 @@ impl miner::MinerService for Miner { ); queue.cull(client); if engine.should_reseal_on_update() { + // force update_sealing here to skip `reseal_required` checks chain.update_sealing(ForceUpdateSealing::Yes); } }; @@ -1463,6 +1464,7 @@ impl miner::MinerService for Miner { } else { self.transaction_queue.cull(client); if self.engine.should_reseal_on_update() { + // force update_sealing here to skip `reseal_required` checks self.update_sealing(chain, ForceUpdateSealing::Yes); } } From 5a68882ef0e2c9734b615d0636c13d11538b1aad Mon Sep 17 00:00:00 2001 From: Seun Lanlege Date: Sat, 9 Nov 2019 16:44:15 +0100 Subject: [PATCH 10/13] revert code changes, doc corrections, sort dep --- ethcore/engine/src/engine.rs | 2 +- ethcore/engines/instant-seal/Cargo.toml | 2 +- ethcore/src/miner/miner.rs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ethcore/engine/src/engine.rs b/ethcore/engine/src/engine.rs index c6d882c31ba..b395d72fee1 100644 --- a/ethcore/engine/src/engine.rs +++ b/ethcore/engine/src/engine.rs @@ -189,7 +189,7 @@ pub trait Engine: Sync + Send { 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, and there are local pending tx in the pool. + /// after a block was recently sealed. /// /// returns false by default fn should_reseal_on_update(&self) -> bool { diff --git a/ethcore/engines/instant-seal/Cargo.toml b/ethcore/engines/instant-seal/Cargo.toml index 8123b77717f..ff1abde55b3 100644 --- a/ethcore/engines/instant-seal/Cargo.toml +++ b/ethcore/engines/instant-seal/Cargo.toml @@ -7,10 +7,10 @@ edition = "2018" license = "GPL-3.0" [dependencies] +client-traits = { path = "../../client-traits" } common-types = { path = "../../types" } engine = { path = "../../engine" } ethjson = { path = "../../../json" } -client-traits = { path = "../../client-traits" } ethereum-types = "0.8.0" keccak-hash = "0.4.0" parking_lot = "0.9" diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs index 11f67ab6831..1a674da180e 100644 --- a/ethcore/src/miner/miner.rs +++ b/ethcore/src/miner/miner.rs @@ -1416,13 +1416,13 @@ impl miner::MinerService for Miner { }); } - if has_new_best_block { + if has_new_best_block || (imported.len() > 0 && self.options.reseal_on_uncle) { // Reset `next_allowed_reseal` in case a block is imported. // Even if min_period is high, we will always attempt to create // new pending block. self.sealing.lock().next_allowed_reseal = Instant::now(); - if !is_internal_import && imported.len() > 0 && self.options.reseal_on_uncle { + if !is_internal_import { // -------------------------------------------------------------------------- // | NOTE Code below requires sealing locks. | // | Make sure to release the locks before calling that method. | From d9468198e651c0bd2bb85fefe1467440ae62b1d7 Mon Sep 17 00:00:00 2001 From: Seun Lanlege Date: Sat, 9 Nov 2019 17:08:06 +0100 Subject: [PATCH 11/13] code optimization --- Cargo.lock | 11 ----------- ethcore/engines/instant-seal/Cargo.toml | 2 -- ethcore/src/miner/miner.rs | 4 +++- 3 files changed, 3 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 04a7aa55819..2c66ebf0cc4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -634,14 +634,6 @@ dependencies = [ "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "crossbeam-channel" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "crossbeam-deque" version = "0.6.3" @@ -2138,14 +2130,12 @@ version = "0.1.0" dependencies = [ "client-traits 0.1.0", "common-types 0.1.0", - "crossbeam-channel 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "engine 0.1.0", "ethcore 1.12.0", "ethereum-types 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethjson 0.1.0", "keccak-hash 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "machine 0.1.0", - "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "rlp 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "spec 0.1.0", "trace 0.1.0", @@ -5402,7 +5392,6 @@ dependencies = [ "checksum combine 3.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fc1d011beeed29187b8db2ac3925c8dd4d3e87db463dc9d2d2833985388fc5bc" "checksum criterion 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "938703e165481c8d612ea3479ac8342e5615185db37765162e762ec3523e2fc6" "checksum criterion-plot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "eccdc6ce8bbe352ca89025bee672aa6d24f4eb8c53e3a8b5d1bc58011da072a2" -"checksum crossbeam-channel 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c8ec7fcd21571dc78f96cc96243cab8d8f035247c3efd16c687be154c3fa9efa" "checksum crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "05e44b8cf3e1a625844d1750e1f7820da46044ff6d28f4d43e455ba3e5bb2c13" "checksum crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b18cd2e169ad86297e6bc0ad9aa679aee9daa4f19e8163860faf7c164e4f5a71" "checksum crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fedcd6772e37f3da2a9af9bf12ebe046c0dfe657992377b4df982a2b54cd37a9" diff --git a/ethcore/engines/instant-seal/Cargo.toml b/ethcore/engines/instant-seal/Cargo.toml index ff1abde55b3..c3a4eb2b485 100644 --- a/ethcore/engines/instant-seal/Cargo.toml +++ b/ethcore/engines/instant-seal/Cargo.toml @@ -13,8 +13,6 @@ engine = { path = "../../engine" } ethjson = { path = "../../../json" } ethereum-types = "0.8.0" keccak-hash = "0.4.0" -parking_lot = "0.9" -crossbeam-channel = "0.3.9" machine = { path = "../../machine" } trace = { path = "../../trace" } diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs index 1a674da180e..a420d400d8e 100644 --- a/ethcore/src/miner/miner.rs +++ b/ethcore/src/miner/miner.rs @@ -1416,7 +1416,7 @@ impl miner::MinerService for Miner { }); } - if has_new_best_block || (imported.len() > 0 && self.options.reseal_on_uncle) { + if has_new_best_block || (imported.len() > 0 && self.options.reseal_on_uncle) { // Reset `next_allowed_reseal` in case a block is imported. // Even if min_period is high, we will always attempt to create // new pending block. @@ -1429,7 +1429,9 @@ impl miner::MinerService for Miner { // -------------------------------------------------------------------------- self.update_sealing(chain, ForceUpdateSealing::No); } + } + if has_new_best_block { // Make sure to cull transactions after we update sealing. // Not culling won't lead to old transactions being added to the block // (thanks to Ready), but culling can take significant amount of time, From 1fd4a174cf5b5ac3d576f499f5d24a206d7f4e62 Mon Sep 17 00:00:00 2001 From: Seun Lanlege Date: Sat, 9 Nov 2019 17:12:36 +0100 Subject: [PATCH 12/13] fix test --- ethcore/engines/validator-set/src/safe_contract.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ethcore/engines/validator-set/src/safe_contract.rs b/ethcore/engines/validator-set/src/safe_contract.rs index cc61837906c..273f5455dbf 100644 --- a/ethcore/engines/validator-set/src/safe_contract.rs +++ b/ethcore/engines/validator-set/src/safe_contract.rs @@ -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}, @@ -478,7 +478,6 @@ mod tests { use super::super::ValidatorSet; use super::{ValidatorSafeContract, EVENT_NAME_HASH}; - use ethcore::miner::ForceUpdateSealing; #[test] fn fetches_validators() { From b6dc6876655f604277c4674353e7c20e1257a9ec Mon Sep 17 00:00:00 2001 From: Seun Lanlege Date: Sat, 9 Nov 2019 17:26:24 +0100 Subject: [PATCH 13/13] fix bench --- ethcore/engines/validator-set/src/multi.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ethcore/engines/validator-set/src/multi.rs b/ethcore/engines/validator-set/src/multi.rs index 913299fb47e..44e9a515790 100644 --- a/ethcore/engines/validator-set/src/multi.rs +++ b/ethcore/engines/validator-set/src/multi.rs @@ -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}, @@ -174,7 +174,6 @@ mod tests { use crate::ValidatorSet; use super::Multi; - use ethcore::miner::ForceUpdateSealing; #[test] fn uses_current_set() {