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

Break circular dependency between Client and Engine (part 1) #10833

Merged
merged 6 commits into from
Jul 4, 2019
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 17 additions & 18 deletions ethcore/src/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@
//! and can be appended to with transactions and uncles.
//!
//! When ready, `OpenBlock` can be closed and turned into a `ClosedBlock`. A `ClosedBlock` can
//! be reopend again by a miner under certain circumstances. On block close, state commit is
//! be re-opend again by a miner under certain circumstances. On block close, state commit is
//! performed.
//!
//! `LockedBlock` is a version of a `ClosedBlock` that cannot be reopened. It can be sealed
//! using an engine.
//!
//! `ExecutedBlock` is an underlaying data structure used by all structs above to store block
//! `ExecutedBlock` is an underlying data structure used by all structs above to store block
//! related info.

use std::{cmp, ops};
Expand Down Expand Up @@ -62,6 +62,7 @@ use types::receipt::{Receipt, TransactionOutcome};
pub struct OpenBlock<'x> {
block: ExecutedBlock,
engine: &'x dyn Engine,
parent: Header,
}

/// Just like `OpenBlock`, except that we've applied `Engine::on_close_block`, finished up the non-seal header fields,
Expand All @@ -72,6 +73,7 @@ pub struct OpenBlock<'x> {
pub struct ClosedBlock {
block: ExecutedBlock,
unclosed_state: State<StateDB>,
parent: Header,
}

/// Just like `ClosedBlock` except that we can't reopen it and it's faster.
Expand Down Expand Up @@ -102,7 +104,7 @@ pub struct ExecutedBlock {
pub receipts: Vec<Receipt>,
/// Hashes of already executed transactions.
pub transactions_set: HashSet<H256>,
/// Underlaying state.
/// Underlying state.
pub state: State<StateDB>,
/// Transaction traces.
pub traces: Tracing,
Expand All @@ -119,13 +121,13 @@ impl ExecutedBlock {
uncles: Default::default(),
receipts: Default::default(),
transactions_set: Default::default(),
state: state,
state,
traces: if tracing {
Tracing::enabled()
} else {
Tracing::Disabled
},
last_hashes: last_hashes,
last_hashes,
}
}

Expand Down Expand Up @@ -173,14 +175,12 @@ impl<'x> OpenBlock<'x> {
gas_range_target: (U256, U256),
extra_data: Bytes,
is_epoch_begin: bool,
ancestry: I,
ancestry: I, // TODO: remove this
) -> Result<Self, Error> {
let number = parent.number() + 1;
let state = State::from_existing(db, parent.state_root().clone(), engine.account_start_nonce(number), factories)?;
let mut r = OpenBlock {
block: ExecutedBlock::new(state, last_hashes, tracing),
engine: engine,
};

let mut r = OpenBlock { block: ExecutedBlock::new(state, last_hashes, tracing), engine, parent: parent.clone() };

r.block.header.set_parent_hash(parent.hash());
r.block.header.set_number(number);
Expand All @@ -195,7 +195,7 @@ impl<'x> OpenBlock<'x> {
engine.populate_from_parent(&mut r.block.header, parent);

engine.machine().on_new_block(&mut r.block)?;
engine.on_new_block(&mut r.block, is_epoch_begin, &mut ancestry.into_iter())?;
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ancestry was never used so I'm not sure what it was used for tbh.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch!

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was for engines that need to compute additional information regarding finalisation (for example, finalise blocks based on ancestor finalisation information).

Looks like we at least don’t need it right now!

engine.on_new_block(&mut r.block, is_epoch_begin)?;

Ok(r)
}
Expand Down Expand Up @@ -297,19 +297,20 @@ impl<'x> OpenBlock<'x> {
/// Turn this into a `ClosedBlock`.
pub fn close(self) -> Result<ClosedBlock, Error> {
let unclosed_state = self.block.state.clone();
let parent = self.parent.clone();
let locked = self.close_and_lock()?;

Ok(ClosedBlock {
block: locked.block,
unclosed_state,
parent,
})
}

/// Turn this into a `LockedBlock`.
pub fn close_and_lock(self) -> Result<LockedBlock, Error> {
let mut s = self;

s.engine.on_close_block(&mut s.block)?;
s.engine.on_close_block(&mut s.block, &s.parent)?;
s.block.state.commit()?;

s.block.header.set_transactions_root(ordered_trie_root(s.block.transactions.iter().map(|e| e.rlp_bytes())));
Expand Down Expand Up @@ -378,10 +379,8 @@ impl ClosedBlock {
// revert rewards (i.e. set state back at last transaction's state).
let mut block = self.block;
block.state = self.unclosed_state;
OpenBlock {
block: block,
engine: engine,
}
let parent = self.parent;
OpenBlock { block, engine, parent }
}
}

Expand Down Expand Up @@ -522,7 +521,7 @@ pub(crate) fn enact(
b.close_and_lock()
}

/// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header
/// Enact the block given by `block_bytes` using `engine` on the database `db` with the given `parent` block header
pub fn enact_verified(
block: PreverifiedBlock,
engine: &dyn Engine,
Expand Down
23 changes: 7 additions & 16 deletions ethcore/src/engines/authority_round/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1211,7 +1211,6 @@ impl Engine for AuthorityRound {
&self,
block: &mut ExecutedBlock,
epoch_begin: bool,
_ancestry: &mut dyn Iterator<Item=ExtendedHeader>,
) -> Result<(), Error> {
// with immediate transitions, we don't use the epoch mechanism anyway.
// the genesis is always considered an epoch, but we ignore it intentionally.
Expand All @@ -1236,26 +1235,18 @@ impl Engine for AuthorityRound {
}

/// Apply the block reward on finalisation of the block.
fn on_close_block(&self, block: &mut ExecutedBlock) -> Result<(), Error> {
fn on_close_block(
&self,
block: &mut ExecutedBlock,
parent: &Header,
) -> Result<(), Error> {
let mut beneficiaries = Vec::new();
if block.header.number() >= self.empty_steps_transition {
let empty_steps = if block.header.seal().is_empty() {
// this is a new block, calculate rewards based on the empty steps messages we have accumulated
let client = match self.client.read().as_ref().and_then(|weak| weak.upgrade()) {
Some(client) => client,
None => {
debug!(target: "engine", "Unable to close block: missing client ref.");
return Err(EngineError::RequiresClient.into())
},
};

let parent = client.block_header(::client::BlockId::Hash(*block.header.parent_hash()))
.expect("hash is from parent; parent header must exist; qed")
.decode()?;

let parent_step = header_step(&parent, self.empty_steps_transition)?;
let parent_step = header_step(parent, self.empty_steps_transition)?;
let current_step = self.step.inner.load();
self.empty_steps(parent_step.into(), current_step.into(), parent.hash())
self.empty_steps(parent_step, current_step, parent.hash())
} else {
// we're verifying a block, extract empty steps from the seal
header_empty_steps(&block.header)?
Expand Down
7 changes: 5 additions & 2 deletions ethcore/src/engines/clique/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -368,13 +368,16 @@ impl Engine for Clique {
&self,
_block: &mut ExecutedBlock,
_epoch_begin: bool,
_ancestry: &mut dyn Iterator<Item=ExtendedHeader>,
) -> Result<(), Error> {
Ok(())
}

// Clique has no block reward.
fn on_close_block(&self, _block: &mut ExecutedBlock) -> Result<(), Error> {
fn on_close_block(
&self,
_block: &mut ExecutedBlock,
_parent_header: &Header
) -> Result<(), Error> {
Ok(())
}

Expand Down
7 changes: 5 additions & 2 deletions ethcore/src/engines/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -304,13 +304,16 @@ pub trait Engine: Sync + Send {
&self,
_block: &mut ExecutedBlock,
_epoch_begin: bool,
_ancestry: &mut dyn Iterator<Item = ExtendedHeader>,
) -> Result<(), Error> {
Ok(())
}

/// Block transformation functions, after the transactions.
fn on_close_block(&self, _block: &mut ExecutedBlock) -> Result<(), Error> {
fn on_close_block(
&self,
_block: &mut ExecutedBlock,
_parent_header: &Header,
) -> Result<(), Error> {
Ok(())
}

Expand Down
6 changes: 5 additions & 1 deletion ethcore/src/engines/null_engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,11 @@ impl Engine for NullEngine {

fn machine(&self) -> &Machine { &self.machine }

fn on_close_block(&self, block: &mut ExecutedBlock) -> Result<(), Error> {
fn on_close_block(
&self,
block: &mut ExecutedBlock,
_parent_header: &Header
) -> Result<(), Error> {
use std::ops::Shr;

let author = *block.header.author();
Expand Down
2 changes: 1 addition & 1 deletion ethcore/src/ethereum/ethash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ impl Engine for Arc<Ethash> {

/// Apply the block reward on finalisation of the block.
/// This assumes that all uncles are valid uncles (i.e. of at least one generation before the current).
fn on_close_block(&self, block: &mut ExecutedBlock) -> Result<(), Error> {
fn on_close_block(&self, block: &mut ExecutedBlock, _parent_header: &Header) -> Result<(), Error> {
use std::ops::Shr;

let author = *block.header.author();
Expand Down
2 changes: 1 addition & 1 deletion ethcore/src/miner/miner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -548,7 +548,7 @@ impl Miner {
}
},
// Invalid nonce error can happen only if previous transaction is skipped because of gas limit.
// If there is errornous state of transaction queue it will be fixed when next block is imported.
// If there is erroneous state of transaction queue it will be fixed when next block is imported.
Err(Error::Execution(ExecutionError::InvalidNonce { expected, got })) => {
debug!(target: "miner", "Skipping adding transaction to block because of invalid nonce: {:?} (expected: {:?}, got: {:?})", hash, expected, got);
},
Expand Down
2 changes: 1 addition & 1 deletion ethcore/src/tests/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ fn query_none_block() {
Arc::new(Miner::new_for_tests(&spec, None)),
IoChannel::disconnected(),
).unwrap();
let non_existant = client.block_header(BlockId::Number(188));
let non_existant = client.block_header(BlockId::Number(188));
assert!(non_existant.is_none());
}

Expand Down