diff --git a/substrate/Cargo.lock b/substrate/Cargo.lock index fb944b782a..a33cb02f7f 100644 --- a/substrate/Cargo.lock +++ b/substrate/Cargo.lock @@ -7208,6 +7208,7 @@ dependencies = [ name = "sc-consensus" version = "0.9.0" dependencies = [ + "async-trait", "parking_lot 0.11.1", "sc-client-api", "sp-blockchain", @@ -8707,6 +8708,7 @@ name = "sp-api-test" version = "2.0.1" dependencies = [ "criterion", + "futures 0.3.15", "log", "parity-scale-codec", "rustversion", diff --git a/substrate/client/consensus/babe/rpc/src/lib.rs b/substrate/client/consensus/babe/rpc/src/lib.rs index 6696a65040..e16c24acac 100644 --- a/substrate/client/consensus/babe/rpc/src/lib.rs +++ b/substrate/client/consensus/babe/rpc/src/lib.rs @@ -93,11 +93,14 @@ impl BabeRpcHandler { } impl BabeApi for BabeRpcHandler - where - B: BlockT, - C: ProvideRuntimeApi + HeaderBackend + HeaderMetadata + 'static, - C::Api: BabeRuntimeApi, - SC: SelectChain + Clone + 'static, +where + B: BlockT, + C: ProvideRuntimeApi + + HeaderBackend + + HeaderMetadata + + 'static, + C::Api: BabeRuntimeApi, + SC: SelectChain + Clone + 'static, { fn epoch_authorship(&self) -> FutureResult> { if let Err(err) = self.deny_unsafe.check_if_safe() { @@ -118,28 +121,33 @@ impl BabeApi for BabeRpcHandler self.select_chain.clone(), ); let future = async move { - let header = select_chain.best_chain().map_err(Error::Consensus)?; - let epoch_start = client.runtime_api() + let header = select_chain.best_chain().map_err(Error::Consensus).await?; + let epoch_start = client + .runtime_api() .current_epoch_start(&BlockId::Hash(header.hash())) - .map_err(|err| { - Error::StringError(format!("{:?}", err)) - })?; + .map_err(|err| Error::StringError(format!("{:?}", err)))?; let epoch = epoch_data( &shared_epoch, &client, &babe_config, *epoch_start, &select_chain, - )?; + ) + .await?; let (epoch_start, epoch_end) = (epoch.start_slot(), epoch.end_slot()); let mut claims: HashMap = HashMap::new(); let keys = { - epoch.authorities.iter() + epoch + .authorities + .iter() .enumerate() .filter_map(|(i, a)| { - if SyncCryptoStore::has_keys(&*keystore, &[(a.0.to_raw_vec(), AuthorityId::ID)]) { + if SyncCryptoStore::has_keys( + &*keystore, + &[(a.0.to_raw_vec(), AuthorityId::ID)], + ) { Some((a.0.clone(), i)) } else { None @@ -167,7 +175,8 @@ impl BabeApi for BabeRpcHandler } Ok(claims) - }.boxed(); + } + .boxed(); Box::new(future.compat()) } @@ -203,20 +212,20 @@ impl From for jsonrpc_core::Error { } } -/// fetches the epoch data for a given slot. -fn epoch_data( +/// Fetches the epoch data for a given slot. +async fn epoch_data( epoch_changes: &SharedEpochChanges, client: &Arc, babe_config: &Config, slot: u64, select_chain: &SC, ) -> Result - where - B: BlockT, - C: HeaderBackend + HeaderMetadata + 'static, - SC: SelectChain, +where + B: BlockT, + C: HeaderBackend + HeaderMetadata + 'static, + SC: SelectChain, { - let parent = select_chain.best_chain()?; + let parent = select_chain.best_chain().await?; epoch_changes.shared_data().epoch_data_for_child_of( descendent_query(&**client), &parent.hash(), diff --git a/substrate/client/consensus/babe/src/lib.rs b/substrate/client/consensus/babe/src/lib.rs index 8112a00416..15d16c91f4 100644 --- a/substrate/client/consensus/babe/src/lib.rs +++ b/substrate/client/consensus/babe/src/lib.rs @@ -989,7 +989,7 @@ where Ok(()) } - fn check_and_report_equivocation( + async fn check_and_report_equivocation( &self, slot_now: Slot, slot: Slot, @@ -1024,6 +1024,7 @@ where let best_id = self .select_chain .best_chain() + .await .map(|h| BlockId::Hash(h.hash())) .map_err(|e| Error::Client(e.into()))?; @@ -1070,13 +1071,26 @@ where } } +type BlockVerificationResult = Result< + ( + BlockImportParams, + Option)>>, + ), + String, +>; + #[async_trait::async_trait] impl Verifier for BabeVerifier where Block: BlockT, - Client: HeaderMetadata + HeaderBackend + ProvideRuntimeApi - + Send + Sync + AuxStore + ProvideCache, + Client: HeaderMetadata + + HeaderBackend + + ProvideRuntimeApi + + Send + + Sync + + AuxStore + + ProvideCache, Client::Api: BlockBuilderApi + BabeApi, SelectChain: sp_consensus::SelectChain, CAW: CanAuthorWith + Send + Sync, @@ -1089,7 +1103,7 @@ where header: Block::Header, justifications: Option, mut body: Option>, - ) -> Result<(BlockImportParams, Option)>>), String> { + ) -> BlockVerificationResult { trace!( target: "babe", "Verifying origin: {:?} header: {:?} justification(s): {:?} body: {:?}", @@ -1158,7 +1172,7 @@ where &header, &verified_info.author, &origin, - ) { + ).await { warn!(target: "babe", "Error checking/reporting BABE equivocation: {:?}", err); } diff --git a/substrate/client/consensus/common/Cargo.toml b/substrate/client/consensus/common/Cargo.toml index 5762b9c998..32babb02c2 100644 --- a/substrate/client/consensus/common/Cargo.toml +++ b/substrate/client/consensus/common/Cargo.toml @@ -13,6 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] +async-trait = "0.1" sc-client-api = { version = "3.0.0", path = "../../api" } sp-blockchain = { version = "3.0.0", path = "../../../primitives/blockchain" } sp-runtime = { version = "3.0.0", path = "../../../primitives/runtime" } diff --git a/substrate/client/consensus/common/src/longest_chain.rs b/substrate/client/consensus/common/src/longest_chain.rs index 8cf32a1dbd..e1fbb600fa 100644 --- a/substrate/client/consensus/common/src/longest_chain.rs +++ b/substrate/client/consensus/common/src/longest_chain.rs @@ -46,15 +46,15 @@ impl Clone for LongestChain { } impl LongestChain - where - B: backend::Backend, - Block: BlockT, +where + B: backend::Backend, + Block: BlockT, { /// Instantiate a new LongestChain for Backend B pub fn new(backend: Arc) -> Self { LongestChain { backend, - _phantom: Default::default() + _phantom: Default::default(), } } @@ -75,30 +75,30 @@ impl LongestChain } } +#[async_trait::async_trait] impl SelectChain for LongestChain - where - B: backend::Backend, - Block: BlockT, +where + B: backend::Backend, + Block: BlockT, { - - fn leaves(&self) -> Result::Hash>, ConsensusError> { - LongestChain::leaves(self) - .map_err(|e| ConsensusError::ChainLookup(e.to_string()).into()) + async fn leaves(&self) -> Result::Hash>, ConsensusError> { + LongestChain::leaves(self).map_err(|e| ConsensusError::ChainLookup(e.to_string()).into()) } - fn best_chain(&self) -> Result<::Header, ConsensusError> - { + async fn best_chain(&self) -> Result<::Header, ConsensusError> { LongestChain::best_block_header(&self) .map_err(|e| ConsensusError::ChainLookup(e.to_string()).into()) } - fn finality_target( + async fn finality_target( &self, target_hash: Block::Hash, - maybe_max_number: Option> + maybe_max_number: Option>, ) -> Result, ConsensusError> { let import_lock = self.backend.get_import_lock(); - self.backend.blockchain().best_containing(target_hash, maybe_max_number, import_lock) + self.backend + .blockchain() + .best_containing(target_hash, maybe_max_number, import_lock) .map_err(|e| ConsensusError::ChainLookup(e.to_string()).into()) } } diff --git a/substrate/client/consensus/manual-seal/src/seal_block.rs b/substrate/client/consensus/manual-seal/src/seal_block.rs index 4aecfc213a..6ddd2cb05d 100644 --- a/substrate/client/consensus/manual-seal/src/seal_block.rs +++ b/substrate/client/consensus/manual-seal/src/seal_block.rs @@ -80,45 +80,47 @@ pub async fn seal_block( create_inherent_data_providers, consensus_data_provider: digest_provider, mut sender, - }: SealBlockParams<'_, B, BI, SC, C, E, P, CIDP> -) - where - B: BlockT, - BI: BlockImport> - + Send + Sync + 'static, - C: HeaderBackend + ProvideRuntimeApi, - E: Environment, - E::Proposer: Proposer>, - P: txpool::ChainApi, - SC: SelectChain, - TransactionFor: 'static, - CIDP: CreateInherentDataProviders, + }: SealBlockParams<'_, B, BI, SC, C, E, P, CIDP>, +) where + B: BlockT, + BI: BlockImport> + + Send + + Sync + + 'static, + C: HeaderBackend + ProvideRuntimeApi, + E: Environment, + E::Proposer: Proposer>, + P: txpool::ChainApi, + SC: SelectChain, + TransactionFor: 'static, + CIDP: CreateInherentDataProviders, { let future = async { if pool.validated_pool().status().ready == 0 && !create_empty { - return Err(Error::EmptyTransactionPool) + return Err(Error::EmptyTransactionPool); } // get the header to build this new block on. // use the parent_hash supplied via `EngineCommand` // or fetch the best_block. let parent = match parent_hash { - Some(hash) => { - client.header(BlockId::Hash(hash))?.ok_or_else(|| Error::BlockNotFound(format!("{}", hash)))? - } - None => select_chain.best_chain()? + Some(hash) => client + .header(BlockId::Hash(hash))? + .ok_or_else(|| Error::BlockNotFound(format!("{}", hash)))?, + None => select_chain.best_chain().await?, }; - let inherent_data_providers = - create_inherent_data_providers - .create_inherent_data_providers(parent.hash(), ()) - .await - .map_err(|e| Error::Other(e))?; + let inherent_data_providers = create_inherent_data_providers + .create_inherent_data_providers(parent.hash(), ()) + .await + .map_err(|e| Error::Other(e))?; let inherent_data = inherent_data_providers.create_inherent_data()?; - let proposer = env.init(&parent) - .map_err(|err| Error::StringError(format!("{:?}", err))).await?; + let proposer = env + .init(&parent) + .map_err(|err| Error::StringError(format!("{:?}", err))) + .await?; let inherents_len = inherent_data.len(); let digest = if let Some(digest_provider) = digest_provider { diff --git a/substrate/client/consensus/pow/src/lib.rs b/substrate/client/consensus/pow/src/lib.rs index 6688c14b63..e71726564e 100644 --- a/substrate/client/consensus/pow/src/lib.rs +++ b/substrate/client/consensus/pow/src/lib.rs @@ -341,7 +341,10 @@ where mut block: BlockImportParams, new_cache: HashMap>, ) -> Result { - let best_header = self.select_chain.best_chain() + let best_header = self + .select_chain + .best_chain() + .await .map_err(|e| format!("Fetch best chain failed via select chain: {:?}", e))?; let best_hash = best_header.hash(); @@ -543,7 +546,8 @@ pub fn start_mining_worker( ) -> ( Arc>::Proof>>>, impl Future, -) where +) +where Block: BlockT, C: ProvideRuntimeApi + BlockchainEvents + 'static, S: SelectChain + 'static, @@ -578,7 +582,7 @@ pub fn start_mining_worker( return; } - let best_header = match select_chain.best_chain() { + let best_header = match select_chain.best_chain().await { Ok(x) => x, Err(err) => { warn!( @@ -588,7 +592,7 @@ pub fn start_mining_worker( err ); return; - }, + } }; let best_hash = best_header.hash(); diff --git a/substrate/client/consensus/slots/src/slots.rs b/substrate/client/consensus/slots/src/slots.rs index 665f7c58ba..1e6dadcdf5 100644 --- a/substrate/client/consensus/slots/src/slots.rs +++ b/substrate/client/consensus/slots/src/slots.rs @@ -151,7 +151,7 @@ where let ends_at = Instant::now() + ends_in; - let chain_head = match self.client.best_chain() { + let chain_head = match self.client.best_chain().await { Ok(x) => x, Err(e) => { log::warn!( diff --git a/substrate/client/finality-grandpa/src/environment.rs b/substrate/client/finality-grandpa/src/environment.rs index 62d9a4a8bb..77c7ccda7d 100644 --- a/substrate/client/finality-grandpa/src/environment.rs +++ b/substrate/client/finality-grandpa/src/environment.rs @@ -34,12 +34,12 @@ use parking_lot::RwLock; use prometheus_endpoint::{register, Counter, Gauge, PrometheusError, U64}; use sc_client_api::{ - backend::{apply_aux, Backend}, + backend::{apply_aux, Backend as BackendT}, utils::is_descendent_of, }; use sc_telemetry::{telemetry, TelemetryHandle, CONSENSUS_DEBUG, CONSENSUS_INFO}; use sp_blockchain::HeaderMetadata; -use sp_consensus::SelectChain; +use sp_consensus::SelectChain as SelectChainT; use sp_finality_grandpa::{ AuthorityId, AuthoritySignature, Equivocation, EquivocationProof, GrandpaApi, RoundNumber, SetId, GRANDPA_ENGINE_ID, @@ -54,7 +54,7 @@ use crate::{ local_authority_id, notification::GrandpaJustificationSender, until_imported::UntilVoteTargetImported, - voting_rule::VotingRule, + voting_rule::VotingRule as VotingRuleT, ClientForGrandpa, CommandOrError, Commit, Config, Error, NewAuthoritySet, Precommit, Prevote, PrimaryPropose, SignedMessage, VoterCommand, }; @@ -478,11 +478,11 @@ impl, SC, VR> Environment Environment where Block: BlockT, - BE: Backend, + BE: BackendT, C: ClientForGrandpa, C::Api: GrandpaApi, N: NetworkT, - SC: SelectChain, + SC: SelectChainT, { /// Report the given equivocation to the GRANDPA runtime module. This method /// generates a session membership proof of the offender and then submits an @@ -503,9 +503,12 @@ where let is_descendent_of = is_descendent_of(&*self.client, None); - let best_header = self.select_chain - .best_chain() - .map_err(|e| Error::Blockchain(e.to_string()))?; + // TODO: add proper async support here + let best_header = futures::executor::block_on( + self.select_chain + .best_chain() + .map_err(|e| Error::Blockchain(e.to_string())), + )?; let authority_set = self.authority_set.inner(); @@ -581,11 +584,11 @@ impl finality_grandpa::Chain where Block: BlockT, - BE: Backend, + BE: BackendT, C: ClientForGrandpa, N: NetworkT, - SC: SelectChain, - VR: VotingRule, + SC: SelectChainT, + VR: VotingRuleT, NumberFor: BlockNumberOps, { fn ancestry( @@ -637,12 +640,12 @@ impl voter::Environment> for Environment where Block: BlockT, - B: Backend, + B: BackendT, C: ClientForGrandpa + 'static, C::Api: GrandpaApi, N: NetworkT, - SC: SelectChain, - VR: VotingRule, + SC: SelectChainT + 'static, + VR: VotingRuleT + Clone + 'static, NumberFor: BlockNumberOps, { type Timer = Pin> + Send>>; @@ -684,116 +687,25 @@ where type Error = CommandOrError>; fn best_chain_containing(&self, block: Block::Hash) -> Self::BestChain { - let find_best_chain = || { + let client = self.client.clone(); + let authority_set = self.authority_set.clone(); + let select_chain = self.select_chain.clone(); + let voting_rule = self.voting_rule.clone(); + let set_id = self.set_id; + + Box::pin(async move { // NOTE: when we finalize an authority set change through the sync protocol the voter is // signaled asynchronously. therefore the voter could still vote in the next round - // before activating the new set. the `authority_set` is updated immediately thus we - // restrict the voter based on that. - if self.set_id != self.authority_set.set_id() { - return None; + // before activating the new set. the `authority_set` is updated immediately thus + // we restrict the voter based on that. + if set_id != authority_set.set_id() { + return Ok(None); } - 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); - return None; - } - }; - - // we refuse to vote beyond the current limit number where transitions are scheduled to - // occur. - // once blocks are finalized that make that transition irrelevant or activate it, - // we will proceed onwards. most of the time there will be no pending transition. - // the limit, if any, is guaranteed to be higher than or equal to the given base number. - let limit = self.authority_set.current_limit(*base_header.number()); - debug!(target: "afg", "Finding best chain containing block {:?} with number limit {:?}", block, limit); - - match self.select_chain.finality_target(block, None) { - Ok(Some(best_hash)) => { - 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 - let limit = limit.filter(|limit| limit < best_header.number()); - - if let Some(target_number) = limit { - let mut target_header = best_header.clone(); - - // walk backwards until we find the target block - loop { - if *target_header.number() < target_number { - unreachable!( - "we are traversing backwards from a known block; \ - blocks are stored contiguously; \ - qed" - ); - } - - if *target_header.number() == target_number { - break; - } - - target_header = self - .client - .header(BlockId::Hash(*target_header.parent_hash())) - .ok()? - .expect("Header known to exist after `finality_target` call; qed"); - } - - Some((base_header, best_header, target_header)) - } else { - // otherwise just use the given best as the target - Some((base_header, best_header.clone(), best_header)) - } - } - Ok(None) => { - debug!(target: "afg", "Encountered error finding best chain containing {:?}: couldn't find target block", block); - None - } - Err(e) => { - debug!(target: "afg", "Encountered error finding best chain containing {:?}: {:?}", block, e); - None - } - } - }; - - if let Some((base_header, best_header, target_header)) = find_best_chain() { - // restrict vote according to the given voting rule, if the - // voting rule doesn't restrict the vote then we keep the - // previous target. - // - // note that we pass the original `best_header`, i.e. before the - // authority set limit filter, which can be considered a - // mandatory/implicit voting rule. - // - // we also make sure that the restricted vote is higher than the - // round base (i.e. last finalized), otherwise the value - // returned by the given voting rule is ignored and the original - // target is used instead. - let rule_fut = self.voting_rule.restrict_vote( - self.client.clone(), - &base_header, - &best_header, - &target_header, - ); - - Box::pin(async move { - Ok(rule_fut - .await - .filter(|(_, restricted_number)| { - // we can only restrict votes within the interval [base, target] - restricted_number >= base_header.number() - && restricted_number < target_header.number() - }) - .or_else(|| Some((target_header.hash(), *target_header.number())))) - }) - } else { - Box::pin(future::ok(None)) - } + best_chain_containing(block, client, authority_set, select_chain, voting_rule) + .await + .map_err(|e| e.into()) + }) } fn round_data( @@ -1227,6 +1139,111 @@ impl From> for JustificationOrCommit< } } +async fn best_chain_containing( + block: Block::Hash, + client: Arc, + authority_set: SharedAuthoritySet>, + select_chain: SelectChain, + voting_rule: VotingRule, +) -> Result)>, Error> +where + Backend: BackendT, + Block: BlockT, + Client: ClientForGrandpa, + SelectChain: SelectChainT + 'static, + VotingRule: VotingRuleT, +{ + let base_header = match client.header(BlockId::Hash(block))? { + Some(h) => h, + None => { + debug!(target: "afg", + "Encountered error finding best chain containing {:?}: couldn't find base block", + block, + ); + + return Ok(None); + } + }; + + // we refuse to vote beyond the current limit number where transitions are scheduled to occur. + // once blocks are finalized that make that transition irrelevant or activate it, we will + // proceed onwards. most of the time there will be no pending transition. the limit, if any, is + // guaranteed to be higher than or equal to the given base number. + let limit = authority_set.current_limit(*base_header.number()); + debug!(target: "afg", "Finding best chain containing block {:?} with number limit {:?}", block, limit); + + let result = match select_chain.finality_target(block, None).await { + Ok(Some(best_hash)) => { + let best_header = client + .header(BlockId::Hash(best_hash))? + .expect("Header known to exist after `finality_target` call; qed"); + + // check if our vote is currently being limited due to a pending change + let limit = limit.filter(|limit| limit < best_header.number()); + + let (base_header, best_header, target_header) = if let Some(target_number) = limit { + let mut target_header = best_header.clone(); + + // walk backwards until we find the target block + loop { + if *target_header.number() < target_number { + unreachable!( + "we are traversing backwards from a known block; \ + blocks are stored contiguously; \ + qed" + ); + } + + if *target_header.number() == target_number { + break; + } + + target_header = client + .header(BlockId::Hash(*target_header.parent_hash()))? + .expect("Header known to exist after `finality_target` call; qed"); + } + + (base_header, best_header, target_header) + } else { + // otherwise just use the given best as the target + (base_header, best_header.clone(), best_header) + }; + + // restrict vote according to the given voting rule, if the + // voting rule doesn't restrict the vote then we keep the + // previous target. + // + // note that we pass the original `best_header`, i.e. before the + // authority set limit filter, which can be considered a + // mandatory/implicit voting rule. + // + // we also make sure that the restricted vote is higher than the + // round base (i.e. last finalized), otherwise the value + // returned by the given voting rule is ignored and the original + // target is used instead. + voting_rule + .restrict_vote(client.clone(), &base_header, &best_header, &target_header) + .await + .filter(|(_, restricted_number)| { + // we can only restrict votes within the interval [base, target] + restricted_number >= base_header.number() && + restricted_number < target_header.number() + }) + .or_else(|| Some((target_header.hash(), *target_header.number()))) + } + Ok(None) => { + debug!(target: "afg", "Encountered error finding best chain containing {:?}: couldn't find target block", block); + None + } + Err(e) => { + debug!(target: "afg", "Encountered error finding best chain containing {:?}: {:?}", block, e); + None + } + }; + + Ok(result) +} + /// Finalize the given block and apply any authority set changes. If an /// authority set change is enacted then a justification is created (if not /// given) and stored with the block when finalizing it. @@ -1244,7 +1261,7 @@ pub(crate) fn finalize_block( ) -> Result<(), CommandOrError>> where Block: BlockT, - BE: Backend, + BE: BackendT, Client: ClientForGrandpa, { // NOTE: lock must be held through writing to DB to avoid race. this lock diff --git a/substrate/client/finality-grandpa/src/import.rs b/substrate/client/finality-grandpa/src/import.rs index de02ea357c..481f38b617 100644 --- a/substrate/client/finality-grandpa/src/import.rs +++ b/substrate/client/finality-grandpa/src/import.rs @@ -81,6 +81,7 @@ impl Clone } } +#[async_trait::async_trait] impl JustificationImport for GrandpaBlockImport where @@ -92,22 +93,30 @@ where { type Error = ConsensusError; - fn on_start(&mut self) -> Vec<(Block::Hash, NumberFor)> { + async fn on_start(&mut self) -> Vec<(Block::Hash, NumberFor)> { let mut out = Vec::new(); 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(); - for pending_change in authorities.pending_changes() { + let pending_changes: Vec<_> = self + .authority_set + .inner() + .pending_changes() + .cloned() + .collect(); + + for pending_change in pending_changes { if pending_change.delay_kind == DelayKind::Finalized && pending_change.effective_number() > chain_info.finalized_number && pending_change.effective_number() <= chain_info.best_number { let effective_block_hash = if !pending_change.delay.is_zero() { - self.select_chain.finality_target( - pending_change.canon_hash, - Some(pending_change.effective_number()), - ) + self.select_chain + .finality_target( + pending_change.canon_hash, + Some(pending_change.effective_number()), + ) + .await } else { Ok(Some(pending_change.canon_hash)) }; @@ -125,7 +134,7 @@ where out } - fn import_justification( + async fn import_justification( &mut self, hash: Block::Hash, number: NumberFor, diff --git a/substrate/client/network/test/src/lib.rs b/substrate/client/network/test/src/lib.rs index 8e56005dad..f55444f8cf 100644 --- a/substrate/client/network/test/src/lib.rs +++ b/substrate/client/network/test/src/lib.rs @@ -1075,10 +1075,15 @@ impl TestNetFactory for TestNet { pub struct ForceFinalized(PeersClient); +#[async_trait::async_trait] impl JustificationImport for ForceFinalized { type Error = ConsensusError; - fn import_justification( + async fn on_start(&mut self) -> Vec<(H256, NumberFor)> { + Vec::new() + } + + async fn import_justification( &mut self, hash: H256, _number: NumberFor, diff --git a/substrate/client/service/src/lib.rs b/substrate/client/service/src/lib.rs index afc1209280..c8ac03ee0e 100644 --- a/substrate/client/service/src/lib.rs +++ b/substrate/client/service/src/lib.rs @@ -561,13 +561,14 @@ mod tests { client.clone(), ); let source = sp_runtime::transaction_validity::TransactionSource::External; - let best = longest_chain.best_chain().unwrap(); + let best = block_on(longest_chain.best_chain()).unwrap(); let transaction = Transfer { amount: 5, nonce: 0, from: AccountKeyring::Alice.into(), to: Default::default(), - }.into_signed_tx(); + } + .into_signed_tx(); block_on(pool.submit_one( &BlockId::hash(best.hash()), source, transaction.clone()), ).unwrap(); diff --git a/substrate/client/service/test/src/client/mod.rs b/substrate/client/service/test/src/client/mod.rs index 3852ab2d61..bf4105377f 100644 --- a/substrate/client/service/test/src/client/mod.rs +++ b/substrate/client/service/test/src/client/mod.rs @@ -337,7 +337,6 @@ fn construct_genesis_with_bad_transaction_should_panic() { assert!(r.is_err()); } - #[test] fn client_initializes_from_genesis_ok() { let client = substrate_test_runtime_client::new(); @@ -450,7 +449,9 @@ fn best_containing_with_genesis_block() { assert_eq!( genesis_hash.clone(), - longest_chain_select.finality_target(genesis_hash.clone(), None).unwrap().unwrap() + block_on(longest_chain_select.finality_target(genesis_hash.clone(), None)) + .unwrap() + .unwrap(), ); } @@ -461,11 +462,17 @@ fn best_containing_with_hash_not_found() { let (client, longest_chain_select) = TestClientBuilder::new().build_with_longest_chain(); - let uninserted_block = client.new_block(Default::default()).unwrap().build().unwrap().block; + let uninserted_block = client + .new_block(Default::default()) + .unwrap() + .build() + .unwrap() + .block; assert_eq!( None, - longest_chain_select.finality_target(uninserted_block.hash().clone(), None).unwrap() + block_on(longest_chain_select.finality_target(uninserted_block.hash().clone(), None)) + .unwrap(), ); } @@ -624,18 +631,43 @@ fn best_containing_on_longest_chain_with_single_chain_3_blocks() { let (mut client, longest_chain_select) = TestClientBuilder::new().build_with_longest_chain(); // G -> A1 - let a1 = client.new_block(Default::default()).unwrap().build().unwrap().block; + let a1 = client + .new_block(Default::default()) + .unwrap() + .build() + .unwrap() + .block; block_on(client.import(BlockOrigin::Own, a1.clone())).unwrap(); // A1 -> A2 - let a2 = client.new_block(Default::default()).unwrap().build().unwrap().block; + let a2 = client + .new_block(Default::default()) + .unwrap() + .build() + .unwrap() + .block; block_on(client.import(BlockOrigin::Own, a2.clone())).unwrap(); let genesis_hash = client.chain_info().genesis_hash; - assert_eq!(a2.hash(), longest_chain_select.finality_target(genesis_hash, None).unwrap().unwrap()); - assert_eq!(a2.hash(), longest_chain_select.finality_target(a1.hash(), None).unwrap().unwrap()); - assert_eq!(a2.hash(), longest_chain_select.finality_target(a2.hash(), None).unwrap().unwrap()); + assert_eq!( + a2.hash(), + block_on(longest_chain_select.finality_target(genesis_hash, None)) + .unwrap() + .unwrap() + ); + assert_eq!( + a2.hash(), + block_on(longest_chain_select.finality_target(a1.hash(), None)) + .unwrap() + .unwrap() + ); + assert_eq!( + a2.hash(), + block_on(longest_chain_select.finality_target(a2.hash(), None)) + .unwrap() + .unwrap() + ); } #[test] @@ -715,19 +747,19 @@ fn best_containing_on_longest_chain_with_multiple_forks() { ).unwrap().build().unwrap().block; block_on(client.import(BlockOrigin::Own, b4.clone())).unwrap(); - // // B2 -> C3 - let mut builder = client.new_block_at( - &BlockId::Hash(b2.hash()), - Default::default(), - false, - ).unwrap(); + // B2 -> C3 + let mut builder = client + .new_block_at(&BlockId::Hash(b2.hash()), Default::default(), false) + .unwrap(); // this push is required as otherwise C3 has the same hash as B3 and won't get imported - builder.push_transfer(Transfer { - from: AccountKeyring::Alice.into(), - to: AccountKeyring::Ferdie.into(), - amount: 1, - nonce: 1, - }).unwrap(); + builder + .push_transfer(Transfer { + from: AccountKeyring::Alice.into(), + to: AccountKeyring::Ferdie.into(), + amount: 1, + nonce: 1, + }) + .unwrap(); let c3 = builder.build().unwrap().block; block_on(client.import(BlockOrigin::Own, c3.clone())).unwrap(); @@ -750,7 +782,7 @@ fn best_containing_on_longest_chain_with_multiple_forks() { assert_eq!(client.chain_info().best_hash, a5.hash()); let genesis_hash = client.chain_info().genesis_hash; - let leaves = longest_chain_select.leaves().unwrap(); + let leaves = block_on(longest_chain_select.leaves()).unwrap(); assert!(leaves.contains(&a5.hash())); assert!(leaves.contains(&b4.hash())); @@ -759,208 +791,422 @@ fn best_containing_on_longest_chain_with_multiple_forks() { assert_eq!(leaves.len(), 4); // search without restriction - - assert_eq!(a5.hash(), longest_chain_select.finality_target( - genesis_hash, None).unwrap().unwrap()); - assert_eq!(a5.hash(), longest_chain_select.finality_target( - a1.hash(), None).unwrap().unwrap()); - assert_eq!(a5.hash(), longest_chain_select.finality_target( - a2.hash(), None).unwrap().unwrap()); - assert_eq!(a5.hash(), longest_chain_select.finality_target( - a3.hash(), None).unwrap().unwrap()); - assert_eq!(a5.hash(), longest_chain_select.finality_target( - a4.hash(), None).unwrap().unwrap()); - assert_eq!(a5.hash(), longest_chain_select.finality_target( - a5.hash(), None).unwrap().unwrap()); - - assert_eq!(b4.hash(), longest_chain_select.finality_target( - b2.hash(), None).unwrap().unwrap()); - assert_eq!(b4.hash(), longest_chain_select.finality_target( - b3.hash(), None).unwrap().unwrap()); - assert_eq!(b4.hash(), longest_chain_select.finality_target( - b4.hash(), None).unwrap().unwrap()); - - assert_eq!(c3.hash(), longest_chain_select.finality_target( - c3.hash(), None).unwrap().unwrap()); - - assert_eq!(d2.hash(), longest_chain_select.finality_target( - d2.hash(), None).unwrap().unwrap()); - + assert_eq!( + a5.hash(), + block_on(longest_chain_select.finality_target(genesis_hash, None)) + .unwrap() + .unwrap() + ); + assert_eq!( + a5.hash(), + block_on(longest_chain_select.finality_target(a1.hash(), None)) + .unwrap() + .unwrap() + ); + assert_eq!( + a5.hash(), + block_on(longest_chain_select.finality_target(a2.hash(), None)) + .unwrap() + .unwrap() + ); + assert_eq!( + a5.hash(), + block_on(longest_chain_select.finality_target(a3.hash(), None)) + .unwrap() + .unwrap() + ); + assert_eq!( + a5.hash(), + block_on(longest_chain_select.finality_target(a4.hash(), None)) + .unwrap() + .unwrap() + ); + assert_eq!( + a5.hash(), + block_on(longest_chain_select.finality_target(a5.hash(), None)) + .unwrap() + .unwrap() + ); + assert_eq!( + b4.hash(), + block_on(longest_chain_select.finality_target(b2.hash(), None)) + .unwrap() + .unwrap() + ); + assert_eq!( + b4.hash(), + block_on(longest_chain_select.finality_target(b3.hash(), None)) + .unwrap() + .unwrap() + ); + assert_eq!( + b4.hash(), + block_on(longest_chain_select.finality_target(b4.hash(), None)) + .unwrap() + .unwrap() + ); + assert_eq!( + c3.hash(), + block_on(longest_chain_select.finality_target(c3.hash(), None)) + .unwrap() + .unwrap() + ); + assert_eq!( + d2.hash(), + block_on(longest_chain_select.finality_target(d2.hash(), None)) + .unwrap() + .unwrap() + ); // search only blocks with number <= 5. equivalent to without restriction for this scenario - - assert_eq!(a5.hash(), longest_chain_select.finality_target( - genesis_hash, Some(5)).unwrap().unwrap()); - assert_eq!(a5.hash(), longest_chain_select.finality_target( - a1.hash(), Some(5)).unwrap().unwrap()); - assert_eq!(a5.hash(), longest_chain_select.finality_target( - a2.hash(), Some(5)).unwrap().unwrap()); - assert_eq!(a5.hash(), longest_chain_select.finality_target( - a3.hash(), Some(5)).unwrap().unwrap()); - assert_eq!(a5.hash(), longest_chain_select.finality_target( - a4.hash(), Some(5)).unwrap().unwrap()); - assert_eq!(a5.hash(), longest_chain_select.finality_target( - a5.hash(), Some(5)).unwrap().unwrap()); - - assert_eq!(b4.hash(), longest_chain_select.finality_target( - b2.hash(), Some(5)).unwrap().unwrap()); - assert_eq!(b4.hash(), longest_chain_select.finality_target( - b3.hash(), Some(5)).unwrap().unwrap()); - assert_eq!(b4.hash(), longest_chain_select.finality_target( - b4.hash(), Some(5)).unwrap().unwrap()); - - assert_eq!(c3.hash(), longest_chain_select.finality_target( - c3.hash(), Some(5)).unwrap().unwrap()); - - assert_eq!(d2.hash(), longest_chain_select.finality_target( - d2.hash(), Some(5)).unwrap().unwrap()); - + assert_eq!( + a5.hash(), + block_on(longest_chain_select.finality_target(genesis_hash, Some(5))) + .unwrap() + .unwrap() + ); + assert_eq!( + a5.hash(), + block_on(longest_chain_select.finality_target(a1.hash(), Some(5))) + .unwrap() + .unwrap() + ); + assert_eq!( + a5.hash(), + block_on(longest_chain_select.finality_target(a2.hash(), Some(5))) + .unwrap() + .unwrap() + ); + assert_eq!( + a5.hash(), + block_on(longest_chain_select.finality_target(a3.hash(), Some(5))) + .unwrap() + .unwrap() + ); + assert_eq!( + a5.hash(), + block_on(longest_chain_select.finality_target(a4.hash(), Some(5))) + .unwrap() + .unwrap() + ); + assert_eq!( + a5.hash(), + block_on(longest_chain_select.finality_target(a5.hash(), Some(5))) + .unwrap() + .unwrap() + ); + assert_eq!( + b4.hash(), + block_on(longest_chain_select.finality_target(b2.hash(), Some(5))) + .unwrap() + .unwrap() + ); + assert_eq!( + b4.hash(), + block_on(longest_chain_select.finality_target(b3.hash(), Some(5))) + .unwrap() + .unwrap() + ); + assert_eq!( + b4.hash(), + block_on(longest_chain_select.finality_target(b4.hash(), Some(5))) + .unwrap() + .unwrap() + ); + assert_eq!( + c3.hash(), + block_on(longest_chain_select.finality_target(c3.hash(), Some(5))) + .unwrap() + .unwrap() + ); + assert_eq!( + d2.hash(), + block_on(longest_chain_select.finality_target(d2.hash(), Some(5))) + .unwrap() + .unwrap() + ); // search only blocks with number <= 4 - - assert_eq!(a4.hash(), longest_chain_select.finality_target( - genesis_hash, Some(4)).unwrap().unwrap()); - assert_eq!(a4.hash(), longest_chain_select.finality_target( - a1.hash(), Some(4)).unwrap().unwrap()); - assert_eq!(a4.hash(), longest_chain_select.finality_target( - a2.hash(), Some(4)).unwrap().unwrap()); - assert_eq!(a4.hash(), longest_chain_select.finality_target( - a3.hash(), Some(4)).unwrap().unwrap()); - assert_eq!(a4.hash(), longest_chain_select.finality_target( - a4.hash(), Some(4)).unwrap().unwrap()); - assert_eq!(None, longest_chain_select.finality_target( - a5.hash(), Some(4)).unwrap()); - - assert_eq!(b4.hash(), longest_chain_select.finality_target( - b2.hash(), Some(4)).unwrap().unwrap()); - assert_eq!(b4.hash(), longest_chain_select.finality_target( - b3.hash(), Some(4)).unwrap().unwrap()); - assert_eq!(b4.hash(), longest_chain_select.finality_target( - b4.hash(), Some(4)).unwrap().unwrap()); - - assert_eq!(c3.hash(), longest_chain_select.finality_target( - c3.hash(), Some(4)).unwrap().unwrap()); - - assert_eq!(d2.hash(), longest_chain_select.finality_target( - d2.hash(), Some(4)).unwrap().unwrap()); - - - // search only blocks with number <= 3 - - assert_eq!(a3.hash(), longest_chain_select.finality_target( - genesis_hash, Some(3)).unwrap().unwrap()); - assert_eq!(a3.hash(), longest_chain_select.finality_target( - a1.hash(), Some(3)).unwrap().unwrap()); - assert_eq!(a3.hash(), longest_chain_select.finality_target( - a2.hash(), Some(3)).unwrap().unwrap()); - assert_eq!(a3.hash(), longest_chain_select.finality_target( - a3.hash(), Some(3)).unwrap().unwrap()); - assert_eq!(None, longest_chain_select.finality_target( - a4.hash(), Some(3)).unwrap()); - assert_eq!(None, longest_chain_select.finality_target( - a5.hash(), Some(3)).unwrap()); - - assert_eq!(b3.hash(), longest_chain_select.finality_target( - b2.hash(), Some(3)).unwrap().unwrap()); - assert_eq!(b3.hash(), longest_chain_select.finality_target( - b3.hash(), Some(3)).unwrap().unwrap()); - assert_eq!(None, longest_chain_select.finality_target( - b4.hash(), Some(3)).unwrap()); - - assert_eq!(c3.hash(), longest_chain_select.finality_target( - c3.hash(), Some(3)).unwrap().unwrap()); - - assert_eq!(d2.hash(), longest_chain_select.finality_target( - d2.hash(), Some(3)).unwrap().unwrap()); - - - // search only blocks with number <= 2 - - assert_eq!(a2.hash(), longest_chain_select.finality_target( - genesis_hash, Some(2)).unwrap().unwrap()); - assert_eq!(a2.hash(), longest_chain_select.finality_target( - a1.hash(), Some(2)).unwrap().unwrap()); - assert_eq!(a2.hash(), longest_chain_select.finality_target( - a2.hash(), Some(2)).unwrap().unwrap()); - assert_eq!(None, longest_chain_select.finality_target( - a3.hash(), Some(2)).unwrap()); - assert_eq!(None, longest_chain_select.finality_target( - a4.hash(), Some(2)).unwrap()); - assert_eq!(None, longest_chain_select.finality_target( - a5.hash(), Some(2)).unwrap()); - - assert_eq!(b2.hash(), longest_chain_select.finality_target( - b2.hash(), Some(2)).unwrap().unwrap()); - assert_eq!(None, longest_chain_select.finality_target( - b3.hash(), Some(2)).unwrap()); - assert_eq!(None, longest_chain_select.finality_target( - b4.hash(), Some(2)).unwrap()); - - assert_eq!(None, longest_chain_select.finality_target( - c3.hash(), Some(2)).unwrap()); - - assert_eq!(d2.hash(), longest_chain_select.finality_target( - d2.hash(), Some(2)).unwrap().unwrap()); - - - // search only blocks with number <= 1 - - assert_eq!(a1.hash(), longest_chain_select.finality_target( - genesis_hash, Some(1)).unwrap().unwrap()); - assert_eq!(a1.hash(), longest_chain_select.finality_target( - a1.hash(), Some(1)).unwrap().unwrap()); - assert_eq!(None, longest_chain_select.finality_target( - a2.hash(), Some(1)).unwrap()); - assert_eq!(None, longest_chain_select.finality_target( - a3.hash(), Some(1)).unwrap()); - assert_eq!(None, longest_chain_select.finality_target( - a4.hash(), Some(1)).unwrap()); - assert_eq!(None, longest_chain_select.finality_target( - a5.hash(), Some(1)).unwrap()); - - assert_eq!(None, longest_chain_select.finality_target( - b2.hash(), Some(1)).unwrap()); - assert_eq!(None, longest_chain_select.finality_target( - b3.hash(), Some(1)).unwrap()); - assert_eq!(None, longest_chain_select.finality_target( - b4.hash(), Some(1)).unwrap()); - - assert_eq!(None, longest_chain_select.finality_target( - c3.hash(), Some(1)).unwrap()); - - assert_eq!(None, longest_chain_select.finality_target( - d2.hash(), Some(1)).unwrap()); - - // search only blocks with number <= 0 - - assert_eq!(genesis_hash, longest_chain_select.finality_target( - genesis_hash, Some(0)).unwrap().unwrap()); - assert_eq!(None, longest_chain_select.finality_target( - a1.hash(), Some(0)).unwrap()); - assert_eq!(None, longest_chain_select.finality_target( - a2.hash(), Some(0)).unwrap()); - assert_eq!(None, longest_chain_select.finality_target( - a3.hash(), Some(0)).unwrap()); - assert_eq!(None, longest_chain_select.finality_target( - a4.hash(), Some(0)).unwrap()); - assert_eq!(None, longest_chain_select.finality_target( - a5.hash(), Some(0)).unwrap()); - - assert_eq!(None, longest_chain_select.finality_target( - b2.hash(), Some(0)).unwrap()); - assert_eq!(None, longest_chain_select.finality_target( - b3.hash(), Some(0)).unwrap()); - assert_eq!(None, longest_chain_select.finality_target( - b4.hash(), Some(0)).unwrap()); - + assert_eq!( + a4.hash(), + block_on(longest_chain_select.finality_target(genesis_hash, Some(4))) + .unwrap() + .unwrap() + ); + assert_eq!( + a4.hash(), + block_on(longest_chain_select.finality_target(a1.hash(), Some(4))) + .unwrap() + .unwrap() + ); + assert_eq!( + a4.hash(), + block_on(longest_chain_select.finality_target(a2.hash(), Some(4))) + .unwrap() + .unwrap() + ); + assert_eq!( + a4.hash(), + block_on(longest_chain_select.finality_target(a3.hash(), Some(4))) + .unwrap() + .unwrap() + ); + assert_eq!( + a4.hash(), + block_on(longest_chain_select.finality_target(a4.hash(), Some(4))) + .unwrap() + .unwrap() + ); assert_eq!( None, - longest_chain_select.finality_target(c3.hash().clone(), Some(0)).unwrap(), + block_on(longest_chain_select.finality_target(a5.hash(), Some(4))).unwrap() + ); + assert_eq!( + b4.hash(), + block_on(longest_chain_select.finality_target(b2.hash(), Some(4))) + .unwrap() + .unwrap() + ); + assert_eq!( + b4.hash(), + block_on(longest_chain_select.finality_target(b3.hash(), Some(4))) + .unwrap() + .unwrap() + ); + assert_eq!( + b4.hash(), + block_on(longest_chain_select.finality_target(b4.hash(), Some(4))) + .unwrap() + .unwrap() + ); + assert_eq!( + c3.hash(), + block_on(longest_chain_select.finality_target(c3.hash(), Some(4))) + .unwrap() + .unwrap() + ); + assert_eq!( + d2.hash(), + block_on(longest_chain_select.finality_target(d2.hash(), Some(4))) + .unwrap() + .unwrap() + ); + + // search only blocks with number <= 3 + assert_eq!( + a3.hash(), + block_on(longest_chain_select.finality_target(genesis_hash, Some(3))) + .unwrap() + .unwrap() + ); + assert_eq!( + a3.hash(), + block_on(longest_chain_select.finality_target(a1.hash(), Some(3))) + .unwrap() + .unwrap() + ); + assert_eq!( + a3.hash(), + block_on(longest_chain_select.finality_target(a2.hash(), Some(3))) + .unwrap() + .unwrap() + ); + assert_eq!( + a3.hash(), + block_on(longest_chain_select.finality_target(a3.hash(), Some(3))) + .unwrap() + .unwrap() + ); + assert_eq!( + None, + block_on(longest_chain_select.finality_target(a4.hash(), Some(3))).unwrap() + ); + assert_eq!( + None, + block_on(longest_chain_select.finality_target(a5.hash(), Some(3))).unwrap() + ); + assert_eq!( + b3.hash(), + block_on(longest_chain_select.finality_target(b2.hash(), Some(3))) + .unwrap() + .unwrap() + ); + assert_eq!( + b3.hash(), + block_on(longest_chain_select.finality_target(b3.hash(), Some(3))) + .unwrap() + .unwrap() + ); + assert_eq!( + None, + block_on(longest_chain_select.finality_target(b4.hash(), Some(3))).unwrap() + ); + assert_eq!( + c3.hash(), + block_on(longest_chain_select.finality_target(c3.hash(), Some(3))) + .unwrap() + .unwrap() + ); + assert_eq!( + d2.hash(), + block_on(longest_chain_select.finality_target(d2.hash(), Some(3))) + .unwrap() + .unwrap() + ); + + // search only blocks with number <= 2 + assert_eq!( + a2.hash(), + block_on(longest_chain_select.finality_target(genesis_hash, Some(2))) + .unwrap() + .unwrap() + ); + assert_eq!( + a2.hash(), + block_on(longest_chain_select.finality_target(a1.hash(), Some(2))) + .unwrap() + .unwrap() + ); + assert_eq!( + a2.hash(), + block_on(longest_chain_select.finality_target(a2.hash(), Some(2))) + .unwrap() + .unwrap() + ); + assert_eq!( + None, + block_on(longest_chain_select.finality_target(a3.hash(), Some(2))).unwrap() + ); + assert_eq!( + None, + block_on(longest_chain_select.finality_target(a4.hash(), Some(2))).unwrap() + ); + assert_eq!( + None, + block_on(longest_chain_select.finality_target(a5.hash(), Some(2))).unwrap() + ); + assert_eq!( + b2.hash(), + block_on(longest_chain_select.finality_target(b2.hash(), Some(2))) + .unwrap() + .unwrap() + ); + assert_eq!( + None, + block_on(longest_chain_select.finality_target(b3.hash(), Some(2))).unwrap() + ); + assert_eq!( + None, + block_on(longest_chain_select.finality_target(b4.hash(), Some(2))).unwrap() + ); + assert_eq!( + None, + block_on(longest_chain_select.finality_target(c3.hash(), Some(2))).unwrap() + ); + assert_eq!( + d2.hash(), + block_on(longest_chain_select.finality_target(d2.hash(), Some(2))) + .unwrap() + .unwrap() + ); + + // search only blocks with number <= 1 + assert_eq!( + a1.hash(), + block_on(longest_chain_select.finality_target(genesis_hash, Some(1))) + .unwrap() + .unwrap() + ); + assert_eq!( + a1.hash(), + block_on(longest_chain_select.finality_target(a1.hash(), Some(1))) + .unwrap() + .unwrap() + ); + assert_eq!( + None, + block_on(longest_chain_select.finality_target(a2.hash(), Some(1))).unwrap() + ); + assert_eq!( + None, + block_on(longest_chain_select.finality_target(a3.hash(), Some(1))).unwrap() + ); + assert_eq!( + None, + block_on(longest_chain_select.finality_target(a4.hash(), Some(1))).unwrap() + ); + assert_eq!( + None, + block_on(longest_chain_select.finality_target(a5.hash(), Some(1))).unwrap() ); assert_eq!( None, - longest_chain_select.finality_target(d2.hash().clone(), Some(0)).unwrap(), + block_on(longest_chain_select.finality_target(b2.hash(), Some(1))).unwrap() + ); + assert_eq!( + None, + block_on(longest_chain_select.finality_target(b3.hash(), Some(1))).unwrap() + ); + assert_eq!( + None, + block_on(longest_chain_select.finality_target(b4.hash(), Some(1))).unwrap() + ); + assert_eq!( + None, + block_on(longest_chain_select.finality_target(c3.hash(), Some(1))).unwrap() + ); + assert_eq!( + None, + block_on(longest_chain_select.finality_target(d2.hash(), Some(1))).unwrap() + ); + + // search only blocks with number <= 0 + assert_eq!( + genesis_hash, + block_on(longest_chain_select.finality_target(genesis_hash, Some(0))) + .unwrap() + .unwrap() + ); + assert_eq!( + None, + block_on(longest_chain_select.finality_target(a1.hash(), Some(0))).unwrap() + ); + assert_eq!( + None, + block_on(longest_chain_select.finality_target(a2.hash(), Some(0))).unwrap() + ); + assert_eq!( + None, + block_on(longest_chain_select.finality_target(a3.hash(), Some(0))).unwrap() + ); + assert_eq!( + None, + block_on(longest_chain_select.finality_target(a4.hash(), Some(0))).unwrap() + ); + assert_eq!( + None, + block_on(longest_chain_select.finality_target(a5.hash(), Some(0))).unwrap() + ); + assert_eq!( + None, + block_on(longest_chain_select.finality_target(b2.hash(), Some(0))).unwrap() + ); + assert_eq!( + None, + block_on(longest_chain_select.finality_target(b3.hash(), Some(0))).unwrap() + ); + assert_eq!( + None, + block_on(longest_chain_select.finality_target(b4.hash(), Some(0))).unwrap() + ); + assert_eq!( + None, + block_on(longest_chain_select.finality_target(c3.hash().clone(), Some(0))).unwrap(), + ); + assert_eq!( + None, + block_on(longest_chain_select.finality_target(d2.hash().clone(), Some(0))).unwrap(), ); } @@ -972,18 +1218,30 @@ fn best_containing_on_longest_chain_with_max_depth_higher_than_best() { let (mut client, longest_chain_select) = TestClientBuilder::new().build_with_longest_chain(); // G -> A1 - let a1 = client.new_block(Default::default()).unwrap().build().unwrap().block; + let a1 = client + .new_block(Default::default()) + .unwrap() + .build() + .unwrap() + .block; block_on(client.import(BlockOrigin::Own, a1.clone())).unwrap(); // A1 -> A2 - let a2 = client.new_block(Default::default()).unwrap().build().unwrap().block; + let a2 = client + .new_block(Default::default()) + .unwrap() + .build() + .unwrap() + .block; block_on(client.import(BlockOrigin::Own, a2.clone())).unwrap(); let genesis_hash = client.chain_info().genesis_hash; assert_eq!( a2.hash(), - longest_chain_select.finality_target(genesis_hash, Some(10)).unwrap().unwrap(), + block_on(longest_chain_select.finality_target(genesis_hash, Some(10))) + .unwrap() + .unwrap(), ); } @@ -1181,7 +1439,7 @@ fn finalizing_diverged_block_should_trigger_reorg() { // `SelectChain` should report B2 as best block though assert_eq!( - select_chain.best_chain().unwrap().hash(), + block_on(select_chain.best_chain()).unwrap().hash(), b2.hash(), ); diff --git a/substrate/primitives/api/test/Cargo.toml b/substrate/primitives/api/test/Cargo.toml index 5866d44bd4..d0c45fb754 100644 --- a/substrate/primitives/api/test/Cargo.toml +++ b/substrate/primitives/api/test/Cargo.toml @@ -27,9 +27,10 @@ rustversion = "1.0.0" [dev-dependencies] criterion = "0.3.0" -substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } -sp-core = { version = "3.0.0", path = "../../core" } +futures = "0.3.9" log = "0.4.14" +sp-core = { version = "3.0.0", path = "../../core" } +substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } [[bench]] name = "bench" diff --git a/substrate/primitives/api/test/tests/runtime_calls.rs b/substrate/primitives/api/test/tests/runtime_calls.rs index e10e1b3401..562735834d 100644 --- a/substrate/primitives/api/test/tests/runtime_calls.rs +++ b/substrate/primitives/api/test/tests/runtime_calls.rs @@ -160,10 +160,15 @@ fn record_proof_works() { .build_with_longest_chain(); let block_id = BlockId::Number(client.chain_info().best_number); - let storage_root = longest_chain.best_chain().unwrap().state_root().clone(); + let storage_root = futures::executor::block_on(longest_chain.best_chain()) + .unwrap() + .state_root() + .clone(); let runtime_code = sp_core::traits::RuntimeCode { - code_fetcher: &sp_core::traits::WrappedRuntimeCode(client.code_at(&block_id).unwrap().into()), + code_fetcher: &sp_core::traits::WrappedRuntimeCode( + client.code_at(&block_id).unwrap().into(), + ), hash: vec![1], heap_pages: None, }; diff --git a/substrate/primitives/consensus/common/src/block_import.rs b/substrate/primitives/consensus/common/src/block_import.rs index 31c3eb7445..6797823200 100644 --- a/substrate/primitives/consensus/common/src/block_import.rs +++ b/substrate/primitives/consensus/common/src/block_import.rs @@ -363,15 +363,16 @@ impl BlockImpo } /// Justification import trait +#[async_trait::async_trait] pub trait JustificationImport { type Error: std::error::Error + Send + 'static; /// Called by the import queue when it is started. Returns a list of justifications to request /// from the network. - fn on_start(&mut self) -> Vec<(B::Hash, NumberFor)> { Vec::new() } + async fn on_start(&mut self) -> Vec<(B::Hash, NumberFor)>; /// Import a Block justification and finalize the given block. - fn import_justification( + async fn import_justification( &mut self, hash: B::Hash, number: NumberFor, diff --git a/substrate/primitives/consensus/common/src/import_queue/basic_queue.rs b/substrate/primitives/consensus/common/src/import_queue/basic_queue.rs index 55fc2eac40..3af983952a 100644 --- a/substrate/primitives/consensus/common/src/import_queue/basic_queue.rs +++ b/substrate/primitives/consensus/common/src/import_queue/basic_queue.rs @@ -220,16 +220,16 @@ impl BlockImportWorker { metrics, }; - // Let's initialize `justification_import` - if let Some(justification_import) = worker.justification_import.as_mut() { - for (hash, number) in justification_import.on_start() { - worker.result_sender.request_justification(&hash, number); - } - } - let delay_between_blocks = Duration::default(); let future = async move { + // Let's initialize `justification_import` + if let Some(justification_import) = worker.justification_import.as_mut() { + for (hash, number) in justification_import.on_start().await { + worker.result_sender.request_justification(&hash, number); + } + } + let block_import_process = block_import_process( block_import, verifier, @@ -254,15 +254,18 @@ impl BlockImportWorker { // Make sure to first process all justifications while let Poll::Ready(justification) = futures::poll!(justification_port.next()) { match justification { - Some(ImportJustification(who, hash, number, justification)) => - worker.import_justification(who, hash, number, justification), + Some(ImportJustification(who, hash, number, justification)) => { + worker + .import_justification(who, hash, number, justification) + .await + } None => { log::debug!( target: "block-import", "Stopping block import because justification channel was closed!", ); - return - }, + return; + } } } @@ -278,7 +281,7 @@ impl BlockImportWorker { (future, justification_sender, block_import_sender) } - fn import_justification( + async fn import_justification( &mut self, who: Origin, hash: B::Hash, @@ -286,8 +289,11 @@ impl BlockImportWorker { justification: Justification, ) { let started = wasm_timer::Instant::now(); - let success = self.justification_import.as_mut().map(|justification_import| { - justification_import.import_justification(hash, number, justification) + + let success = match self.justification_import.as_mut() { + Some(justification_import) => justification_import + .import_justification(hash, number, justification) + .await .map_err(|e| { debug!( target: "sync", @@ -298,14 +304,19 @@ impl BlockImportWorker { who, ); e - }).is_ok() - }).unwrap_or(false); + }) + .is_ok(), + None => false, + }; if let Some(metrics) = self.metrics.as_ref() { - metrics.justification_import_time.observe(started.elapsed().as_secs_f64()); + metrics + .justification_import_time + .observe(started.elapsed().as_secs_f64()); } - self.result_sender.justification_imported(who, &hash, number, success); + self.result_sender + .justification_imported(who, &hash, number, success); } } @@ -472,10 +483,15 @@ mod tests { } } + #[async_trait::async_trait] impl JustificationImport for () { type Error = crate::Error; - fn import_justification( + async fn on_start(&mut self) -> Vec<(Hash, BlockNumber)> { + Vec::new() + } + + async fn import_justification( &mut self, _hash: Hash, _number: BlockNumber, diff --git a/substrate/primitives/consensus/common/src/select_chain.rs b/substrate/primitives/consensus/common/src/select_chain.rs index 11f6fbeb54..e99a675617 100644 --- a/substrate/primitives/consensus/common/src/select_chain.rs +++ b/substrate/primitives/consensus/common/src/select_chain.rs @@ -33,23 +33,24 @@ use sp_runtime::traits::{Block as BlockT, NumberFor}; /// some implementations. /// /// Non-deterministically finalizing chains may only use the `_authoring` functions. +#[async_trait::async_trait] pub trait SelectChain: Sync + Send + Clone { - - /// Get all leaves of the chain: block hashes that have no children currently. + /// Get all leaves of the chain, i.e. block hashes that have no children currently. /// Leaves that can never be finalized will not be returned. - fn leaves(&self) -> Result::Hash>, Error>; + async fn leaves(&self) -> Result::Hash>, Error>; /// Among those `leaves` deterministically pick one chain as the generally - /// best chain to author new blocks upon and probably finalize. - fn best_chain(&self) -> Result<::Header, Error>; + /// best chain to author new blocks upon and probably (but not necessarily) + /// finalize. + async fn best_chain(&self) -> Result<::Header, Error>; /// Get the best descendent of `target_hash` that we should attempt to /// finalize next, if any. It is valid to return the given `target_hash` /// itself if no better descendent exists. - fn finality_target( + async fn finality_target( &self, target_hash: ::Hash, - _maybe_max_number: Option> + _maybe_max_number: Option>, ) -> Result::Hash>, Error> { Ok(Some(target_hash)) }