Make ClientIoMessage generic over the Client (#10981)
* Add client-traits crate Move the BlockInfo trait to new crate * New crate `machine` Contains code extracted from ethcore that defines `Machine`, `Externalities` and other execution related code. * Use new machine and client-traits crates in ethcore * Use new crates machine and client-traits instead of ethcore where appropriate * Fix tests * Don't re-export so many types from ethcore::client * Fixing more fallout from removing re-export * fix test * More fallout from not re-exporting types * Add some docs * cleanup * import the macro edition style * Tweak docs * Add missing import * remove unused ethabi_derive imports * Use latest ethabi-contract * Move many traits from ethcore/client/traits to client-traits crate Initial version of extracted Engine trait * Move snapshot related traits to the engine crate (eew) * Move a few snapshot related types to common_types Cleanup Executed as exported from machine crate * fix warning * Gradually introduce new engine crate: snapshot * ethcore typechecks with new engine crate * Sort out types outside ethcore * Add an EpochVerifier to ethash and use that in Engine.epoch_verifier() Cleanup * Document pub members * Sort out tests Sort out default impls for EpochVerifier * Add test-helpers feature and move EngineSigner impl to the right place * Sort out tests * Sort out tests and refactor verification types * Fix missing traits * More missing traits Fix Histogram * Fix tests and cleanup * cleanup * Put back needed logger import * Don't rexport common_types from ethcore/src/client Don't export ethcore::client::* * Remove files no longer used Use types from the engine crate Explicit exports from engine::engine * Get rid of itertools * Move a few more traits from ethcore to client-traits: BlockChainReset, ScheduleInfo, StateClient * Move ProvingBlockChainClient to client-traits * Don't re-export ForkChoice and Transition from ethcore * Address grumbles: sort imports, remove commented out code * Fix merge resolution error * Extract the Clique engine to own crate * Extract NullEngine and the block_reward module from ethcore * Extract InstantSeal engine to own crate * Extract remaining engines * Extract executive_state to own crate so it can be used by engine crates * Remove snapshot stuff from the engine crate * Put snapshot traits back in ethcore * cleanup * Remove stuff from ethcore * Don't use itertools * itertools in aura is legit-ish * More post-merge fixes * Re-export less types in client * cleanup * Extract spec to own crate * Put back the test-helpers from basic-authority * Fix ethcore benchmarks * Reduce the public api of ethcore/verification * WIP * Add Cargo.toml * Fix compilation outside ethcore * Audit uses of import_verified_blocks() and remove unneeded calls Cleanup * cleanup * Remove unused imports from ethcore * Cleanup * remove double semi-colons * Add missing generic param * More missing generics * Update ethcore/block-reward/Cargo.toml Co-Authored-By: Tomasz Drwięga <tomusdrw@users.noreply.github.com> * Update ethcore/engines/basic-authority/Cargo.toml Co-Authored-By: Tomasz Drwięga <tomusdrw@users.noreply.github.com> * Update ethcore/engines/ethash/Cargo.toml Co-Authored-By: Tomasz Drwięga <tomusdrw@users.noreply.github.com> * Update ethcore/engines/clique/src/lib.rs Co-Authored-By: Tomasz Drwięga <tomusdrw@users.noreply.github.com> * signers is already a ref * Add an EngineType enum to tighten up Engine.name() * Introduce Snapshotting enum to distinguish the type of snapshots a chain uses * Rename supports_warp to snapshot_mode * Missing import * Update ethcore/src/snapshot/consensus/mod.rs Co-Authored-By: Tomasz Drwięga <tomusdrw@users.noreply.github.com> * missing import * Fix import * double semi * Fix merge problem * cleanup * Parametrise `ClientIoMessage` with `()` for the light client * Add impl Tick for () * Address review feedback * Move ClientIoMessage to common-types * remove superseeded fixme * fix merge conflict errors
This commit is contained in:
@@ -14,7 +14,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use std::{cmp, ops};
|
||||
use std::cmp;
|
||||
use std::collections::{HashSet, BTreeMap, VecDeque};
|
||||
use std::sync::atomic::{AtomicUsize, AtomicBool, Ordering as AtomicOrdering};
|
||||
use std::sync::{Arc, Weak};
|
||||
@@ -42,14 +42,15 @@ use client::ancient_import::AncientVerifier;
|
||||
use client::{
|
||||
ReopenBlock, PrepareOpenBlock, ImportSealedBlock, BroadcastProposalBlock,
|
||||
Call, BlockProducer, SealedBlockImporter, ChainNotify, EngineInfo,
|
||||
ClientConfig, NewBlocks, ChainRoute, ChainMessageType, bad_blocks, ClientIoMessage,
|
||||
ClientConfig, NewBlocks, ChainRoute, ChainMessageType, bad_blocks,
|
||||
};
|
||||
use client_traits::{
|
||||
BlockInfo, ScheduleInfo, StateClient, BlockChainReset,
|
||||
Nonce, Balance, ChainInfo, TransactionInfo, ImportBlock,
|
||||
AccountData, BlockChain as BlockChainTrait, BlockChainClient,
|
||||
IoClient, BadBlocks, ProvingBlockChainClient,
|
||||
StateOrBlock
|
||||
IoClient, BadBlocks, ProvingBlockChainClient, SnapshotClient,
|
||||
DatabaseRestore, SnapshotWriter, Tick,
|
||||
StateOrBlock,
|
||||
};
|
||||
use engine::Engine;
|
||||
use machine::{
|
||||
@@ -59,7 +60,7 @@ use machine::{
|
||||
};
|
||||
use trie_vm_factories::{Factories, VmFactory};
|
||||
use miner::{Miner, MinerService};
|
||||
use snapshot::{self, io as snapshot_io, SnapshotClient};
|
||||
use snapshot;
|
||||
use spec::Spec;
|
||||
use account_state::State;
|
||||
use executive_state;
|
||||
@@ -71,6 +72,8 @@ use types::{
|
||||
block::PreverifiedBlock,
|
||||
block_status::BlockStatus,
|
||||
blockchain_info::BlockChainInfo,
|
||||
client_types::ClientReport,
|
||||
io_message::ClientIoMessage,
|
||||
encoded,
|
||||
engines::{
|
||||
ForkChoice,
|
||||
@@ -111,44 +114,6 @@ const MAX_ANCIENT_BLOCKS_TO_IMPORT: usize = 4;
|
||||
const MAX_QUEUE_SIZE_TO_SLEEP_ON: usize = 2;
|
||||
const MIN_HISTORY_SIZE: u64 = 8;
|
||||
|
||||
/// Report on the status of a client.
|
||||
#[derive(Default, Clone, Debug, Eq, PartialEq)]
|
||||
pub struct ClientReport {
|
||||
/// How many blocks have been imported so far.
|
||||
pub blocks_imported: usize,
|
||||
/// How many transactions have been applied so far.
|
||||
pub transactions_applied: usize,
|
||||
/// How much gas has been processed so far.
|
||||
pub gas_processed: U256,
|
||||
/// Memory used by state DB
|
||||
pub state_db_mem: usize,
|
||||
}
|
||||
|
||||
impl ClientReport {
|
||||
/// Alter internal reporting to reflect the additional `block` has been processed.
|
||||
pub fn accrue_block(&mut self, header: &Header, transactions: usize) {
|
||||
self.blocks_imported += 1;
|
||||
self.transactions_applied += transactions;
|
||||
self.gas_processed = self.gas_processed + *header.gas_used();
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ops::Sub<&'a ClientReport> for ClientReport {
|
||||
type Output = Self;
|
||||
|
||||
fn sub(mut self, other: &'a ClientReport) -> Self {
|
||||
let higher_mem = cmp::max(self.state_db_mem, other.state_db_mem);
|
||||
let lower_mem = cmp::min(self.state_db_mem, other.state_db_mem);
|
||||
|
||||
self.blocks_imported -= other.blocks_imported;
|
||||
self.transactions_applied -= other.transactions_applied;
|
||||
self.gas_processed = self.gas_processed - other.gas_processed;
|
||||
self.state_db_mem = higher_mem - lower_mem;
|
||||
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
struct SleepState {
|
||||
last_activity: Option<Instant>,
|
||||
last_autosleep: Option<Instant>,
|
||||
@@ -171,7 +136,7 @@ struct Importer {
|
||||
pub verifier: Box<dyn Verifier<Client>>,
|
||||
|
||||
/// Queue containing pending blocks
|
||||
pub block_queue: BlockQueue,
|
||||
pub block_queue: BlockQueue<Client>,
|
||||
|
||||
/// Handles block sealing
|
||||
pub miner: Arc<Miner>,
|
||||
@@ -222,7 +187,7 @@ pub struct Client {
|
||||
|
||||
/// Flag changed by `sleep` and `wake_up` methods. Not to be confused with `enabled`.
|
||||
liveness: AtomicBool,
|
||||
io_channel: RwLock<IoChannel<ClientIoMessage>>,
|
||||
io_channel: RwLock<IoChannel<ClientIoMessage<Self>>>,
|
||||
|
||||
/// List of actors to be notified on certain chain events
|
||||
notify: RwLock<Vec<Weak<dyn ChainNotify>>>,
|
||||
@@ -261,7 +226,7 @@ impl Importer {
|
||||
pub fn new(
|
||||
config: &ClientConfig,
|
||||
engine: Arc<dyn Engine>,
|
||||
message_channel: IoChannel<ClientIoMessage>,
|
||||
message_channel: IoChannel<ClientIoMessage<Client>>,
|
||||
miner: Arc<Miner>,
|
||||
) -> Result<Importer, EthcoreError> {
|
||||
let block_queue = BlockQueue::new(
|
||||
@@ -723,7 +688,7 @@ impl Client {
|
||||
spec: &Spec,
|
||||
db: Arc<dyn BlockChainDB>,
|
||||
miner: Arc<Miner>,
|
||||
message_channel: IoChannel<ClientIoMessage>,
|
||||
message_channel: IoChannel<ClientIoMessage<Self>>,
|
||||
) -> Result<Arc<Client>, EthcoreError> {
|
||||
let trie_spec = match config.fat_db {
|
||||
true => TrieSpec::Fat,
|
||||
@@ -948,11 +913,6 @@ impl Client {
|
||||
Arc::new(last_hashes)
|
||||
}
|
||||
|
||||
/// This is triggered by a message coming from a block queue when the block is ready for insertion
|
||||
pub fn import_verified_blocks(&self) -> usize {
|
||||
self.importer.import_verified_blocks(self)
|
||||
}
|
||||
|
||||
// use a state-proving closure for the given block.
|
||||
fn with_proving_caller<F, T>(&self, id: BlockId, with_call: F) -> T
|
||||
where F: FnOnce(&MachineCall) -> T
|
||||
@@ -1037,7 +997,7 @@ impl Client {
|
||||
}
|
||||
|
||||
/// Replace io channel. Useful for testing.
|
||||
pub fn set_io_channel(&self, io_channel: IoChannel<ClientIoMessage>) {
|
||||
pub fn set_io_channel(&self, io_channel: IoChannel<ClientIoMessage<Self>>) {
|
||||
*self.io_channel.write() = io_channel;
|
||||
}
|
||||
|
||||
@@ -1112,15 +1072,6 @@ impl Client {
|
||||
report
|
||||
}
|
||||
|
||||
/// Tick the client.
|
||||
// TODO: manage by real events.
|
||||
pub fn tick(&self, prevent_sleep: bool) {
|
||||
self.check_garbage();
|
||||
if !prevent_sleep {
|
||||
self.check_snooze();
|
||||
}
|
||||
}
|
||||
|
||||
fn check_garbage(&self) {
|
||||
self.chain.read().collect_garbage();
|
||||
self.importer.block_queue.collect_garbage();
|
||||
@@ -1161,64 +1112,6 @@ impl Client {
|
||||
}
|
||||
}
|
||||
|
||||
/// Take a snapshot at the given block.
|
||||
/// If the ID given is "latest", this will default to 1000 blocks behind.
|
||||
pub fn take_snapshot<W: snapshot_io::SnapshotWriter + Send>(
|
||||
&self,
|
||||
writer: W,
|
||||
at: BlockId,
|
||||
p: &Progress,
|
||||
) -> Result<(), EthcoreError> {
|
||||
if let Snapshotting::Unsupported = self.engine.snapshot_mode() {
|
||||
return Err(EthcoreError::Snapshot(SnapshotError::SnapshotsUnsupported));
|
||||
}
|
||||
let db = self.state_db.read().journal_db().boxed_clone();
|
||||
let best_block_number = self.chain_info().best_block_number;
|
||||
let block_number = self.block_number(at).ok_or_else(|| SnapshotError::InvalidStartingBlock(at))?;
|
||||
|
||||
if db.is_prunable() && self.pruning_info().earliest_state > block_number {
|
||||
return Err(SnapshotError::OldBlockPrunedDB.into());
|
||||
}
|
||||
|
||||
let history = cmp::min(self.history, 1000);
|
||||
|
||||
let start_hash = match at {
|
||||
BlockId::Latest => {
|
||||
let start_num = match db.earliest_era() {
|
||||
Some(era) => cmp::max(era, best_block_number.saturating_sub(history)),
|
||||
None => best_block_number.saturating_sub(history),
|
||||
};
|
||||
|
||||
match self.block_hash(BlockId::Number(start_num)) {
|
||||
Some(h) => h,
|
||||
None => return Err(SnapshotError::InvalidStartingBlock(at).into()),
|
||||
}
|
||||
}
|
||||
_ => match self.block_hash(at) {
|
||||
Some(hash) => hash,
|
||||
None => return Err(SnapshotError::InvalidStartingBlock(at).into()),
|
||||
},
|
||||
};
|
||||
|
||||
let processing_threads = self.config.snapshot.processing_threads;
|
||||
let chunker = snapshot::chunker(self.engine.snapshot_mode()).ok_or_else(|| SnapshotError::SnapshotsUnsupported)?;
|
||||
snapshot::take_snapshot(
|
||||
chunker,
|
||||
&self.chain.read(),
|
||||
start_hash,
|
||||
db.as_hash_db(),
|
||||
writer,
|
||||
p,
|
||||
processing_threads,
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Ask the client what the history parameter is.
|
||||
pub fn pruning_history(&self) -> u64 {
|
||||
self.history
|
||||
}
|
||||
|
||||
fn block_hash(chain: &BlockChain, id: BlockId) -> Option<H256> {
|
||||
match id {
|
||||
BlockId::Hash(hash) => Some(hash),
|
||||
@@ -1342,7 +1235,7 @@ impl Client {
|
||||
}
|
||||
}
|
||||
|
||||
impl snapshot::DatabaseRestore for Client {
|
||||
impl DatabaseRestore for Client {
|
||||
/// Restart the client with a new backend
|
||||
fn restore_db(&self, new_db: &str) -> Result<(), EthcoreError> {
|
||||
trace!(target: "snapshot", "Replacing client database with {:?}", new_db);
|
||||
@@ -1426,6 +1319,11 @@ impl BlockChainReset for Client {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Ask the client what the history parameter is.
|
||||
fn pruning_history(&self) -> u64 {
|
||||
self.history
|
||||
}
|
||||
}
|
||||
|
||||
impl Nonce for Client {
|
||||
@@ -1547,6 +1445,11 @@ impl ImportBlock for Client {
|
||||
Err((_, e)) => Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
/// Triggered by a message from a block queue when the block is ready for insertion
|
||||
fn import_verified_blocks(&self) -> usize {
|
||||
self.importer.import_verified_blocks(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl StateClient for Client {
|
||||
@@ -2341,6 +2244,18 @@ impl IoClient for Client {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl Tick for Client {
|
||||
/// Tick the client.
|
||||
// TODO: manage by real events.
|
||||
fn tick(&self, prevent_sleep: bool) {
|
||||
self.check_garbage();
|
||||
if !prevent_sleep {
|
||||
self.check_snooze();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ReopenBlock for Client {
|
||||
@@ -2581,7 +2496,60 @@ impl ProvingBlockChainClient for Client {
|
||||
}
|
||||
}
|
||||
|
||||
impl SnapshotClient for Client {}
|
||||
impl SnapshotClient for Client {
|
||||
fn take_snapshot<W: SnapshotWriter + Send>(
|
||||
&self,
|
||||
writer: W,
|
||||
at: BlockId,
|
||||
p: &Progress,
|
||||
) -> Result<(), EthcoreError> {
|
||||
if let Snapshotting::Unsupported = self.engine.snapshot_mode() {
|
||||
return Err(EthcoreError::Snapshot(SnapshotError::SnapshotsUnsupported));
|
||||
}
|
||||
let db = self.state_db.read().journal_db().boxed_clone();
|
||||
let best_block_number = self.chain_info().best_block_number;
|
||||
let block_number = self.block_number(at).ok_or_else(|| SnapshotError::InvalidStartingBlock(at))?;
|
||||
|
||||
if db.is_prunable() && self.pruning_info().earliest_state > block_number {
|
||||
return Err(SnapshotError::OldBlockPrunedDB.into());
|
||||
}
|
||||
|
||||
let history = cmp::min(self.history, 1000);
|
||||
|
||||
let start_hash = match at {
|
||||
BlockId::Latest => {
|
||||
let start_num = match db.earliest_era() {
|
||||
Some(era) => cmp::max(era, best_block_number.saturating_sub(history)),
|
||||
None => best_block_number.saturating_sub(history),
|
||||
};
|
||||
|
||||
match self.block_hash(BlockId::Number(start_num)) {
|
||||
Some(h) => h,
|
||||
None => return Err(SnapshotError::InvalidStartingBlock(at).into()),
|
||||
}
|
||||
}
|
||||
_ => match self.block_hash(at) {
|
||||
Some(hash) => hash,
|
||||
None => return Err(SnapshotError::InvalidStartingBlock(at).into()),
|
||||
},
|
||||
};
|
||||
|
||||
let processing_threads = self.config.snapshot.processing_threads;
|
||||
let chunker = snapshot::chunker(self.engine.snapshot_mode()).ok_or_else(|| SnapshotError::SnapshotsUnsupported)?;
|
||||
snapshot::take_snapshot(
|
||||
chunker,
|
||||
&self.chain.read(),
|
||||
start_hash,
|
||||
db.as_hash_db(),
|
||||
writer,
|
||||
p,
|
||||
processing_threads,
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// Returns `LocalizedReceipt` given `LocalizedTransaction`
|
||||
/// and a vector of receipts from given block up to transaction index.
|
||||
@@ -2641,7 +2609,7 @@ impl IoChannelQueue {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn queue<F>(&self, channel: &IoChannel<ClientIoMessage>, count: usize, fun: F) -> EthcoreResult<()> where
|
||||
pub fn queue<F>(&self, channel: &IoChannel<ClientIoMessage<Client>>, count: usize, fun: F) -> EthcoreResult<()> where
|
||||
F: Fn(&Client) + Send + Sync + 'static,
|
||||
{
|
||||
let queue_size = self.currently_queued.load(AtomicOrdering::Relaxed);
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity Ethereum.
|
||||
|
||||
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use std::fmt;
|
||||
use bytes::Bytes;
|
||||
use client::Client;
|
||||
use ethereum_types::H256;
|
||||
use types::snapshot::ManifestData;
|
||||
|
||||
/// Message type for external and internal events
|
||||
#[derive(Debug)]
|
||||
pub enum ClientIoMessage {
|
||||
/// Best Block Hash in chain has been changed
|
||||
NewChainHead,
|
||||
/// A block is ready
|
||||
BlockVerified,
|
||||
/// Begin snapshot restoration
|
||||
BeginRestoration(ManifestData),
|
||||
/// Feed a state chunk to the snapshot service
|
||||
FeedStateChunk(H256, Bytes),
|
||||
/// Feed a block chunk to the snapshot service
|
||||
FeedBlockChunk(H256, Bytes),
|
||||
/// Take a snapshot for the block with given number.
|
||||
TakeSnapshot(u64),
|
||||
/// Execute wrapped closure
|
||||
Execute(Callback),
|
||||
}
|
||||
|
||||
impl ClientIoMessage {
|
||||
/// Create new `ClientIoMessage` that executes given procedure.
|
||||
pub fn execute<F: Fn(&Client) + Send + Sync + 'static>(fun: F) -> Self {
|
||||
ClientIoMessage::Execute(Callback(Box::new(fun)))
|
||||
}
|
||||
}
|
||||
|
||||
/// A function to invoke in the client thread.
|
||||
pub struct Callback(pub Box<dyn Fn(&Client) + Send + Sync>);
|
||||
|
||||
impl fmt::Debug for Callback {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(fmt, "<callback>")
|
||||
}
|
||||
}
|
||||
@@ -22,15 +22,13 @@ mod client;
|
||||
mod config;
|
||||
#[cfg(any(test, feature = "test-helpers"))]
|
||||
mod evm_test_client;
|
||||
mod io_message;
|
||||
#[cfg(any(test, feature = "test-helpers"))]
|
||||
mod test_client;
|
||||
|
||||
pub use self::client::{Client, ClientReport};
|
||||
pub use self::client::Client;
|
||||
pub use self::config::{ClientConfig, DatabaseCompactionProfile, BlockChainConfig, VMType};
|
||||
#[cfg(any(test, feature = "test-helpers"))]
|
||||
pub use self::evm_test_client::{EvmTestClient, EvmTestError, TransactErr, TransactSuccess};
|
||||
pub use self::io_message::ClientIoMessage;
|
||||
#[cfg(any(test, feature = "test-helpers"))]
|
||||
pub use self::test_client::{TestBlockChainClient, EachBlockWith, TestState};
|
||||
pub use self::chain_notify::{ChainNotify, NewBlocks, ChainRoute, ChainRouteType, ChainMessageType};
|
||||
|
||||
@@ -592,6 +592,10 @@ impl ImportBlock for TestBlockChainClient {
|
||||
}
|
||||
Ok(h)
|
||||
}
|
||||
|
||||
fn import_verified_blocks(&self) -> usize {
|
||||
unimplemented!("TestClient does not implement import_verified_blocks()")
|
||||
}
|
||||
}
|
||||
|
||||
impl Call for TestBlockChainClient {
|
||||
|
||||
Reference in New Issue
Block a user