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:
Seun LanLege 2019-11-10 11:41:31 +01:00 committed by Andronik Ordian
parent 8adde605e9
commit 887aa62fdb
16 changed files with 134 additions and 66 deletions

1
Cargo.lock generated
View File

@ -2156,6 +2156,7 @@ dependencies = [
name = "instant-seal" name = "instant-seal"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"client-traits 0.1.0",
"common-types 0.1.0", "common-types 0.1.0",
"engine 0.1.0", "engine 0.1.0",
"ethcore 1.12.0", "ethcore 1.12.0",

View File

@ -146,10 +146,18 @@ pub trait TransactionInfo {
/// Provides various blockchain information, like block header, chain state etc. /// Provides various blockchain information, like block header, chain state etc.
pub trait BlockChain: ChainInfo + BlockInfo + TransactionInfo {} 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. /// Client facilities used by internally sealing Engines.
pub trait EngineClient: Sync + Send + ChainInfo { pub trait EngineClient: Sync + Send + ChainInfo {
/// Make a new block and seal it. /// 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. /// Submit a seal for a block in the mining queue.
fn submit_seal(&self, block_hash: H256, seal: Vec<Bytes>); fn submit_seal(&self, block_hash: H256, seal: Vec<Bytes>);

View File

@ -188,6 +188,14 @@ pub trait Engine: Sync + Send {
/// Returns the engine's current sealing state. /// Returns the engine's current sealing state.
fn sealing_state(&self) -> SealingState { SealingState::External } 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. /// Attempt to seal the block internally.
/// ///
/// If `Some` is returned, then you get a valid seal. /// If `Some` is returned, then you get a valid seal.

View File

@ -40,7 +40,7 @@ use std::sync::{Weak, Arc};
use std::time::{UNIX_EPOCH, Duration}; use std::time::{UNIX_EPOCH, Duration};
use std::u64; use std::u64;
use client_traits::EngineClient; use client_traits::{EngineClient, ForceUpdateSealing};
use engine::{Engine, ConstructedVerifier}; use engine::{Engine, ConstructedVerifier};
use block_reward::{self, BlockRewardContract, RewardKind}; use block_reward::{self, BlockRewardContract, RewardKind};
use ethjson; use ethjson;
@ -1075,7 +1075,7 @@ impl IoHandler<()> for TransitionHandler {
self.step.can_propose.store(true, AtomicOrdering::SeqCst); self.step.can_propose.store(true, AtomicOrdering::SeqCst);
if let Some(ref weak) = *self.client.read() { if let Some(ref weak) = *self.client.read() {
if let Some(c) = weak.upgrade() { 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); self.step.can_propose.store(true, AtomicOrdering::SeqCst);
if let Some(ref weak) = *self.client.read() { if let Some(ref weak) = *self.client.read() {
if let Some(c) = weak.upgrade() { if let Some(c) = weak.upgrade() {
c.update_sealing(); c.update_sealing(ForceUpdateSealing::No);
} }
} }
} }

View File

@ -66,7 +66,7 @@ use std::{
time::{self, Instant, Duration, SystemTime, UNIX_EPOCH}, time::{self, Instant, Duration, SystemTime, UNIX_EPOCH},
}; };
use client_traits::EngineClient; use client_traits::{EngineClient, ForceUpdateSealing};
use engine::{ use engine::{
Engine, Engine,
signer::EngineSigner, signer::EngineSigner,
@ -780,7 +780,7 @@ impl Engine for Clique {
if self.signer.read().is_some() { if self.signer.read().is_some() {
if let Some(ref weak) = *self.client.read() { if let Some(ref weak) = *self.client.read() {
if let Some(c) = weak.upgrade() { if let Some(c) = weak.upgrade() {
c.update_sealing(); c.update_sealing(ForceUpdateSealing::No);
} }
} }
} }

View File

@ -7,6 +7,7 @@ edition = "2018"
license = "GPL-3.0" license = "GPL-3.0"
[dependencies] [dependencies]
client-traits = { path = "../../client-traits" }
common-types = { path = "../../types" } common-types = { path = "../../types" }
engine = { path = "../../engine" } engine = { path = "../../engine" }
ethjson = { path = "../../../json" } ethjson = { path = "../../../json" }

View File

@ -74,6 +74,13 @@ impl Engine for InstantSeal {
fn sealing_state(&self) -> SealingState { SealingState::Ready } 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 { fn generate_seal(&self, block: &ExecutedBlock, _parent: &Header) -> Seal {
if !block.transactions.is_empty() { if !block.transactions.is_empty() {
let block_number = block.header.number(); let block_number = block.header.number();

View File

@ -161,7 +161,7 @@ mod tests {
ids::BlockId, ids::BlockId,
verification::Unverified, verification::Unverified,
}; };
use client_traits::{BlockChainClient, BlockInfo, ChainInfo, ImportBlock, EngineClient}; use client_traits::{BlockChainClient, BlockInfo, ChainInfo, ImportBlock, EngineClient, ForceUpdateSealing};
use engine::EpochChange; use engine::EpochChange;
use ethcore::{ use ethcore::{
miner::{self, MinerService}, miner::{self, MinerService},
@ -191,24 +191,24 @@ mod tests {
let signer = Box::new((tap.clone(), v1, "".into())); let signer = Box::new((tap.clone(), v1, "".into()));
client.miner().set_author(miner::Author::Sealer(signer)); client.miner().set_author(miner::Author::Sealer(signer));
client.transact_contract(Default::default(), Default::default()).unwrap(); 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); assert_eq!(client.chain_info().best_block_number, 0);
// Right signer for the first block. // Right signer for the first block.
let signer = Box::new((tap.clone(), v0, "".into())); let signer = Box::new((tap.clone(), v0, "".into()));
client.miner().set_author(miner::Author::Sealer(signer)); 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); assert_eq!(client.chain_info().best_block_number, 1);
// This time v0 is wrong. // This time v0 is wrong.
client.transact_contract(Default::default(), Default::default()).unwrap(); 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); assert_eq!(client.chain_info().best_block_number, 1);
let signer = Box::new((tap.clone(), v1, "".into())); let signer = Box::new((tap.clone(), v1, "".into()));
client.miner().set_author(miner::Author::Sealer(signer)); 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); assert_eq!(client.chain_info().best_block_number, 2);
// v1 is still good. // v1 is still good.
client.transact_contract(Default::default(), Default::default()).unwrap(); 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); assert_eq!(client.chain_info().best_block_number, 3);
// Check syncing. // Check syncing.

View File

@ -464,7 +464,7 @@ mod tests {
transaction::{Transaction, Action}, transaction::{Transaction, Action},
verification::Unverified, verification::Unverified,
}; };
use client_traits::{BlockInfo, ChainInfo, ImportBlock, EngineClient}; use client_traits::{BlockInfo, ChainInfo, ImportBlock, EngineClient, ForceUpdateSealing};
use engine::{EpochChange, Proof}; use engine::{EpochChange, Proof};
use ethcore::{ use ethcore::{
miner::{self, MinerService}, miner::{self, MinerService},
@ -513,7 +513,7 @@ mod tests {
data: "bfc708a000000000000000000000000082a978b3f5962a5b0957d9ee9eef472ee55b42f1".from_hex().unwrap(), data: "bfc708a000000000000000000000000082a978b3f5962a5b0957d9ee9eef472ee55b42f1".from_hex().unwrap(),
}.sign(&s0, Some(chain_id)); }.sign(&s0, Some(chain_id));
client.miner().import_own_transaction(client.as_ref(), tx.into()).unwrap(); 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); assert_eq!(client.chain_info().best_block_number, 1);
// Add "1" validator back in. // Add "1" validator back in.
let tx = Transaction { let tx = Transaction {
@ -525,14 +525,14 @@ mod tests {
data: "4d238c8e00000000000000000000000082a978b3f5962a5b0957d9ee9eef472ee55b42f1".from_hex().unwrap(), data: "4d238c8e00000000000000000000000082a978b3f5962a5b0957d9ee9eef472ee55b42f1".from_hex().unwrap(),
}.sign(&s0, Some(chain_id)); }.sign(&s0, Some(chain_id));
client.miner().import_own_transaction(client.as_ref(), tx.into()).unwrap(); 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. // The transaction is not yet included so still unable to seal.
assert_eq!(client.chain_info().best_block_number, 1); assert_eq!(client.chain_info().best_block_number, 1);
// Switch to the validator that is still there. // Switch to the validator that is still there.
let signer = Box::new((tap.clone(), v0, "".into())); let signer = Box::new((tap.clone(), v0, "".into()));
client.miner().set_author(miner::Author::Sealer(signer)); 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); assert_eq!(client.chain_info().best_block_number, 2);
// Switch back to the added validator, since the state is updated. // Switch back to the added validator, since the state is updated.
let signer = Box::new((tap.clone(), v1, "".into())); let signer = Box::new((tap.clone(), v1, "".into()));
@ -546,7 +546,7 @@ mod tests {
data: Vec::new(), data: Vec::new(),
}.sign(&s0, Some(chain_id)); }.sign(&s0, Some(chain_id));
client.miner().import_own_transaction(client.as_ref(), tx.into()).unwrap(); 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. // Able to seal again.
assert_eq!(client.chain_info().best_block_number, 3); assert_eq!(client.chain_info().best_block_number, 3);

View File

@ -48,6 +48,7 @@ use self::header_chain::{AncestryIter, HeaderChain, HardcodedSync};
use cache::Cache; use cache::Cache;
pub use self::service::Service; pub use self::service::Service;
use client_traits::ForceUpdateSealing;
mod header_chain; mod header_chain;
mod service; mod service;
@ -626,7 +627,7 @@ impl<T: ChainDataFetcher> client_traits::ChainInfo for Client<T> {
} }
impl<T: ChainDataFetcher> client_traits::EngineClient 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 submit_seal(&self, _block_hash: H256, _seal: Vec<Vec<u8>>) { }
fn broadcast_consensus_message(&self, _message: Vec<u8>) { } fn broadcast_consensus_message(&self, _message: Vec<u8>) { }

View File

@ -78,7 +78,8 @@ use client_traits::{
StateClient, StateClient,
StateOrBlock, StateOrBlock,
Tick, Tick,
TransactionInfo TransactionInfo,
ForceUpdateSealing
}; };
use db::{keys::BlockDetails, Readable, Writable}; use db::{keys::BlockDetails, Readable, Writable};
use engine::Engine; use engine::Engine;
@ -2383,7 +2384,9 @@ impl ImportSealedBlock for Client {
let raw = block.rlp_bytes(); let raw = block.rlp_bytes();
let header = block.header.clone(); let header = block.header.clone();
let hash = header.hash(); 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 = { let route = {
// Do a super duper basic verification to detect potential bugs // 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 ::miner::BlockChainClient for Client {}
impl client_traits::EngineClient for Client { impl client_traits::EngineClient for Client {
fn update_sealing(&self) { fn update_sealing(&self, force: ForceUpdateSealing) {
self.importer.miner.update_sealing(self) self.importer.miner.update_sealing(self, force)
} }
fn submit_seal(&self, block_hash: H256, seal: Vec<Bytes>) { 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 { if let Err(err) = import {
warn!(target: "poa", "Wrong internal seal submission! {:?}", err); warn!(target: "poa", "Wrong internal seal submission! {:?}", err);
} }
} }
fn broadcast_consensus_message(&self, message: Bytes) { 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> { fn epoch_transition_for(&self, parent_hash: H256) -> Option<EpochTransition> {
@ -2622,13 +2628,21 @@ impl ImportExportBlocks for Client {
if i % 10000 == 0 { if i % 10000 == 0 {
info!("#{}", i); 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 { match format {
DataFormat::Binary => { 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 => { 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 { let format = match format {
Some(format) => format, Some(format) => format,
None => { 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] { match first_bytes[0] {
0xf9 => DataFormat::Binary, 0xf9 => DataFormat::Binary,
_ => DataFormat::Hex, _ => DataFormat::Hex,
@ -2659,7 +2676,9 @@ impl ImportExportBlocks for Client {
let do_import = |bytes: Vec<u8>| { let do_import = |bytes: Vec<u8>| {
let block = Unverified::from_rlp(bytes).map_err(|_| "Invalid block rlp")?; let block = Unverified::from_rlp(bytes).map_err(|_| "Invalid block rlp")?;
let number = block.header.number(); 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) { match self.import_block(block) {
Err(EthcoreError::Import(ImportError::AlreadyInChain)) => { Err(EthcoreError::Import(ImportError::AlreadyInChain)) => {
trace!("Skipping block #{}: already in chain.", number); trace!("Skipping block #{}: already in chain.", number);
@ -2680,33 +2699,45 @@ impl ImportExportBlocks for Client {
} else { } else {
let mut bytes = vec![0; READAHEAD_BYTES]; let mut bytes = vec![0; READAHEAD_BYTES];
let n = source.read(&mut 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) (bytes, n)
}; };
if n == 0 { break; } if n == 0 { break; }
first_read = 0; first_read = 0;
let s = PayloadInfo::from(&bytes) 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); bytes.resize(s, 0);
source.read_exact(&mut bytes[n..]) 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)?; do_import(bytes)?;
} }
} }
DataFormat::Hex => { DataFormat::Hex => {
for line in BufReader::new(source).lines() { for line in BufReader::new(source).lines() {
let s = line 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 { let s = if first_read > 0 {
from_utf8(&first_bytes) from_utf8(&first_bytes)
.map_err(|err| format!("Invalid UTF-8: {:?}", err))? .map_err(|err| {
format!("Invalid UTF-8: {:?}", err)
})?
.to_owned() + &(s[..]) .to_owned() + &(s[..])
} else { } else {
s s
}; };
first_read = 0; first_read = 0;
let bytes = s.from_hex() 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)?; do_import(bytes)?;
} }
} }

View File

@ -58,7 +58,7 @@ use using_queue::{UsingQueue, GetAction};
use block::{ClosedBlock, SealedBlock}; use block::{ClosedBlock, SealedBlock};
use client::{BlockProducer, SealedBlockImporter, Client}; 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 engine::{Engine, signer::EngineSigner};
use machine::executive::contract_address; use machine::executive::contract_address;
use spec::Spec; use spec::Spec;
@ -294,6 +294,7 @@ impl Miner {
let tx_queue_strategy = options.tx_queue_strategy; let tx_queue_strategy = options.tx_queue_strategy;
let nonce_cache_size = cmp::max(4096, limits.max_count / 4); let nonce_cache_size = cmp::max(4096, limits.max_count / 4);
let refuse_service_transactions = options.refuse_service_transactions; let refuse_service_transactions = options.refuse_service_transactions;
let engine = spec.engine.clone();
Miner { Miner {
sealing: Mutex::new(SealingWork { sealing: Mutex::new(SealingWork {
@ -312,7 +313,7 @@ impl Miner {
options, options,
transaction_queue: Arc::new(TransactionQueue::new(limits, verifier_options, tx_queue_strategy)), transaction_queue: Arc::new(TransactionQueue::new(limits, verifier_options, tx_queue_strategy)),
accounts: Arc::new(accounts), accounts: Arc::new(accounts),
engine: spec.engine.clone(), engine,
io_channel: RwLock::new(None), io_channel: RwLock::new(None),
service_transaction_checker: if refuse_service_transactions { service_transaction_checker: if refuse_service_transactions {
None None
@ -865,12 +866,12 @@ impl Miner {
match self.engine.sealing_state() { match self.engine.sealing_state() {
SealingState::Ready => { SealingState::Ready => {
self.maybe_enable_sealing(); self.maybe_enable_sealing();
self.update_sealing(chain) self.update_sealing(chain, ForceUpdateSealing::No);
} }
SealingState::External => { SealingState::External => {
// this calls `maybe_enable_sealing()` // this calls `maybe_enable_sealing()`
if self.prepare_pending_block(chain) == BlockPreparationStatus::NotPrepared { if self.prepare_pending_block(chain) == BlockPreparationStatus::NotPrepared {
self.update_sealing(chain) self.update_sealing(chain, ForceUpdateSealing::No);
} }
} }
SealingState::NotReady => { self.maybe_enable_sealing(); }, SealingState::NotReady => { self.maybe_enable_sealing(); },
@ -1263,14 +1264,16 @@ impl miner::MinerService for Miner {
/// Update sealing if required. /// Update sealing if required.
/// Prepare the block and work if the Engine does not seal internally. /// 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, C: BlockChain + CallContract + BlockProducer + SealedBlockImporter + Nonce + Sync,
{ {
trace!(target: "miner", "update_sealing"); 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. // 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; return;
} }
@ -1305,13 +1308,14 @@ impl miner::MinerService for Miner {
if self.seal_and_import_block_internally(chain, block) { if self.seal_and_import_block_internally(chain, block) {
trace!(target: "miner", "update_sealing: imported internally sealed block"); trace!(target: "miner", "update_sealing: imported internally sealed block");
} }
return
}, },
SealingState::NotReady => unreachable!("We returned right after sealing_state was computed. qed."), SealingState::NotReady => unreachable!("We returned right after sealing_state was computed. qed."),
SealingState::External => { SealingState::External => {
trace!(target: "miner", "update_sealing: engine does not seal internally, preparing work"); 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 { fn is_currently_sealing(&self) -> bool {
@ -1423,7 +1427,7 @@ impl miner::MinerService for Miner {
// | NOTE Code below requires sealing locks. | // | NOTE Code below requires sealing locks. |
// | Make sure to release the locks before calling that method. | // | 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 engine = self.engine.clone();
let accounts = self.accounts.clone(); let accounts = self.accounts.clone();
let service_transaction_checker = self.service_transaction_checker.clone(); let service_transaction_checker = self.service_transaction_checker.clone();
let cull = move |chain: &Client| { let cull = move |chain: &Client| {
let client = PoolClient::new( let client = PoolClient::new(
chain, chain,
@ -1451,8 +1454,9 @@ impl miner::MinerService for Miner {
service_transaction_checker.as_ref(), service_transaction_checker.as_ref(),
); );
queue.cull(client); queue.cull(client);
if is_internal_import { if engine.should_reseal_on_update() {
chain.update_sealing(); // force update_sealing here to skip `reseal_required` checks
chain.update_sealing(ForceUpdateSealing::Yes);
} }
}; };
@ -1461,8 +1465,9 @@ impl miner::MinerService for Miner {
} }
} else { } else {
self.transaction_queue.cull(client); self.transaction_queue.cull(client);
if is_internal_import { if self.engine.should_reseal_on_update() {
self.update_sealing(chain); // force update_sealing here to skip `reseal_required` checks
self.update_sealing(chain, ForceUpdateSealing::Yes);
} }
} }
} }
@ -1793,7 +1798,7 @@ mod tests {
).pop().unwrap(); ).pop().unwrap();
assert_eq!(import.unwrap(), ()); assert_eq!(import.unwrap(), ());
miner.update_sealing(&*client); miner.update_sealing(&*client, ForceUpdateSealing::No);
client.flush_queue(); client.flush_queue();
assert!(miner.pending_block(0).is_none()); assert!(miner.pending_block(0).is_none());
assert_eq!(client.chain_info().best_block_number, 3 as BlockNumber); 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) PendingTransaction::new(transaction_with_chain_id(spec.chain_id()).into(), None)
).is_ok()); ).is_ok());
miner.update_sealing(&*client); miner.update_sealing(&*client, ForceUpdateSealing::No);
client.flush_queue(); client.flush_queue();
assert!(miner.pending_block(0).is_none()); assert!(miner.pending_block(0).is_none());
assert_eq!(client.chain_info().best_block_number, 4 as BlockNumber); 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 miner = Miner::new_for_tests(&spec, None);
let client = generate_dummy_client(2); let client = generate_dummy_client(2);
miner.update_sealing(&*client); miner.update_sealing(&*client, ForceUpdateSealing::No);
assert!(miner.is_currently_sealing()); assert!(miner.is_currently_sealing());
} }
@ -1842,7 +1847,7 @@ mod tests {
let miner = Miner::new_for_tests(&spec, None); let miner = Miner::new_for_tests(&spec, None);
let client = generate_dummy_client(2); let client = generate_dummy_client(2);
miner.update_sealing(&*client); miner.update_sealing(&*client, ForceUpdateSealing::No);
assert!(!miner.is_currently_sealing()); assert!(!miner.is_currently_sealing());
} }
@ -1853,7 +1858,7 @@ mod tests {
let miner = Miner::new_for_tests(&spec, None); let miner = Miner::new_for_tests(&spec, None);
let client = generate_dummy_client(2); let client = generate_dummy_client(2);
miner.update_sealing(&*client); miner.update_sealing(&*client, ForceUpdateSealing::No);
assert!(!miner.is_currently_sealing()); assert!(!miner.is_currently_sealing());
} }
@ -1872,7 +1877,7 @@ mod tests {
miner.add_work_listener(Box::new(DummyNotifyWork)); miner.add_work_listener(Box::new(DummyNotifyWork));
let client = generate_dummy_client(2); let client = generate_dummy_client(2);
miner.update_sealing(&*client); miner.update_sealing(&*client, ForceUpdateSealing::No);
assert!(miner.is_currently_sealing()); assert!(miner.is_currently_sealing());
} }

View File

@ -47,7 +47,7 @@ use types::{
use call_contract::CallContract; use call_contract::CallContract;
use registrar::RegistrarClient; 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 account_state::state::StateInfo;
use crate::{ use crate::{
@ -87,7 +87,7 @@ pub trait MinerService : Send + Sync {
where C: BlockChain + CallContract + BlockProducer + SealedBlockImporter + Nonce + Sync; where C: BlockChain + CallContract + BlockProducer + SealedBlockImporter + Nonce + Sync;
/// Update current pending block /// 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; where C: BlockChain + CallContract + BlockProducer + SealedBlockImporter + Nonce + Sync;
// Notifications // Notifications

View File

@ -72,7 +72,7 @@ use client::{
use client_traits::{ use client_traits::{
BlockInfo, Nonce, Balance, ChainInfo, TransactionInfo, BlockChainClient, ImportBlock, BlockInfo, Nonce, Balance, ChainInfo, TransactionInfo, BlockChainClient, ImportBlock,
AccountData, BlockChain, IoClient, BadBlocks, ScheduleInfo, StateClient, ProvingBlockChainClient, AccountData, BlockChain, IoClient, BadBlocks, ScheduleInfo, StateClient, ProvingBlockChainClient,
StateOrBlock StateOrBlock, ForceUpdateSealing
}; };
use engine::Engine; use engine::Engine;
use machine::executed::Executed; use machine::executed::Executed;
@ -963,8 +963,8 @@ impl ProvingBlockChainClient for TestBlockChainClient {
} }
impl client_traits::EngineClient for TestBlockChainClient { impl client_traits::EngineClient for TestBlockChainClient {
fn update_sealing(&self) { fn update_sealing(&self, force: ForceUpdateSealing) {
self.miner.update_sealing(self) self.miner.update_sealing(self, force)
} }
fn submit_seal(&self, block_hash: H256, seal: Vec<Bytes>) { fn submit_seal(&self, block_hash: H256, seal: Vec<Bytes>) {

View File

@ -105,11 +105,17 @@ impl TransactionsPoolNotifier {
.map(|(hash, _)| hash) .map(|(hash, _)| hash)
.collect() .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 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()
});
} }
} }

View File

@ -20,7 +20,7 @@ use std::sync::Arc;
use std::collections::{BTreeMap, BTreeSet, HashMap}; use std::collections::{BTreeMap, BTreeSet, HashMap};
use bytes::Bytes; use bytes::Bytes;
use client_traits::{Nonce, StateClient}; use client_traits::{Nonce, StateClient, ForceUpdateSealing};
use engine::{Engine, signer::EngineSigner}; use engine::{Engine, signer::EngineSigner};
use ethcore::block::SealedBlock; use ethcore::block::SealedBlock;
use ethcore::client::{PrepareOpenBlock, EngineInfo}; use ethcore::client::{PrepareOpenBlock, EngineInfo};
@ -192,7 +192,7 @@ impl MinerService for TestMinerService {
} }
/// New chain head event. Restart mining operation. /// New chain head event. Restart mining operation.
fn update_sealing<C>(&self, _chain: &C) { fn update_sealing<C>(&self, _chain: &C, _force: ForceUpdateSealing) {
unimplemented!(); unimplemented!();
} }