Skip to content
This repository has been archived by the owner on Nov 6, 2020. It is now read-only.

Make InstantSeal Instant again #11186

Merged
merged 13 commits into from
Nov 10, 2019
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 9 additions & 1 deletion ethcore/client-traits/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,10 +146,18 @@ pub trait TransactionInfo {
/// Provides various blockchain information, like block header, chain state etc.
pub trait BlockChain: ChainInfo + BlockInfo + TransactionInfo {}

/// Do we want to force update sealing?
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum ForceUpdateSealing {
/// Ideally you want to use `No` at all times as `Yes` skips `reseal_required` checks.
Yes,
/// Don't skip `reseal_required` checks
No
}
/// Client facilities used by internally sealing Engines.
pub trait EngineClient: Sync + Send + ChainInfo {
/// Make a new block and seal it.
fn update_sealing(&self);
fn update_sealing(&self, force: ForceUpdateSealing);

/// Submit a seal for a block in the mining queue.
fn submit_seal(&self, block_hash: H256, seal: Vec<Bytes>);
Expand Down
8 changes: 8 additions & 0 deletions ethcore/engine/src/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,14 @@ pub trait Engine: Sync + Send {
/// Returns the engine's current sealing state.
fn sealing_state(&self) -> SealingState { SealingState::External }

/// Called in `miner.chain_new_blocks` if the engine wishes to `update_sealing`
/// after a block was recently sealed.
///
/// returns false by default
fn should_reseal_on_update(&self) -> bool {
false
}

/// Attempt to seal the block internally.
///
/// If `Some` is returned, then you get a valid seal.
Expand Down
6 changes: 3 additions & 3 deletions ethcore/engines/authority-round/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}
}
}
Expand Down Expand Up @@ -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);
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions ethcore/engines/clique/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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);
}
}
}
Expand Down
1 change: 1 addition & 0 deletions ethcore/engines/instant-seal/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ edition = "2018"
license = "GPL-3.0"

[dependencies]
client-traits = { path = "../../client-traits" }
common-types = { path = "../../types" }
engine = { path = "../../engine" }
ethjson = { path = "../../../json" }
Expand Down
7 changes: 7 additions & 0 deletions ethcore/engines/instant-seal/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,13 @@ impl Engine for InstantSeal {

fn sealing_state(&self) -> SealingState { SealingState::Ready }

fn should_reseal_on_update(&self) -> bool {
// We would like for the miner to `update_sealing` if there are local_pending_transactions
// in the pool to prevent transactions sent in parallel from stalling in the transaction
// pool. (see #9660)
true
}

fn generate_seal(&self, block: &ExecutedBlock, _parent: &Header) -> Seal {
if !block.transactions.is_empty() {
let block_number = block.header.number();
Expand Down
11 changes: 6 additions & 5 deletions ethcore/engines/validator-set/src/multi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ mod tests {

use crate::ValidatorSet;
use super::Multi;
use ethcore::miner::ForceUpdateSealing;

#[test]
fn uses_current_set() {
Expand All @@ -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.
Expand Down
9 changes: 5 additions & 4 deletions ethcore/engines/validator-set/src/safe_contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,7 @@ mod tests {

use super::super::ValidatorSet;
use super::{ValidatorSafeContract, EVENT_NAME_HASH};
use ethcore::miner::ForceUpdateSealing;

#[test]
fn fetches_validators() {
Expand Down Expand Up @@ -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 {
Expand All @@ -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()));
Expand All @@ -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);

Expand Down
3 changes: 2 additions & 1 deletion ethcore/light/src/client/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -626,7 +627,7 @@ impl<T: ChainDataFetcher> client_traits::ChainInfo for Client<T> {
}

impl<T: ChainDataFetcher> client_traits::EngineClient for Client<T> {
fn update_sealing(&self) { }
fn update_sealing(&self, _force: ForceUpdateSealing) {}
fn submit_seal(&self, _block_hash: H256, _seal: Vec<Vec<u8>>) { }
fn broadcast_consensus_message(&self, _message: Vec<u8>) { }

Expand Down
65 changes: 48 additions & 17 deletions ethcore/src/client/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ use client_traits::{
StateClient,
StateOrBlock,
Tick,
TransactionInfo
TransactionInfo,
ForceUpdateSealing
};
use db::{keys::BlockDetails, Readable, Writable};
use engine::Engine;
Expand Down Expand Up @@ -2367,7 +2368,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
Expand Down Expand Up @@ -2455,19 +2458,22 @@ impl ::miner::TransactionVerifierClient for Client {}
impl ::miner::BlockChainClient for Client {}

impl client_traits::EngineClient for Client {
fn update_sealing(&self) {
self.importer.miner.update_sealing(self)
fn update_sealing(&self, force: ForceUpdateSealing) {
self.importer.miner.update_sealing(self, force)
}

fn submit_seal(&self, block_hash: H256, seal: Vec<Bytes>) {
let import = self.importer.miner.submit_seal(block_hash, seal).and_then(|block| self.import_sealed_block(block));
let import = self.importer.miner.submit_seal(block_hash, seal)
.and_then(|block| self.import_sealed_block(block));
if let Err(err) = import {
warn!(target: "poa", "Wrong internal seal submission! {:?}", err);
}
}

fn broadcast_consensus_message(&self, message: Bytes) {
self.notify(|notify| notify.broadcast(ChainMessageType::Consensus(message.clone())));
self.notify(|notify| {
notify.broadcast(ChainMessageType::Consensus(message.clone()))
});
}

fn epoch_transition_for(&self, parent_hash: H256) -> Option<EpochTransition> {
Expand Down Expand Up @@ -2593,13 +2599,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)
})?;
}
}
}
Expand All @@ -2619,7 +2633,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,
Expand All @@ -2630,7 +2647,9 @@ impl ImportExportBlocks for Client {
let do_import = |bytes: Vec<u8>| {
let block = Unverified::from_rlp(bytes).map_err(|_| "Invalid block rlp")?;
let number = block.header.number();
while self.queue_info().is_full() { std::thread::sleep(Duration::from_secs(1)); }
while self.queue_info().is_full() {
std::thread::sleep(Duration::from_secs(1));
}
match self.import_block(block) {
Err(EthcoreError::Import(ImportError::AlreadyInChain)) => {
trace!("Skipping block #{}: already in chain.", number);
Expand All @@ -2651,33 +2670,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)?;
}
}
Expand Down
Loading