diff --git a/substrate/bin/node/cli/src/service.rs b/substrate/bin/node/cli/src/service.rs index b12dfcdc51..603df5b7d9 100644 --- a/substrate/bin/node/cli/src/service.rs +++ b/substrate/bin/node/cli/src/service.rs @@ -565,7 +565,8 @@ mod tests { storage_changes: None, finalized: false, auxiliary: Vec::new(), - fork_choice: ForkChoiceStrategy::LongestChain, + intermediates: Default::default(), + fork_choice: Some(ForkChoiceStrategy::LongestChain), allow_missing_state: false, import_existing: false, }; diff --git a/substrate/bin/node/transaction-factory/src/lib.rs b/substrate/bin/node/transaction-factory/src/lib.rs index f3dcdb0875..a0c6a4f663 100644 --- a/substrate/bin/node/transaction-factory/src/lib.rs +++ b/substrate/bin/node/transaction-factory/src/lib.rs @@ -202,7 +202,8 @@ fn import_block( finalized: false, justification: None, auxiliary: Vec::new(), - fork_choice: ForkChoiceStrategy::LongestChain, + intermediates: Default::default(), + fork_choice: Some(ForkChoiceStrategy::LongestChain), allow_missing_state: false, import_existing: false, }; diff --git a/substrate/client/consensus/aura/src/lib.rs b/substrate/client/consensus/aura/src/lib.rs index 95dc08afaf..270bd19422 100644 --- a/substrate/client/consensus/aura/src/lib.rs +++ b/substrate/client/consensus/aura/src/lib.rs @@ -290,7 +290,8 @@ impl sc_consensus_slots::SimpleSlotWorker for AuraW storage_changes: Some(storage_changes), finalized: false, auxiliary: Vec::new(), - fork_choice: ForkChoiceStrategy::LongestChain, + intermediates: Default::default(), + fork_choice: Some(ForkChoiceStrategy::LongestChain), allow_missing_state: false, import_existing: false, } @@ -644,7 +645,8 @@ impl Verifier for AuraVerifier where finalized: false, justification, auxiliary: Vec::new(), - fork_choice: ForkChoiceStrategy::LongestChain, + intermediates: Default::default(), + fork_choice: Some(ForkChoiceStrategy::LongestChain), allow_missing_state: false, import_existing: false, }; diff --git a/substrate/client/consensus/babe/src/lib.rs b/substrate/client/consensus/babe/src/lib.rs index 770f8a4eec..8480972311 100644 --- a/substrate/client/consensus/babe/src/lib.rs +++ b/substrate/client/consensus/babe/src/lib.rs @@ -451,10 +451,8 @@ impl sc_consensus_slots::SimpleSlotWorker for BabeWork storage_changes: Some(storage_changes), finalized: false, auxiliary: Vec::new(), // block-weight is written in block import. - // TODO: block-import handles fork choice and this shouldn't even have the - // option to specify one. - // https://github.com/paritytech/substrate/issues/3623 - fork_choice: ForkChoiceStrategy::LongestChain, + intermediates: Default::default(), + fork_choice: None, allow_missing_state: false, import_existing: false, } @@ -807,10 +805,8 @@ impl Verifier for BabeVerifier BlockImport for BabeBlockImport last_best_weight { + Some(ForkChoiceStrategy::Custom(if total_weight > last_best_weight { true } else if total_weight == last_best_weight { number > last_best_number } else { false - }) + })) }; let import_result = self.inner.import_block(block, new_cache); diff --git a/substrate/client/consensus/babe/src/tests.rs b/substrate/client/consensus/babe/src/tests.rs index 880e028000..3339c06d65 100644 --- a/substrate/client/consensus/babe/src/tests.rs +++ b/substrate/client/consensus/babe/src/tests.rs @@ -594,7 +594,8 @@ fn propose_and_import_block( storage_changes: None, finalized: false, auxiliary: Vec::new(), - fork_choice: ForkChoiceStrategy::LongestChain, + intermediates: Default::default(), + fork_choice: Some(ForkChoiceStrategy::LongestChain), allow_missing_state: false, import_existing: false, }, diff --git a/substrate/client/consensus/pow/src/lib.rs b/substrate/client/consensus/pow/src/lib.rs index 2ea0cbdf0f..ca7285b7fe 100644 --- a/substrate/client/consensus/pow/src/lib.rs +++ b/substrate/client/consensus/pow/src/lib.rs @@ -32,6 +32,7 @@ use std::sync::Arc; use std::thread; use std::collections::HashMap; +use std::marker::PhantomData; use sc_client_api::{BlockOf, backend::AuxStore}; use sp_blockchain::{HeaderBackend, ProvideCache, well_known_cache_keys::Id as CacheKeyId}; use sp_block_builder::BlockBuilder as BlockBuilderApi; @@ -43,7 +44,8 @@ use sp_consensus_pow::{Seal, TotalDifficulty, POW_ENGINE_ID}; use sp_inherents::{InherentDataProviders, InherentData}; use sp_consensus::{ BlockImportParams, BlockOrigin, ForkChoiceStrategy, SyncOracle, Environment, Proposer, - SelectChain, Error as ConsensusError, CanAuthorWith, RecordProof, + SelectChain, Error as ConsensusError, CanAuthorWith, RecordProof, BlockImport, + BlockCheckParams, ImportResult, }; use sp_consensus::import_queue::{BoxBlockImport, BasicQueue, Verifier}; use codec::{Encode, Decode}; @@ -59,6 +61,10 @@ pub enum Error { HeaderUnsealed(B::Hash), #[display(fmt = "PoW validation error: invalid seal")] InvalidSeal, + #[display(fmt = "PoW validation error: invalid difficulty")] + InvalidDifficulty, + #[display(fmt = "PoW block import expects an intermediate, but not found one")] + NoIntermediate, #[display(fmt = "Rejecting block too far in future")] TooFarInFuture, #[display(fmt = "Fetching best header failed using select chain: {:?}", _0)] @@ -89,6 +95,12 @@ impl std::convert::From> for String { } } +impl std::convert::From> for ConsensusError { + fn from(error: Error) -> ConsensusError { + ConsensusError::ClientImport(error.to_string()) + } +} + /// Auxiliary storage prefix for PoW engine. pub const POW_AUX_PREFIX: [u8; 4] = *b"PoW:"; @@ -97,6 +109,18 @@ fn aux_key>(hash: &T) -> Vec { POW_AUX_PREFIX.iter().chain(hash.as_ref()).copied().collect() } +/// Intermediate value passed to block importer. +#[derive(Encode, Decode, Clone, Debug, Default)] +pub struct PowIntermediate { + /// The header hash with seal, used for auxiliary key. + pub hash: B::Hash, + /// Difficulty of the block, if known. + pub difficulty: Option, +} + +/// Intermediate key for PoW engine. +pub static INTERMEDIATE_KEY: &[u8] = b"pow1"; + /// Auxiliary storage data for PoW. #[derive(Encode, Decode, Clone, Debug, Default)] pub struct PowAux { @@ -126,14 +150,22 @@ pub trait PowAlgorithm { type Difficulty: TotalDifficulty + Default + Encode + Decode + Ord + Clone + Copy; /// Get the next block's difficulty. + /// + /// This function will be called twice during the import process, so the implementation + /// should be properly cached. fn difficulty(&self, parent: &BlockId) -> Result>; - /// Verify proof of work against the given difficulty. - fn verify( + /// Verify that the seal is valid against given pre hash. + fn verify_seal( &self, - parent: &BlockId, pre_hash: &B::Hash, seal: &Seal, + ) -> Result>; + /// Verify that the difficulty is valid against given seal. + fn verify_difficulty( + &self, difficulty: Self::Difficulty, + parent: &BlockId, + seal: &Seal, ) -> Result>; /// Mine a seal that satisfies the given difficulty. fn mine( @@ -145,59 +177,35 @@ pub trait PowAlgorithm { ) -> Result, Error>; } -/// A verifier for PoW blocks. -pub struct PowVerifier { - client: Arc, +/// A block importer for PoW. +pub struct PowBlockImport { algorithm: Algorithm, - inherent_data_providers: sp_inherents::InherentDataProviders, + inner: I, select_chain: Option, + client: Arc, + inherent_data_providers: sp_inherents::InherentDataProviders, check_inherents_after: <::Header as HeaderT>::Number, } -impl PowVerifier { +impl PowBlockImport where + B: BlockT, + I: BlockImport> + Send + Sync, + I::Error: Into, + C: ProvideRuntimeApi + Send + Sync + HeaderBackend + AuxStore + ProvideCache + BlockOf, + C::Api: BlockBuilderApi, + Algorithm: PowAlgorithm, +{ + /// Create a new block import suitable to be used in PoW pub fn new( + inner: I, client: Arc, algorithm: Algorithm, check_inherents_after: <::Header as HeaderT>::Number, select_chain: Option, inherent_data_providers: sp_inherents::InherentDataProviders, ) -> Self { - Self { client, algorithm, inherent_data_providers, select_chain, check_inherents_after } - } - - fn check_header( - &self, - mut header: B::Header, - parent_block_id: BlockId, - ) -> Result<(B::Header, Algorithm::Difficulty, DigestItem), Error> where - Algorithm: PowAlgorithm, - { - let hash = header.hash(); - - let (seal, inner_seal) = match header.digest_mut().pop() { - Some(DigestItem::Seal(id, seal)) => { - if id == POW_ENGINE_ID { - (DigestItem::Seal(id, seal.clone()), seal) - } else { - return Err(Error::WrongEngine(id)) - } - }, - _ => return Err(Error::HeaderUnsealed(hash)), - }; - - let pre_hash = header.hash(); - let difficulty = self.algorithm.difficulty(&parent_block_id)?; - - if !self.algorithm.verify( - &parent_block_id, - &pre_hash, - &inner_seal, - difficulty, - )? { - return Err(Error::InvalidSeal); - } - - Ok((header, difficulty, seal)) + Self { inner, client, algorithm, check_inherents_after, + select_chain, inherent_data_providers } } fn check_inherents( @@ -206,9 +214,7 @@ impl PowVerifier { block_id: BlockId, inherent_data: InherentData, timestamp_now: u64, - ) -> Result<(), Error> where - C: ProvideRuntimeApi, C::Api: BlockBuilderApi - { + ) -> Result<(), Error> { const MAX_TIMESTAMP_DRIFT_SECS: u64 = 60; if *block.header().number() < self.check_inherents_after { @@ -243,10 +249,148 @@ impl PowVerifier { } } -impl Verifier for PowVerifier where +impl BlockImport for PowBlockImport where + B: BlockT, + I: BlockImport> + Send + Sync, + I::Error: Into, + S: SelectChain, C: ProvideRuntimeApi + Send + Sync + HeaderBackend + AuxStore + ProvideCache + BlockOf, C::Api: BlockBuilderApi, - S: SelectChain, + Algorithm: PowAlgorithm, +{ + type Error = ConsensusError; + type Transaction = sp_api::TransactionFor; + + fn check_block( + &mut self, + block: BlockCheckParams, + ) -> Result { + self.inner.check_block(block).map_err(Into::into) + } + + fn import_block( + &mut self, + mut block: BlockImportParams, + new_cache: HashMap>, + ) -> Result { + let best_hash = match self.select_chain.as_ref() { + Some(select_chain) => select_chain.best_chain() + .map_err(|e| format!("Fetch best chain failed via select chain: {:?}", e))? + .hash(), + None => self.client.info().best_hash, + }; + + let parent_hash = *block.header.parent_hash(); + let best_aux = PowAux::read::<_, B>(self.client.as_ref(), &best_hash)?; + let mut aux = PowAux::read::<_, B>(self.client.as_ref(), &parent_hash)?; + + if let Some(inner_body) = block.body.take() { + let inherent_data = self.inherent_data_providers + .create_inherent_data().map_err(|e| e.into_string())?; + let timestamp_now = inherent_data.timestamp_inherent_data().map_err(|e| e.into_string())?; + + let check_block = B::new(block.header.clone(), inner_body); + + self.check_inherents( + check_block.clone(), + BlockId::Hash(parent_hash), + inherent_data, + timestamp_now + )?; + + block.body = Some(check_block.deconstruct().1); + } + + let inner_seal = match block.post_digests.last() { + Some(DigestItem::Seal(id, seal)) => { + if id == &POW_ENGINE_ID { + seal.clone() + } else { + return Err(Error::::WrongEngine(*id).into()) + } + }, + _ => return Err(Error::::HeaderUnsealed(block.header.hash()).into()), + }; + + let intermediate = PowIntermediate::::decode( + &mut &block.intermediates.remove(INTERMEDIATE_KEY) + .ok_or(Error::::NoIntermediate)?[..] + ).map_err(|_| Error::::NoIntermediate)?; + + let difficulty = match intermediate.difficulty { + Some(difficulty) => difficulty, + None => self.algorithm.difficulty(&BlockId::hash(parent_hash))?, + }; + + if !self.algorithm.verify_difficulty( + difficulty, + &BlockId::hash(parent_hash), + &inner_seal, + )? { + return Err(Error::::InvalidDifficulty.into()) + } + + aux.difficulty = difficulty; + aux.total_difficulty.increment(difficulty); + + let key = aux_key(&intermediate.hash); + block.auxiliary.push((key, Some(aux.encode()))); + if block.fork_choice.is_none() { + block.fork_choice = Some(ForkChoiceStrategy::Custom( + aux.total_difficulty > best_aux.total_difficulty + )); + } + + self.inner.import_block(block, new_cache).map_err(Into::into) + } +} + +/// A verifier for PoW blocks. +pub struct PowVerifier { + algorithm: Algorithm, + _marker: PhantomData, +} + +impl PowVerifier { + pub fn new( + algorithm: Algorithm, + ) -> Self { + Self { algorithm, _marker: PhantomData } + } + + fn check_header( + &self, + mut header: B::Header, + ) -> Result<(B::Header, DigestItem), Error> where + Algorithm: PowAlgorithm, + { + let hash = header.hash(); + + let (seal, inner_seal) = match header.digest_mut().pop() { + Some(DigestItem::Seal(id, seal)) => { + if id == POW_ENGINE_ID { + (DigestItem::Seal(id, seal.clone()), seal) + } else { + return Err(Error::WrongEngine(id)) + } + }, + _ => return Err(Error::HeaderUnsealed(hash)), + }; + + let pre_hash = header.hash(); + + if !self.algorithm.verify_seal( + &pre_hash, + &inner_seal, + )? { + return Err(Error::InvalidSeal); + } + + Ok((header, seal)) + } +} + +impl Verifier for PowVerifier where Algorithm: PowAlgorithm + Send + Sync, { fn verify( @@ -254,44 +398,16 @@ impl Verifier for PowVerifier origin: BlockOrigin, header: B::Header, justification: Option, - mut body: Option>, + body: Option>, ) -> Result<(BlockImportParams, Option)>>), String> { - let inherent_data = self.inherent_data_providers - .create_inherent_data().map_err(|e| e.into_string())?; - let timestamp_now = inherent_data.timestamp_inherent_data().map_err(|e| e.into_string())?; - - let best_hash = match self.select_chain.as_ref() { - Some(select_chain) => select_chain.best_chain() - .map_err(|e| format!("Fetch best chain failed via select chain: {:?}", e))? - .hash(), - None => self.client.info().best_hash, - }; let hash = header.hash(); - let parent_hash = *header.parent_hash(); - let best_aux = PowAux::read::<_, B>(self.client.as_ref(), &best_hash)?; - let mut aux = PowAux::read::<_, B>(self.client.as_ref(), &parent_hash)?; + let (checked_header, seal) = self.check_header(header)?; - let (checked_header, difficulty, seal) = self.check_header( - header, - BlockId::Hash(parent_hash), - )?; - aux.difficulty = difficulty; - aux.total_difficulty.increment(difficulty); + let intermediate = PowIntermediate:: { + hash: hash, + difficulty: None, + }; - if let Some(inner_body) = body.take() { - let block = B::new(checked_header.clone(), inner_body); - - self.check_inherents( - block.clone(), - BlockId::Hash(parent_hash), - inherent_data, - timestamp_now - )?; - - body = Some(block.deconstruct().1); - } - - let key = aux_key(&hash); let import_block = BlockImportParams { origin, header: checked_header, @@ -300,10 +416,13 @@ impl Verifier for PowVerifier storage_changes: None, finalized: false, justification, - auxiliary: vec![(key, Some(aux.encode()))], - fork_choice: ForkChoiceStrategy::Custom( - aux.total_difficulty > best_aux.total_difficulty - ), + intermediates: { + let mut ret = HashMap::new(); + ret.insert(INTERMEDIATE_KEY.to_vec(), intermediate.encode()); + ret + }, + auxiliary: vec![], + fork_choice: None, allow_missing_state: false, import_existing: false, }; @@ -332,10 +451,7 @@ pub type PowImportQueue = BasicQueue; /// Import queue for PoW engine. pub fn import_queue( block_import: BoxBlockImport>, - client: Arc, algorithm: Algorithm, - check_inherents_after: <::Header as HeaderT>::Number, - select_chain: Option, inherent_data_providers: InherentDataProviders, ) -> Result< PowImportQueue>, @@ -345,18 +461,12 @@ pub fn import_queue( C: ProvideRuntimeApi + HeaderBackend + BlockOf + ProvideCache + AuxStore, C: Send + Sync + AuxStore + 'static, C::Api: BlockBuilderApi, - Algorithm: PowAlgorithm + Send + Sync + 'static, + Algorithm: PowAlgorithm + Clone + Send + Sync + 'static, S: SelectChain + 'static, { register_pow_inherent_data_provider(&inherent_data_providers)?; - let verifier = PowVerifier::new( - client.clone(), - algorithm, - check_inherents_after, - select_chain, - inherent_data_providers, - ); + let verifier = PowVerifier::new(algorithm); Ok(BasicQueue::new( verifier, @@ -485,7 +595,6 @@ fn mine_loop( continue 'outer } - let mut aux = PowAux::read(client, &best_hash)?; let mut proposer = futures::executor::block_on(env.init(&best_header)) .map_err(|e| Error::Environment(format!("{:?}", e)))?; @@ -526,38 +635,36 @@ fn mine_loop( } }; - aux.difficulty = difficulty; - aux.total_difficulty.increment(difficulty); - let hash = { + let (hash, seal) = { + let seal = DigestItem::Seal(POW_ENGINE_ID, seal); let mut header = header.clone(); - header.digest_mut().push(DigestItem::Seal(POW_ENGINE_ID, seal.clone())); - header.hash() + header.digest_mut().push(seal); + let hash = header.hash(); + let seal = header.digest_mut().pop() + .expect("Pushed one seal above; length greater than zero; qed"); + (hash, seal) }; - let key = aux_key(&hash); - let best_hash = match select_chain { - Some(select_chain) => select_chain.best_chain() - .map_err(Error::BestHashSelectChain)? - .hash(), - None => client.info().best_hash, + let intermediate = PowIntermediate:: { + hash, + difficulty: Some(difficulty), }; - let best_aux = PowAux::::read(client, &best_hash)?; - - // if the best block has changed in the meantime drop our proposal - if best_aux.total_difficulty > aux.total_difficulty { - continue 'outer - } let import_block = BlockImportParams { origin: BlockOrigin::Own, header, justification: None, - post_digests: vec![DigestItem::Seal(POW_ENGINE_ID, seal)], + post_digests: vec![seal], body: Some(body), storage_changes: Some(proposal.storage_changes), + intermediates: { + let mut ret = HashMap::new(); + ret.insert(INTERMEDIATE_KEY.to_vec(), intermediate.encode()); + ret + }, finalized: false, - auxiliary: vec![(key, Some(aux.encode()))], - fork_choice: ForkChoiceStrategy::Custom(true), + auxiliary: vec![], + fork_choice: None, allow_missing_state: false, import_existing: false, }; diff --git a/substrate/client/finality-grandpa/src/light_import.rs b/substrate/client/finality-grandpa/src/light_import.rs index 0da2248778..4ae35167be 100644 --- a/substrate/client/finality-grandpa/src/light_import.rs +++ b/substrate/client/finality-grandpa/src/light_import.rs @@ -697,7 +697,8 @@ pub mod tests { storage_changes: None, finalized: false, auxiliary: Vec::new(), - fork_choice: ForkChoiceStrategy::LongestChain, + intermediates: Default::default(), + fork_choice: Some(ForkChoiceStrategy::LongestChain), allow_missing_state: true, import_existing: false, }; diff --git a/substrate/client/finality-grandpa/src/tests.rs b/substrate/client/finality-grandpa/src/tests.rs index 9ad12c6c31..889250c54d 100644 --- a/substrate/client/finality-grandpa/src/tests.rs +++ b/substrate/client/finality-grandpa/src/tests.rs @@ -1032,7 +1032,8 @@ fn allows_reimporting_change_blocks() { storage_changes: None, finalized: false, auxiliary: Vec::new(), - fork_choice: ForkChoiceStrategy::LongestChain, + intermediates: Default::default(), + fork_choice: Some(ForkChoiceStrategy::LongestChain), allow_missing_state: false, import_existing: false, } @@ -1091,7 +1092,8 @@ fn test_bad_justification() { storage_changes: None, finalized: false, auxiliary: Vec::new(), - fork_choice: ForkChoiceStrategy::LongestChain, + intermediates: Default::default(), + fork_choice: Some(ForkChoiceStrategy::LongestChain), allow_missing_state: false, import_existing: false, } @@ -1829,7 +1831,8 @@ fn imports_justification_for_regular_blocks_on_import() { storage_changes: None, finalized: false, auxiliary: Vec::new(), - fork_choice: ForkChoiceStrategy::LongestChain, + intermediates: Default::default(), + fork_choice: Some(ForkChoiceStrategy::LongestChain), allow_missing_state: false, import_existing: false, }; diff --git a/substrate/client/network/test/src/lib.rs b/substrate/client/network/test/src/lib.rs index 1b13e83343..2369ba4f22 100644 --- a/substrate/client/network/test/src/lib.rs +++ b/substrate/client/network/test/src/lib.rs @@ -95,7 +95,8 @@ impl Verifier for PassThroughVerifier { justification, post_digests: vec![], auxiliary: Vec::new(), - fork_choice: ForkChoiceStrategy::LongestChain, + intermediates: Default::default(), + fork_choice: Some(ForkChoiceStrategy::LongestChain), allow_missing_state: false, import_existing: false, }, maybe_keys)) diff --git a/substrate/client/src/client.rs b/substrate/client/src/client.rs index c74a005c6f..26b077277f 100644 --- a/substrate/client/src/client.rs +++ b/substrate/client/src/client.rs @@ -818,12 +818,19 @@ impl Client where finalized, auxiliary, fork_choice, + intermediates, import_existing, .. } = import_block; assert!(justification.is_some() && finalized || justification.is_none()); + if !intermediates.is_empty() { + return Err(Error::IncompletePipeline) + } + + let fork_choice = fork_choice.ok_or(Error::IncompletePipeline)?; + let import_headers = if post_digests.is_empty() { PrePostHeader::Same(header) } else { diff --git a/substrate/primitives/blockchain/src/error.rs b/substrate/primitives/blockchain/src/error.rs index d51ab787c7..24872448ab 100644 --- a/substrate/primitives/blockchain/src/error.rs +++ b/substrate/primitives/blockchain/src/error.rs @@ -126,6 +126,9 @@ pub enum Error { /// Invalid calculated state root on block import. #[display(fmt = "Calculated state root does not match.")] InvalidStateRoot, + /// Incomplete block import pipeline. + #[display(fmt = "Incomplete block import pipeline.")] + IncompletePipeline, /// A convenience variant for String #[display(fmt = "{}", _0)] Msg(String), diff --git a/substrate/primitives/consensus/common/src/block_import.rs b/substrate/primitives/consensus/common/src/block_import.rs index f8d05e1054..71315b63ef 100644 --- a/substrate/primitives/consensus/common/src/block_import.rs +++ b/substrate/primitives/consensus/common/src/block_import.rs @@ -142,13 +142,21 @@ pub struct BlockImportParams { /// Is this block finalized already? /// `true` implies instant finality. pub finalized: bool, + /// Intermediate values that are interpreted by block importers. Each block importer, + /// upon handling a value, removes it from the intermediate list. The final block importer + /// rejects block import if there are still intermediate values that remain unhandled. + pub intermediates: HashMap, Vec>, /// Auxiliary consensus data produced by the block. /// Contains a list of key-value pairs. If values are `None`, the keys /// will be deleted. pub auxiliary: Vec<(Vec, Option>)>, /// Fork choice strategy of this import. This should only be set by a /// synchronous import, otherwise it may race against other imports. - pub fork_choice: ForkChoiceStrategy, + /// `None` indicates that the current verifier or importer cannot yet + /// determine the fork choice value, and it expects subsequent importer + /// to modify it. If `None` is passed all the way down to bottom block + /// importer, the import fails with an `IncompletePipeline` error. + pub fork_choice: Option, /// Allow importing the block skipping state verification if parent state is missing. pub allow_missing_state: bool, /// Re-validate existing block. @@ -210,6 +218,7 @@ impl BlockImportParams { storage_changes: None, finalized: self.finalized, auxiliary: self.auxiliary, + intermediates: self.intermediates, allow_missing_state: self.allow_missing_state, fork_choice: self.fork_choice, import_existing: self.import_existing, diff --git a/substrate/test-utils/client/src/client_ext.rs b/substrate/test-utils/client/src/client_ext.rs index aa7383e3ab..e29ee787d0 100644 --- a/substrate/test-utils/client/src/client_ext.rs +++ b/substrate/test-utils/client/src/client_ext.rs @@ -96,7 +96,8 @@ impl ClientBlockImportExt for std::sync::A storage_changes: None, finalized: false, auxiliary: Vec::new(), - fork_choice: ForkChoiceStrategy::LongestChain, + intermediates: Default::default(), + fork_choice: Some(ForkChoiceStrategy::LongestChain), allow_missing_state: false, import_existing: false, }; @@ -115,7 +116,8 @@ impl ClientBlockImportExt for std::sync::A storage_changes: None, finalized: false, auxiliary: Vec::new(), - fork_choice: ForkChoiceStrategy::Custom(true), + intermediates: Default::default(), + fork_choice: Some(ForkChoiceStrategy::Custom(true)), allow_missing_state: false, import_existing: false, }; @@ -134,7 +136,8 @@ impl ClientBlockImportExt for std::sync::A storage_changes: None, finalized: true, auxiliary: Vec::new(), - fork_choice: ForkChoiceStrategy::Custom(true), + intermediates: Default::default(), + fork_choice: Some(ForkChoiceStrategy::Custom(true)), allow_missing_state: false, import_existing: false, }; @@ -158,7 +161,8 @@ impl ClientBlockImportExt for std::sync::A storage_changes: None, finalized: true, auxiliary: Vec::new(), - fork_choice: ForkChoiceStrategy::LongestChain, + intermediates: Default::default(), + fork_choice: Some(ForkChoiceStrategy::LongestChain), allow_missing_state: false, import_existing: false, }; @@ -182,7 +186,8 @@ impl ClientBlockImportExt for Client ClientBlockImportExt for Client ClientBlockImportExt for Client ClientBlockImportExt for Client