diff --git a/bin/node-template/node/src/service.rs b/bin/node-template/node/src/service.rs index 6298f194e4f25..6e2a766dc1a4b 100644 --- a/bin/node-template/node/src/service.rs +++ b/bin/node-template/node/src/service.rs @@ -42,9 +42,7 @@ macro_rules! new_full_start { .ok_or_else(|| sc_service::Error::SelectChainRequired)?; let (grandpa_block_import, grandpa_link) = - grandpa::block_import::<_, _, _, node_template_runtime::RuntimeApi, _>( - client.clone(), &*client, select_chain - )?; + grandpa::block_import(client.clone(), &*client, select_chain)?; let aura_block_import = sc_consensus_aura::AuraBlockImport::<_, _, _, AuraPair>::new( grandpa_block_import.clone(), client.clone(), @@ -202,7 +200,7 @@ pub fn new_light(config: Configuration) let fetch_checker = fetcher .map(|fetcher| fetcher.checker().clone()) .ok_or_else(|| "Trying to start light import queue without active fetch checker")?; - let grandpa_block_import = grandpa::light_block_import::<_, _, _, RuntimeApi>( + let grandpa_block_import = grandpa::light_block_import( client.clone(), backend, &*client.clone(), Arc::new(fetch_checker), )?; let finality_proof_import = grandpa_block_import.clone(); diff --git a/bin/node/cli/src/service.rs b/bin/node/cli/src/service.rs index 70dd0521dece3..90090cdf54775 100644 --- a/bin/node/cli/src/service.rs +++ b/bin/node/cli/src/service.rs @@ -314,7 +314,7 @@ pub fn new_light(config: NodeConfiguration) let fetch_checker = fetcher .map(|fetcher| fetcher.checker().clone()) .ok_or_else(|| "Trying to start light import queue without active fetch checker")?; - let grandpa_block_import = grandpa::light_block_import::<_, _, _, RuntimeApi>( + let grandpa_block_import = grandpa::light_block_import( client.clone(), backend, &*client, diff --git a/client/api/src/backend.rs b/client/api/src/backend.rs index a389af5671b32..c3e56e7f8b216 100644 --- a/client/api/src/backend.rs +++ b/client/api/src/backend.rs @@ -169,6 +169,15 @@ pub trait BlockImportOperation { fn mark_head(&mut self, id: BlockId) -> sp_blockchain::Result<()>; } +/// Interface for performing operations on the backend. +pub trait LockImportRun> { + /// Lock the import lock, and run operations inside. + fn lock_import_and_run(&self, f: F) -> Result + where + F: FnOnce(&mut ClientImportOperation) -> Result, + Err: From; +} + /// Finalize Facilities pub trait Finalizer> { /// Mark all blocks up to given as finalized in operation. diff --git a/client/finality-grandpa/Cargo.toml b/client/finality-grandpa/Cargo.toml index 51c52ddf6e50a..f8774ea2836a6 100644 --- a/client/finality-grandpa/Cargo.toml +++ b/client/finality-grandpa/Cargo.toml @@ -21,8 +21,9 @@ assert_matches = "1.3.0" parity-scale-codec = { version = "1.0.0", features = ["derive"] } sp-arithmetic = { version = "2.0.0-alpha.2", path = "../../primitives/arithmetic" } sp-runtime = { version = "2.0.0-alpha.2", path = "../../primitives/runtime" } -sp-consensus = { version = "0.8.0-alpha.2", path = "../../primitives/consensus/common" } +sp-consensus = { version = "0.8.0-alpha.1", path = "../../primitives/consensus/common" } sp-core = { version = "2.0.0-alpha.2", path = "../../primitives/core" } +sp-api = { version = "2.0.0-alpha.2", path = "../../primitives/api" } sc-telemetry = { version = "2.0.0-alpha.2", path = "../telemetry" } sc-keystore = { version = "2.0.0-alpha.2", path = "../keystore" } serde_json = "1.0.41" diff --git a/client/finality-grandpa/src/environment.rs b/client/finality-grandpa/src/environment.rs index fd88113776c9c..dca1eab993262 100644 --- a/client/finality-grandpa/src/environment.rs +++ b/client/finality-grandpa/src/environment.rs @@ -25,18 +25,14 @@ use parity_scale_codec::{Decode, Encode}; use futures::prelude::*; use futures_timer::Delay; use parking_lot::RwLock; -use sp_blockchain::{HeaderBackend, Error as ClientError}; +use sp_blockchain::{HeaderBackend, Error as ClientError, HeaderMetadata}; +use std::marker::PhantomData; use sc_client_api::{ - BlockchainEvents, - backend::{AuxStore, Backend}, - Finalizer, - call_executor::CallExecutor, + backend::Backend, utils::is_descendent_of, }; -use sc_client::{ - apply_aux, Client, -}; +use sc_client::apply_aux; use finality_grandpa::{ BlockNumberOps, Equivocation, Error as GrandpaError, round::State as RoundState, voter, voter_set::VoterSet, @@ -377,8 +373,8 @@ impl SharedVoterSetState { } /// The environment we run GRANDPA in. -pub(crate) struct Environment, RA, SC, VR> { - pub(crate) client: Arc>, +pub(crate) struct Environment, SC, VR> { + pub(crate) client: Arc, pub(crate) select_chain: SC, pub(crate) voters: Arc>, pub(crate) config: Config, @@ -388,9 +384,10 @@ pub(crate) struct Environment, RA, SC, V pub(crate) set_id: SetId, pub(crate) voter_set_state: SharedVoterSetState, pub(crate) voting_rule: VR, + pub(crate) _phantom: PhantomData, } -impl, RA, SC, VR> Environment { +impl, SC, VR> Environment { /// Updates the voter set state using the given closure. The write lock is /// held during evaluation of the closure and the environment's voter set /// state is set to its result if successful. @@ -406,17 +403,16 @@ impl, RA, SC, VR> Environment +impl finality_grandpa::Chain> -for Environment +for Environment where Block: 'static, - B: Backend + 'static, - E: CallExecutor + Send + Sync, + BE: Backend, + C: crate::ClientForGrandpa, N: NetworkT + 'static + Send, SC: SelectChain + 'static, - VR: VotingRule>, - RA: Send + Sync, + VR: VotingRule, NumberFor: BlockNumberOps, { fn ancestry(&self, base: Block::Hash, block: Block::Hash) -> Result, GrandpaError> { @@ -432,7 +428,7 @@ where return None; } - let base_header = match self.client.header(&BlockId::Hash(block)).ok()? { + let base_header = match self.client.header(BlockId::Hash(block)).ok()? { Some(h) => h, None => { debug!(target: "afg", "Encountered error finding best chain containing {:?}: couldn't find base block", block); @@ -450,7 +446,7 @@ where match self.select_chain.finality_target(block, None) { Ok(Some(best_hash)) => { - let best_header = self.client.header(&BlockId::Hash(best_hash)).ok()? + let best_header = self.client.header(BlockId::Hash(best_hash)).ok()? .expect("Header known to exist after `finality_target` call; qed"); // check if our vote is currently being limited due to a pending change @@ -474,7 +470,7 @@ where break; } - target_header = self.client.header(&BlockId::Hash(*target_header.parent_hash())).ok()? + target_header = self.client.header(BlockId::Hash(*target_header.parent_hash())).ok()? .expect("Header known to exist after `finality_target` call; qed"); } @@ -519,17 +515,16 @@ where } -pub(crate) fn ancestry( - client: &Client, +pub(crate) fn ancestry( + client: &Arc, base: Block::Hash, block: Block::Hash, ) -> Result, GrandpaError> where - B: Backend, - E: CallExecutor, + Client: HeaderMetadata, { if base == block { return Err(GrandpaError::NotDescendent) } - let tree_route_res = sp_blockchain::tree_route(client, block, base); + let tree_route_res = sp_blockchain::tree_route(&**client, block, base); let tree_route = match tree_route_res { Ok(tree_route) => tree_route, @@ -550,19 +545,17 @@ pub(crate) fn ancestry( Ok(tree_route.retracted().iter().skip(1).map(|e| e.hash).collect()) } -impl +impl voter::Environment> -for Environment +for Environment where Block: 'static, - B: Backend + 'static, - E: CallExecutor + 'static + Send + Sync, + B: Backend, + C: crate::ClientForGrandpa + 'static, N: NetworkT + 'static + Send, - RA: 'static + Send + Sync, SC: SelectChain + 'static, - VR: VotingRule>, + VR: VotingRule, NumberFor: BlockNumberOps, - Client: AuxStore, { type Timer = Pin> + Send>>; type Id = AuthorityId; @@ -882,7 +875,7 @@ where commit: Commit, ) -> Result<(), Self::Error> { finalize_block( - &*self.client, + self.client.clone(), &self.authority_set, &self.consensus_changes, Some(self.config.justification_period.into()), @@ -940,8 +933,8 @@ impl From> for JustificationOrCommit< /// authority set change is enacted then a justification is created (if not /// given) and stored with the block when finalizing it. /// This method assumes that the block being finalized has already been imported. -pub(crate) fn finalize_block( - client: &Client, +pub(crate) fn finalize_block( + client: Arc, authority_set: &SharedAuthoritySet>, consensus_changes: &SharedConsensusChanges>, justification_period: Option>, @@ -949,16 +942,16 @@ pub(crate) fn finalize_block( number: NumberFor, justification_or_commit: JustificationOrCommit, ) -> Result<(), CommandOrError>> where - B: Backend, - E: CallExecutor + Send + Sync, - RA: Send + Sync, + Block: BlockT, + BE: Backend, + Client: crate::ClientForGrandpa, { // NOTE: lock must be held through writing to DB to avoid race. this lock // also implicitly synchronizes the check for last finalized number // below. let mut authority_set = authority_set.inner().write(); - let status = client.chain_info(); + let status = client.info(); if number <= status.finalized_number && client.hash(number)? == Some(hash) { // This can happen after a forced change (triggered by the finality tracker when finality is stalled), since // the voter will be restarted at the median last finalized block, which can be lower than the local best @@ -981,14 +974,14 @@ pub(crate) fn finalize_block( let mut consensus_changes = consensus_changes.lock(); let canon_at_height = |canon_number| { // "true" because the block is finalized - canonical_at_height(client, (hash, number), true, canon_number) + canonical_at_height(&*client, (hash, number), true, canon_number) }; let update_res: Result<_, Error> = client.lock_import_and_run(|import_op| { let status = authority_set.apply_standard_changes( hash, number, - &is_descendent_of::(client, None), + &is_descendent_of::(&*client, None), ).map_err(|e| Error::Safety(e.to_string()))?; // check if this is this is the first finalization of some consensus changes @@ -1031,7 +1024,7 @@ pub(crate) fn finalize_block( // finalization to remote nodes if !justification_required { if let Some(justification_period) = justification_period { - let last_finalized_number = client.chain_info().finalized_number; + let last_finalized_number = client.info().finalized_number; justification_required = (!last_finalized_number.is_zero() || number - last_finalized_number == justification_period) && (last_finalized_number / justification_period != number / justification_period); @@ -1040,7 +1033,7 @@ pub(crate) fn finalize_block( if justification_required { let justification = GrandpaJustification::from_commit( - client, + &client, round_number, commit, )?; diff --git a/client/finality-grandpa/src/import.rs b/client/finality-grandpa/src/import.rs index 2eb1b4a7c889c..28a08339dcb36 100644 --- a/client/finality-grandpa/src/import.rs +++ b/client/finality-grandpa/src/import.rs @@ -21,9 +21,10 @@ use parity_scale_codec::Encode; use futures::channel::mpsc; use parking_lot::RwLockWriteGuard; -use sp_blockchain::{HeaderBackend, BlockStatus, well_known_cache_keys}; -use sc_client_api::{backend::{TransactionFor, Backend}, CallExecutor, utils::is_descendent_of}; -use sc_client::Client; +use sp_blockchain::{BlockStatus, well_known_cache_keys}; +use sc_client_api::{backend::Backend, utils::is_descendent_of}; +use sp_api::{TransactionFor}; + use sp_consensus::{ BlockImport, Error as ConsensusError, BlockCheckParams, BlockImportParams, ImportResult, JustificationImport, @@ -41,6 +42,7 @@ use crate::authorities::{AuthoritySet, SharedAuthoritySet, DelayKind, PendingCha use crate::consensus_changes::SharedConsensusChanges; use crate::environment::finalize_block; use crate::justification::GrandpaJustification; +use std::marker::PhantomData; /// A block-import handler for GRANDPA. /// @@ -51,16 +53,17 @@ use crate::justification::GrandpaJustification; /// /// When using GRANDPA, the block import worker should be using this block import /// object. -pub struct GrandpaBlockImport { - inner: Arc>, +pub struct GrandpaBlockImport { + inner: Arc, select_chain: SC, authority_set: SharedAuthoritySet>, send_voter_commands: mpsc::UnboundedSender>>, consensus_changes: SharedConsensusChanges>, + _phantom: PhantomData, } -impl Clone for - GrandpaBlockImport +impl Clone for + GrandpaBlockImport { fn clone(&self) -> Self { GrandpaBlockImport { @@ -69,24 +72,24 @@ impl Clone for authority_set: self.authority_set.clone(), send_voter_commands: self.send_voter_commands.clone(), consensus_changes: self.consensus_changes.clone(), + _phantom: PhantomData, } } } -impl JustificationImport - for GrandpaBlockImport where +impl JustificationImport + for GrandpaBlockImport where NumberFor: finality_grandpa::BlockNumberOps, - B: Backend + 'static, - E: CallExecutor + 'static + Clone + Send + Sync, DigestFor: Encode, - RA: Send + Sync, + BE: Backend, + Client: crate::ClientForGrandpa, SC: SelectChain, { type Error = ConsensusError; fn on_start(&mut self) -> Vec<(Block::Hash, NumberFor)> { let mut out = Vec::new(); - let chain_info = self.inner.chain_info(); + let chain_info = self.inner.info(); // request justifications for all pending changes for which change blocks have already been imported let authorities = self.authority_set.inner().read(); @@ -105,7 +108,7 @@ impl JustificationImport }; if let Ok(Some(hash)) = effective_block_hash { - if let Ok(Some(header)) = self.inner.header(&BlockId::Hash(hash)) { + if let Ok(Some(header)) = self.inner.header(BlockId::Hash(hash)) { if *header.number() == pending_change.effective_number() { out.push((header.hash(), *header.number())); } @@ -123,7 +126,7 @@ impl JustificationImport number: NumberFor, justification: Justification, ) -> Result<(), Self::Error> { - self.import_justification(hash, number, justification, false) + GrandpaBlockImport::import_justification(self, hash, number, justification, false) } } @@ -200,14 +203,13 @@ fn find_forced_change(header: &B::Header) header.digest().convert_first(|l| l.try_to(id).and_then(filter_log)) } -impl - GrandpaBlockImport +impl + GrandpaBlockImport where NumberFor: finality_grandpa::BlockNumberOps, - B: Backend + 'static, - E: CallExecutor + 'static + Clone + Send + Sync, DigestFor: Encode, - RA: Send + Sync, + BE: Backend, + Client: crate::ClientForGrandpa, { // check for a new authority set change. fn check_new_change(&self, header: &Block::Header, hash: Block::Hash) @@ -235,11 +237,11 @@ where }) } - fn make_authorities_changes<'a>( - &'a self, - block: &mut BlockImportParams>, + fn make_authorities_changes( + &self, + block: &mut BlockImportParams>, hash: Block::Hash, - ) -> Result, ConsensusError> { + ) -> Result, ConsensusError> { // when we update the authorities, we need to hold the lock // until the block is written to prevent a race if we need to restore // the old authority set on error or panic. @@ -325,10 +327,10 @@ where // for the canon block the new authority set should start // with. we use the minimum between the median and the local // best finalized block. - let best_finalized_number = self.inner.chain_info().finalized_number; + let best_finalized_number = self.inner.info().finalized_number; let canon_number = best_finalized_number.min(median_last_finalized_number); let canon_hash = - self.inner.header(&BlockId::Number(canon_number)) + self.inner.header(BlockId::Number(canon_number)) .map_err(|e| ConsensusError::ClientImport(e.to_string()))? .expect("the given block number is less or equal than the current best finalized number; \ current best finalized number must exist in chain; qed.") @@ -380,18 +382,17 @@ where } } -impl BlockImport - for GrandpaBlockImport where +impl BlockImport + for GrandpaBlockImport where NumberFor: finality_grandpa::BlockNumberOps, - B: Backend + 'static, - E: CallExecutor + 'static + Clone + Send + Sync, DigestFor: Encode, - RA: Send + Sync, - for<'a> &'a Client: - BlockImport>, + BE: Backend, + Client: crate::ClientForGrandpa, + for<'a> &'a Client: + BlockImport>, { type Error = ConsensusError; - type Transaction = TransactionFor; + type Transaction = TransactionFor; fn import_block( &mut self, @@ -521,31 +522,31 @@ impl BlockImport } } -impl GrandpaBlockImport { +impl GrandpaBlockImport { pub(crate) fn new( - inner: Arc>, + inner: Arc, select_chain: SC, authority_set: SharedAuthoritySet>, send_voter_commands: mpsc::UnboundedSender>>, consensus_changes: SharedConsensusChanges>, - ) -> GrandpaBlockImport { + ) -> GrandpaBlockImport { GrandpaBlockImport { inner, select_chain, authority_set, send_voter_commands, consensus_changes, + _phantom: PhantomData, } } } -impl - GrandpaBlockImport +impl + GrandpaBlockImport where + BE: Backend, + Client: crate::ClientForGrandpa, NumberFor: finality_grandpa::BlockNumberOps, - B: Backend + 'static, - E: CallExecutor + 'static + Clone + Send + Sync, - RA: Send + Sync, { /// Import a block justification and finalize the block. @@ -572,7 +573,7 @@ where }; let result = finalize_block( - &*self.inner, + self.inner.clone(), &self.authority_set, &self.consensus_changes, None, diff --git a/client/finality-grandpa/src/justification.rs b/client/finality-grandpa/src/justification.rs index ad96956454fd7..084c0042ab19a 100644 --- a/client/finality-grandpa/src/justification.rs +++ b/client/finality-grandpa/src/justification.rs @@ -15,10 +15,9 @@ // along with Substrate. If not, see . use std::collections::{HashMap, HashSet}; +use std::sync::Arc; -use sc_client::Client; -use sc_client_api::{CallExecutor, backend::Backend}; -use sp_blockchain::Error as ClientError; +use sp_blockchain::{Error as ClientError, HeaderBackend}; use parity_scale_codec::{Encode, Decode}; use finality_grandpa::voter_set::VoterSet; use finality_grandpa::{Error as GrandpaError}; @@ -47,14 +46,12 @@ pub struct GrandpaJustification { impl GrandpaJustification { /// Create a GRANDPA justification from the given commit. This method /// assumes the commit is valid and well-formed. - pub(crate) fn from_commit( - client: &Client, + pub(crate) fn from_commit( + client: &Arc, round: u64, commit: Commit, ) -> Result, Error> where - B: Backend, - E: CallExecutor + Send + Sync, - RA: Send + Sync, + C: HeaderBackend, { let mut votes_ancestries_hashes = HashSet::new(); let mut votes_ancestries = Vec::new(); @@ -69,7 +66,7 @@ impl GrandpaJustification { loop { if current_hash == commit.target_hash { break; } - match client.header(&BlockId::Hash(current_hash))? { + match client.header(BlockId::Hash(current_hash))? { Some(current_header) => { if *current_header.number() <= commit.target_number { return error(); diff --git a/client/finality-grandpa/src/lib.rs b/client/finality-grandpa/src/lib.rs index 650b59dfff662..887d30a70cdc0 100644 --- a/client/finality-grandpa/src/lib.rs +++ b/client/finality-grandpa/src/lib.rs @@ -56,15 +56,18 @@ use futures::prelude::*; use futures::StreamExt; use log::{debug, info}; use futures::channel::mpsc; -use sc_client_api::{BlockchainEvents, CallExecutor, backend::{AuxStore, Backend}, ExecutionStrategy}; -use sp_blockchain::{HeaderBackend, Error as ClientError}; +use sc_client_api::{ + LockImportRun, BlockchainEvents, CallExecutor, + backend::{AuxStore, Backend}, ExecutionStrategy, Finalizer, TransactionFor, +}; +use sp_blockchain::{HeaderBackend, Error as ClientError, HeaderMetadata}; use sc_client::Client; use parity_scale_codec::{Decode, Encode}; use sp_runtime::generic::BlockId; use sp_runtime::traits::{NumberFor, Block as BlockT, DigestFor, Zero}; use sc_keystore::KeyStorePtr; use sp_inherents::InherentDataProviders; -use sp_consensus::SelectChain; +use sp_consensus::{SelectChain, BlockImport}; use sp_core::Pair; use sc_telemetry::{telemetry, CONSENSUS_INFO, CONSENSUS_DEBUG}; use serde_json; @@ -109,6 +112,8 @@ use sp_finality_grandpa::{AuthorityList, AuthorityPair, AuthoritySignature, SetI // Re-export these two because it's just so damn convenient. pub use sp_finality_grandpa::{AuthorityId, ScheduledChange}; +use sp_api::ProvideRuntimeApi; +use std::marker::PhantomData; #[cfg(test)] mod tests; @@ -245,10 +250,8 @@ pub(crate) trait BlockStatus { fn block_number(&self, hash: Block::Hash) -> Result>, Error>; } -impl BlockStatus for Arc> where - B: Backend, - E: CallExecutor + Send + Sync, - RA: Send + Sync, +impl BlockStatus for Arc where + Client: HeaderBackend, NumberFor: BlockNumberOps, { fn block_number(&self, hash: Block::Hash) -> Result>, Error> { @@ -257,6 +260,29 @@ impl BlockStatus for Arc } } +/// A trait that includes all the client functionalities grandpa requires. +/// Ideally this would be a trait alias, we're not there yet. +/// tracking issue https://github.com/rust-lang/rust/issues/41517 +pub trait ClientForGrandpa: + LockImportRun + Finalizer + AuxStore + + HeaderMetadata + HeaderBackend + + BlockchainEvents + ProvideRuntimeApi + + BlockImport, Error = sp_consensus::Error> + where + BE: Backend, + Block: BlockT, +{} + +impl ClientForGrandpa for T + where + BE: Backend, + Block: BlockT, + T: LockImportRun + Finalizer + AuxStore + + HeaderMetadata + HeaderBackend + + BlockchainEvents + ProvideRuntimeApi + + BlockImport, Error = sp_consensus::Error>, +{} + /// Something that one can ask to do a block sync request. pub(crate) trait BlockSyncRequester { /// Notifies the sync service to try and sync the given block from the given @@ -348,8 +374,8 @@ impl fmt::Display for CommandOrError { } } -pub struct LinkHalf { - client: Arc>, +pub struct LinkHalf { + client: Arc, select_chain: SC, persistent_data: PersistentData, voter_commands_rx: mpsc::UnboundedReceiver>>, @@ -390,22 +416,20 @@ impl GenesisAuthoritySetProvider for Client( - client: Arc>, +pub fn block_import( + client: Arc, genesis_authorities_provider: &dyn GenesisAuthoritySetProvider, select_chain: SC, ) -> Result<( - GrandpaBlockImport, - LinkHalf + GrandpaBlockImport, + LinkHalf, ), ClientError> where - B: Backend + 'static, - E: CallExecutor + Send + Sync, - RA: Send + Sync, SC: SelectChain, - Client: AuxStore, + BE: Backend + 'static, + Client: ClientForGrandpa + 'static, { - let chain_info = client.chain_info(); + let chain_info = client.info(); let genesis_hash = chain_info.genesis_hash; let persistent_data = aux_schema::load_persistent( @@ -440,10 +464,10 @@ where )) } -fn global_communication( +fn global_communication( set_id: SetId, voters: &Arc>, - client: &Arc>, + client: Arc, network: &NetworkBridge, keystore: &Option, ) -> ( @@ -455,10 +479,9 @@ fn global_communication( Error = CommandOrError>, > + Unpin, ) where - B: Backend, - E: CallExecutor + Send + Sync, + BE: Backend + 'static, + C: ClientForGrandpa + 'static, N: NetworkT, - RA: Send + Sync, NumberFor: BlockNumberOps, { let is_voter = is_voter(voters, keystore).is_some(); @@ -487,20 +510,18 @@ fn global_communication( /// Register the finality tracker inherent data provider (which is used by /// GRANDPA), if not registered already. -fn register_finality_tracker_inherent_data_provider( - client: Arc>, +fn register_finality_tracker_inherent_data_provider( + client: Arc, inherent_data_providers: &InherentDataProviders, ) -> Result<(), sp_consensus::Error> where - B: Backend + 'static, - E: CallExecutor + Send + Sync + 'static, - RA: Send + Sync + 'static, + Client: HeaderBackend + 'static, { if !inherent_data_providers.has_provider(&sp_finality_tracker::INHERENT_IDENTIFIER) { inherent_data_providers .register_provider(sp_finality_tracker::InherentDataProvider::new(move || { #[allow(deprecated)] { - let info = client.chain_info(); + let info = client.info(); telemetry!(CONSENSUS_INFO; "afg.finalized"; "finalized_number" => ?info.finalized_number, "finalized_hash" => ?info.finalized_hash, @@ -515,11 +536,11 @@ fn register_finality_tracker_inherent_data_provider( } /// Parameters used to run Grandpa. -pub struct GrandpaParams { +pub struct GrandpaParams { /// Configuration for the GRANDPA service. pub config: Config, /// A link to the block import worker. - pub link: LinkHalf, + pub link: LinkHalf, /// The Network instance. pub network: N, /// The inherent data providers. @@ -534,20 +555,18 @@ pub struct GrandpaParams { /// Run a GRANDPA voter as a task. Provide configuration and a link to a /// block import worker that has already been instantiated with `block_import`. -pub fn run_grandpa_voter( - grandpa_params: GrandpaParams, +pub fn run_grandpa_voter( + grandpa_params: GrandpaParams, ) -> sp_blockchain::Result + Unpin + Send + 'static> where Block::Hash: Ord, - B: Backend + 'static, - E: CallExecutor + Send + Sync + 'static, + BE: Backend + 'static, N: NetworkT + Send + Sync + Clone + 'static, SC: SelectChain + 'static, - VR: VotingRule> + Clone + 'static, + VR: VotingRule + Clone + 'static, NumberFor: BlockNumberOps, DigestFor: Encode, - RA: Send + Sync + 'static, X: futures::Future + Clone + Send + Unpin + 'static, - Client: AuxStore, + C: ClientForGrandpa + 'static, { let GrandpaParams { mut config, @@ -629,27 +648,25 @@ pub fn run_grandpa_voter( /// Future that powers the voter. #[must_use] -struct VoterWork, RA, SC, VR> { +struct VoterWork, SC, VR> { voter: Pin>>> + Send>>, - env: Arc>, + env: Arc>, voter_commands_rx: mpsc::UnboundedReceiver>>, network: NetworkBridge, } -impl VoterWork +impl VoterWork where Block: BlockT, + B: Backend + 'static, + C: ClientForGrandpa + 'static, N: NetworkT + Sync, NumberFor: BlockNumberOps, - RA: 'static + Send + Sync, - E: CallExecutor + Send + Sync + 'static, - B: Backend + 'static, SC: SelectChain + 'static, - VR: VotingRule> + Clone + 'static, - Client: AuxStore, + VR: VotingRule + Clone + 'static, { fn new( - client: Arc>, + client: Arc, config: Config, network: NetworkBridge, select_chain: SC, @@ -670,6 +687,7 @@ where authority_set: persistent_data.authority_set.clone(), consensus_changes: persistent_data.consensus_changes.clone(), voter_set_state: persistent_data.set_state.clone(), + _phantom: PhantomData, }); let mut work = VoterWork { @@ -700,7 +718,7 @@ where "authority_id" => authority_id.to_string(), ); - let chain_info = self.env.client.chain_info(); + let chain_info = self.env.client.info(); telemetry!(CONSENSUS_INFO; "afg.authority_set"; "number" => ?chain_info.finalized_number, "hash" => ?chain_info.finalized_hash, @@ -724,7 +742,7 @@ where let global_comms = global_communication( self.env.set_id, &self.env.voters, - &self.env.client, + self.env.client.clone(), &self.env.network, &self.env.config.keystore, ); @@ -789,6 +807,7 @@ where consensus_changes: self.env.consensus_changes.clone(), network: self.env.network.clone(), voting_rule: self.env.voting_rule.clone(), + _phantom: PhantomData, }); self.rebuild_voter(); @@ -813,17 +832,15 @@ where } } -impl Future for VoterWork +impl Future for VoterWork where Block: BlockT, + B: Backend + 'static, N: NetworkT + Sync, NumberFor: BlockNumberOps, - RA: 'static + Send + Sync, - E: CallExecutor + Send + Sync + 'static, - B: Backend + 'static, SC: SelectChain + 'static, - VR: VotingRule> + Clone + 'static, - Client: AuxStore, + C: ClientForGrandpa + 'static, + VR: VotingRule + Clone + 'static, { type Output = Result<(), Error>; @@ -868,15 +885,13 @@ where /// discards all GRANDPA messages (otherwise, we end up banning nodes that send /// us a `Neighbor` message, since there is no registered gossip validator for /// the engine id defined in the message.) -pub fn setup_disabled_grandpa( - client: Arc>, +pub fn setup_disabled_grandpa( + client: Arc, inherent_data_providers: &InherentDataProviders, network: N, ) -> Result<(), sp_consensus::Error> where - B: Backend + 'static, - E: CallExecutor + Send + Sync + 'static, - RA: Send + Sync + 'static, N: NetworkT + Send + Clone + 'static, + Client: HeaderBackend + 'static, { register_finality_tracker_inherent_data_provider( client, diff --git a/client/finality-grandpa/src/light_import.rs b/client/finality-grandpa/src/light_import.rs index 0181a93f1088c..258ea81bd5197 100644 --- a/client/finality-grandpa/src/light_import.rs +++ b/client/finality-grandpa/src/light_import.rs @@ -18,8 +18,7 @@ use std::collections::HashMap; use std::sync::Arc; use log::{info, trace, warn}; use parking_lot::RwLock; -use sc_client::Client; -use sc_client_api::{CallExecutor, backend::{AuxStore, Backend, Finalizer, TransactionFor}}; +use sc_client_api::backend::{AuxStore, Backend, Finalizer, TransactionFor}; use sp_blockchain::{HeaderBackend, Error as ClientError, well_known_cache_keys}; use parity_scale_codec::{Encode, Decode}; use sp_consensus::{ @@ -48,17 +47,15 @@ const LIGHT_AUTHORITY_SET_KEY: &[u8] = b"grandpa_voters"; const LIGHT_CONSENSUS_CHANGES_KEY: &[u8] = b"grandpa_consensus_changes"; /// Create light block importer. -pub fn light_block_import( - client: Arc>, - backend: Arc, +pub fn light_block_import( + client: Arc, + backend: Arc, genesis_authorities_provider: &dyn GenesisAuthoritySetProvider, authority_set_provider: Arc>, -) -> Result, ClientError> +) -> Result, ClientError> where - B: Backend + 'static, - E: CallExecutor + 'static + Clone + Send + Sync, - RA: Send + Sync, - Client: AuxStore, + BE: Backend, + Client: crate::ClientForGrandpa, { let info = client.info(); let import_data = load_aux_import_data( @@ -79,14 +76,14 @@ pub fn light_block_import( /// It is responsible for: /// - checking GRANDPA justifications; /// - fetching finality proofs for blocks that are enacting consensus changes. -pub struct GrandpaLightBlockImport { - client: Arc>, - backend: Arc, +pub struct GrandpaLightBlockImport { + client: Arc, + backend: Arc, authority_set_provider: Arc>, data: Arc>>, } -impl Clone for GrandpaLightBlockImport { +impl Clone for GrandpaLightBlockImport { fn clone(&self) -> Self { GrandpaLightBlockImport { client: self.client.clone(), @@ -111,27 +108,26 @@ struct LightAuthoritySet { authorities: AuthorityList, } -impl GrandpaLightBlockImport { +impl GrandpaLightBlockImport { /// Create finality proof request builder. pub fn create_finality_proof_request_builder(&self) -> BoxFinalityProofRequestBuilder { Box::new(GrandpaFinalityProofRequestBuilder(self.data.clone())) as _ } } -impl BlockImport - for GrandpaLightBlockImport where +impl BlockImport + for GrandpaLightBlockImport where NumberFor: finality_grandpa::BlockNumberOps, - B: Backend + 'static, - E: CallExecutor + 'static + Clone + Send + Sync, DigestFor: Encode, - RA: Send + Sync, - for<'a> &'a Client: - BlockImport> - + Finalizer + BE: Backend + 'static, + for<'a> &'a Client: + HeaderBackend + + BlockImport> + + Finalizer + AuxStore, { type Error = ConsensusError; - type Transaction = TransactionFor; + type Transaction = TransactionFor; fn import_block( &mut self, @@ -151,23 +147,22 @@ impl BlockImport } } -impl FinalityProofImport - for GrandpaLightBlockImport where +impl FinalityProofImport + for GrandpaLightBlockImport where NumberFor: finality_grandpa::BlockNumberOps, - B: Backend + 'static, - E: CallExecutor + 'static + Clone + Send + Sync, DigestFor: Encode, - RA: Send + Sync, - for<'a> &'a Client: - BlockImport> - + Finalizer + BE: Backend + 'static, + for<'a> &'a Client: + HeaderBackend + + BlockImport> + + Finalizer + AuxStore, { type Error = ConsensusError; fn on_start(&mut self) -> Vec<(Block::Hash, NumberFor)> { let mut out = Vec::new(); - let chain_info = self.client.chain_info(); + let chain_info = (&*self.client).info(); let data = self.data.read(); for (pending_number, pending_hash) in data.consensus_changes.pending_changes() { @@ -567,7 +562,7 @@ fn on_post_finalization_error(error: ClientError, value_type: &str) -> Consensus #[cfg(test)] pub mod tests { use super::*; - use sp_consensus::ForkChoiceStrategy; + use sp_consensus::{ForkChoiceStrategy, BlockImport}; use sp_finality_grandpa::AuthorityId; use sp_core::{H256, crypto::Public}; use substrate_test_runtime_client::sc_client::in_mem::Blockchain as InMemoryAuxStore; @@ -575,37 +570,36 @@ pub mod tests { use crate::tests::TestApi; use crate::finality_proof::tests::TestJustification; - pub struct NoJustificationsImport( - pub GrandpaLightBlockImport + pub struct NoJustificationsImport( + pub GrandpaLightBlockImport ); - impl Clone - for NoJustificationsImport where + impl Clone + for NoJustificationsImport where NumberFor: finality_grandpa::BlockNumberOps, - B: Backend + 'static, - E: CallExecutor + 'static + Clone + Send + Sync, DigestFor: Encode, - RA: Send + Sync, + BE: Backend + 'static, { fn clone(&self) -> Self { NoJustificationsImport(self.0.clone()) } } - impl BlockImport - for NoJustificationsImport where + impl BlockImport + for NoJustificationsImport where NumberFor: finality_grandpa::BlockNumberOps, - B: Backend + 'static, - E: CallExecutor + 'static + Clone + Send + Sync, DigestFor: Encode, - RA: Send + Sync, - for<'a> &'a Client: - BlockImport> - + Finalizer + BE: Backend + 'static, + for <'a > &'a Client: + HeaderBackend + + BlockImport> + + Finalizer + AuxStore, + GrandpaLightBlockImport: + BlockImport, Error = ConsensusError> { type Error = ConsensusError; - type Transaction = TransactionFor; + type Transaction = TransactionFor; fn import_block( &mut self, @@ -624,16 +618,15 @@ pub mod tests { } } - impl FinalityProofImport - for NoJustificationsImport where + impl FinalityProofImport + for NoJustificationsImport where NumberFor: finality_grandpa::BlockNumberOps, - B: Backend + 'static, - E: CallExecutor + 'static + Clone + Send + Sync, + BE: Backend + 'static, DigestFor: Encode, - RA: Send + Sync, - for<'a> &'a Client: - BlockImport> - + Finalizer + for <'a > &'a Client: + HeaderBackend + + BlockImport> + + Finalizer + AuxStore, { type Error = ConsensusError; @@ -654,19 +647,15 @@ pub mod tests { } /// Creates light block import that ignores justifications that came outside of finality proofs. - pub fn light_block_import_without_justifications( - client: Arc>, - backend: Arc, + pub fn light_block_import_without_justifications( + client: Arc, + backend: Arc, genesis_authorities_provider: &dyn GenesisAuthoritySetProvider, authority_set_provider: Arc>, - ) -> Result, ClientError> + ) -> Result, ClientError> where - B: Backend + 'static, - E: CallExecutor + 'static + Clone + Send + Sync, - RA: Send + Sync, - Client: BlockImport - + Finalizer - + AuxStore, + BE: Backend + 'static, + Client: crate::ClientForGrandpa, { light_block_import(client, backend, genesis_authorities_provider, authority_set_provider) .map(NoJustificationsImport) @@ -677,6 +666,7 @@ pub mod tests { justification: Option, ) -> ImportResult { let (client, _backend) = substrate_test_runtime_client::new_light(); + let client = Arc::new(client); let mut import_data = LightImportData { last_finalized: Default::default(), authority_set: LightAuthoritySet::genesis(vec![(AuthorityId::from_slice(&[1; 32]), 1)]), @@ -696,7 +686,7 @@ pub mod tests { block.fork_choice = Some(ForkChoiceStrategy::LongestChain); do_import_block::<_, _, _, TestJustification>( - &client, + &*client, &mut import_data, block, new_cache, diff --git a/client/finality-grandpa/src/observer.rs b/client/finality-grandpa/src/observer.rs index 8345a3420998e..f6cf1a8aa1478 100644 --- a/client/finality-grandpa/src/observer.rs +++ b/client/finality-grandpa/src/observer.rs @@ -26,10 +26,9 @@ use finality_grandpa::{ use log::{debug, info, warn}; use sp_consensus::SelectChain; -use sc_client_api::{CallExecutor, backend::{Backend, AuxStore}}; -use sc_client::Client; +use sc_client_api::backend::Backend; use sp_runtime::traits::{NumberFor, Block as BlockT}; - +use sp_blockchain::HeaderMetadata; use crate::{ global_communication, CommandOrError, CommunicationIn, Config, environment, LinkHalf, Error, aux_schema::PersistentData, VoterCommand, VoterSetState, @@ -38,17 +37,21 @@ use crate::authorities::SharedAuthoritySet; use crate::communication::{Network as NetworkT, NetworkBridge}; use crate::consensus_changes::SharedConsensusChanges; use sp_finality_grandpa::AuthorityId; +use std::marker::{PhantomData, Unpin}; -struct ObserverChain<'a, Block: BlockT, B, E, RA>(&'a Client); +struct ObserverChain<'a, Block: BlockT, Client> { + client: &'a Arc, + _phantom: PhantomData, +} -impl<'a, Block: BlockT, B, E, RA> finality_grandpa::Chain> - for ObserverChain<'a, Block, B, E, RA> where - B: Backend, - E: CallExecutor, +impl<'a, Block, Client> finality_grandpa::Chain> + for ObserverChain<'a, Block, Client> where + Block: BlockT, + Client: HeaderMetadata, NumberFor: BlockNumberOps, { fn ancestry(&self, base: Block::Hash, block: Block::Hash) -> Result, GrandpaError> { - environment::ancestry(&self.0, base, block) + environment::ancestry(&self.client, base, block) } fn best_chain_containing(&self, _block: Block::Hash) -> Option<(Block::Hash, NumberFor)> { @@ -57,8 +60,8 @@ impl<'a, Block: BlockT, B, E, RA> finality_grandpa::Chain( - client: &Arc>, +fn grandpa_observer( + client: &Arc, authority_set: &SharedAuthoritySet>, consensus_changes: &SharedConsensusChanges>, voters: &Arc>, @@ -67,13 +70,12 @@ fn grandpa_observer( note_round: F, ) -> impl Future>>> where NumberFor: BlockNumberOps, - B: Backend, - E: CallExecutor + Send + Sync + 'static, - RA: Send + Sync, S: Stream< Item = Result, CommandOrError>>, >, F: Fn(u64), + BE: Backend, + Client: crate::ClientForGrandpa, { let authority_set = authority_set.clone(); let consensus_changes = consensus_changes.clone(); @@ -101,7 +103,7 @@ fn grandpa_observer( let validation_result = match finality_grandpa::validate_commit( &commit, &voters, - &ObserverChain(&*client), + &ObserverChain { client: &client, _phantom: PhantomData }, ) { Ok(r) => r, Err(e) => return future::err(e.into()), @@ -113,7 +115,7 @@ fn grandpa_observer( // commit is valid, finalize the block it targets match environment::finalize_block( - &client, + client.clone(), &authority_set, &consensus_changes, None, @@ -153,19 +155,17 @@ fn grandpa_observer( /// NOTE: this is currently not part of the crate's public API since we don't consider /// it stable enough to use on a live network. #[allow(unused)] -pub fn run_grandpa_observer( +pub fn run_grandpa_observer( config: Config, - link: LinkHalf, + link: LinkHalf, network: N, on_exit: impl futures::Future + Clone + Send + Unpin + 'static, ) -> sp_blockchain::Result + Unpin + Send + 'static> where - B: Backend + 'static, - E: CallExecutor + Send + Sync + 'static, + BE: Backend + Unpin + 'static, N: NetworkT + Send + Clone + 'static, SC: SelectChain + 'static, NumberFor: BlockNumberOps, - RA: Send + Sync + 'static, - Client: AuxStore, + Client: crate::ClientForGrandpa + 'static, { let LinkHalf { client, @@ -199,28 +199,27 @@ pub fn run_grandpa_observer( /// Future that powers the observer. #[must_use] -struct ObserverWork, E, Backend, RA> { +struct ObserverWork> { observer: Pin>>> + Send>>, - client: Arc>, + client: Arc, network: NetworkBridge, persistent_data: PersistentData, keystore: Option, voter_commands_rx: mpsc::UnboundedReceiver>>, + _phantom: PhantomData, } -impl ObserverWork +impl ObserverWork where B: BlockT, - N: NetworkT, + BE: Backend + 'static, + Client: crate::ClientForGrandpa + 'static, + Network: NetworkT, NumberFor: BlockNumberOps, - RA: 'static + Send + Sync, - E: CallExecutor + Send + Sync + 'static, - Bk: Backend + 'static, - Client: AuxStore, { fn new( - client: Arc>, - network: NetworkBridge, + client: Arc, + network: NetworkBridge, persistent_data: PersistentData, keystore: Option, voter_commands_rx: mpsc::UnboundedReceiver>>, @@ -235,6 +234,7 @@ where persistent_data, keystore, voter_commands_rx, + _phantom: PhantomData, }; work.rebuild_observer(); work @@ -251,12 +251,12 @@ where let (global_in, _) = global_communication( set_id, &voters, - &self.client, + self.client.clone(), &self.network, &self.keystore, ); - let last_finalized_number = self.client.chain_info().finalized_number; + let last_finalized_number = self.client.info().finalized_number; // NOTE: since we are not using `round_communication` we have to // manually note the round with the gossip validator, otherwise we won't @@ -324,15 +324,13 @@ where } } -impl Future for ObserverWork +impl Future for ObserverWork where B: BlockT, + BE: Backend + Unpin + 'static, + C: crate::ClientForGrandpa+ 'static, N: NetworkT, NumberFor: BlockNumberOps, - RA: 'static + Send + Sync, - E: CallExecutor + Send + Sync + 'static, - Bk: Backend + 'static, - Client: AuxStore, { type Output = Result<(), Error>; @@ -379,6 +377,7 @@ mod tests { use crate::{aux_schema, communication::tests::{Event, make_test_network}}; use substrate_test_runtime_client::{TestClientBuilder, TestClientBuilderExt}; use sc_network::PeerId; + use sp_blockchain::HeaderBackend as _; use futures::executor; @@ -406,7 +405,7 @@ mod tests { let persistent_data = aux_schema::load_persistent( &*backend, - client.chain_info().genesis_hash, + client.info().genesis_hash, 0, || Ok(vec![]), ).unwrap(); diff --git a/client/finality-grandpa/src/tests.rs b/client/finality-grandpa/src/tests.rs index 16b50ccb9f226..23c7ec9ba8777 100644 --- a/client/finality-grandpa/src/tests.rs +++ b/client/finality-grandpa/src/tests.rs @@ -20,7 +20,7 @@ use super::*; use environment::HasVoted; use sc_network_test::{ Block, Hash, TestNetFactory, BlockImportAdapter, Peer, - PeersClient, PassThroughVerifier, + PeersClient, PassThroughVerifier, PeersFullClient, }; use sc_network::config::{ProtocolConfig, Roles, BoxFinalityProofRequestBuilder}; use parking_lot::Mutex; @@ -60,10 +60,8 @@ type PeerData = Mutex< Option< LinkHalf< - substrate_test_runtime_client::Backend, - substrate_test_runtime_client::Executor, Block, - substrate_test_runtime_client::runtime::RuntimeApi, + PeersFullClient, LongestChain > > @@ -1654,6 +1652,7 @@ fn grandpa_environment_respects_voting_rules() { voters: Arc::new(authority_set.current_authorities()), network, voting_rule, + _phantom: PhantomData, } }; diff --git a/client/src/client.rs b/client/src/client.rs index e9a8f1228c5e1..babbaaf7ef74d 100644 --- a/client/src/client.rs +++ b/client/src/client.rs @@ -66,7 +66,7 @@ pub use sc_client_api::{ backend::{ self, BlockImportOperation, PrunableStateChangesTrieStorage, ClientImportOperation, Finalizer, ImportSummary, NewBlockState, - changes_tries_state_at_block, + LockImportRun, changes_tries_state_at_block, }, client::{ ImportNotifications, FinalityNotification, FinalityNotifications, BlockImportNotification, @@ -218,6 +218,61 @@ impl BlockOf for Client where type Type = Block; } +impl LockImportRun for Client + where + B: backend::Backend, + E: CallExecutor, + Block: BlockT, +{ + fn lock_import_and_run(&self, f: F) -> Result + where + F: FnOnce(&mut ClientImportOperation) -> Result, + Err: From, + { + let inner = || { + let _import_lock = self.backend.get_import_lock().write(); + + let mut op = ClientImportOperation { + op: self.backend.begin_operation()?, + notify_imported: None, + notify_finalized: Vec::new(), + }; + + let r = f(&mut op)?; + + let ClientImportOperation { op, notify_imported, notify_finalized } = op; + self.backend.commit_operation(op)?; + self.notify_finalized(notify_finalized)?; + + if let Some(notify_imported) = notify_imported { + self.notify_imported(notify_imported)?; + } + + Ok(r) + }; + + let result = inner(); + *self.importing_block.write() = None; + + result + } +} + +impl LockImportRun for &Client + where + Block: BlockT, + B: backend::Backend, + E: CallExecutor, +{ + fn lock_import_and_run(&self, f: F) -> Result + where + F: FnOnce(&mut ClientImportOperation) -> Result, + Err: From, + { + (**self).lock_import_and_run(f) + } +} + impl Client where B: backend::Backend, E: CallExecutor, @@ -835,39 +890,6 @@ impl Client where ) } - /// Lock the import lock, and run operations inside. - pub fn lock_import_and_run(&self, f: F) -> Result where - F: FnOnce(&mut ClientImportOperation) -> Result, - Err: From, - { - let inner = || { - let _import_lock = self.backend.get_import_lock().write(); - - let mut op = ClientImportOperation { - op: self.backend.begin_operation()?, - notify_imported: None, - notify_finalized: Vec::new(), - }; - - let r = f(&mut op)?; - - let ClientImportOperation { op, notify_imported, notify_finalized } = op; - self.backend.commit_operation(op)?; - self.notify_finalized(notify_finalized)?; - - if let Some(notify_imported) = notify_imported { - self.notify_imported(notify_imported)?; - } - - Ok(r) - }; - - let result = inner(); - *self.importing_block.write() = None; - - result - } - /// Apply a checked and validated block to an operation. If a justification is provided /// then `finalized` *must* be true. fn apply_block( diff --git a/client/src/lib.rs b/client/src/lib.rs index d97246d478c2b..1d279cabad499 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -98,7 +98,7 @@ pub use crate::{ client::{ new_with_backend, new_in_mem, - BlockBody, ImportNotifications, FinalityNotifications, BlockchainEvents, + BlockBody, ImportNotifications, FinalityNotifications, BlockchainEvents, LockImportRun, BlockImportNotification, Client, ClientInfo, ExecutionStrategies, FinalityNotification, LongestChain, BlockOf, ProvideUncles, BadBlocks, ForkBlocks, apply_aux, },