diff --git a/substrate/bin/node/cli/res/flaming-fir.json b/substrate/bin/node/cli/res/flaming-fir.json index 401825b4a6..413fa3b6d7 100644 --- a/substrate/bin/node/cli/res/flaming-fir.json +++ b/substrate/bin/node/cli/res/flaming-fir.json @@ -22,7 +22,8 @@ "tokenDecimals": 15, "tokenSymbol": "FIR" }, - "fork_blocks": null, + "forkBlocks": null, + "badBlocks": null, "consensusEngine": null, "genesis": { "raw": { @@ -119,4 +120,4 @@ "children": {} } } -} \ No newline at end of file +} diff --git a/substrate/bin/node/cli/src/chain_spec.rs b/substrate/bin/node/cli/src/chain_spec.rs index 836ce53996..26b1f6d294 100644 --- a/substrate/bin/node/cli/src/chain_spec.rs +++ b/substrate/bin/node/cli/src/chain_spec.rs @@ -47,9 +47,12 @@ const STAGING_TELEMETRY_URL: &str = "wss://telemetry.polkadot.io/submit/"; /// Additional parameters for some Substrate core modules, /// customizable from the chain spec. #[derive(Default, Clone, Serialize, Deserialize, ChainSpecExtension)] +#[serde(rename_all = "camelCase")] pub struct Extensions { /// Block numbers with known hashes. pub fork_blocks: sc_client::ForkBlocks, + /// Known bad block hashes. + pub bad_blocks: sc_client::BadBlocks, } /// Specialized `ChainSpec`. diff --git a/substrate/client/api/src/client.rs b/substrate/client/api/src/client.rs index ceb3601085..9e095a897f 100644 --- a/substrate/client/api/src/client.rs +++ b/substrate/client/api/src/client.rs @@ -16,6 +16,7 @@ //! A set of APIs supported by the client along with their primitives. +use std::collections::HashSet; use futures::channel::mpsc; use sp_core::storage::StorageKey; use sp_runtime::{ @@ -36,9 +37,16 @@ pub type FinalityNotifications = mpsc::UnboundedReceiver = Option, ::Hash)>>; +/// Known bad block hashes. +/// +/// This may be used as chain spec extension to filter out known, unwanted forks. +pub type BadBlocks = Option::Hash>>; + /// Figure out the block type for a given type (for now, just a `Client`). pub trait BlockOf { /// The type of the block. diff --git a/substrate/client/db/src/lib.rs b/substrate/client/db/src/lib.rs index d8dcf3c0af..34aec0441f 100644 --- a/substrate/client/db/src/lib.rs +++ b/substrate/client/db/src/lib.rs @@ -39,7 +39,7 @@ use std::path::PathBuf; use std::io; use std::collections::{HashMap, HashSet}; -use sc_client_api::{execution_extensions::ExecutionExtensions, ForkBlocks}; +use sc_client_api::{execution_extensions::ExecutionExtensions, BadBlocks, ForkBlocks}; use sc_client_api::backend::NewBlockState; use sc_client_api::backend::{StorageCollection, ChildStorageCollection}; use sp_blockchain::{ @@ -276,6 +276,7 @@ pub fn new_client( executor: E, genesis_storage: S, fork_blocks: ForkBlocks, + bad_blocks: BadBlocks, execution_extensions: ExecutionExtensions, ) -> Result<( sc_client::Client< @@ -296,7 +297,14 @@ pub fn new_client( let backend = Arc::new(Backend::new(settings, CANONICALIZATION_DELAY)?); let executor = sc_client::LocalCallExecutor::new(backend.clone(), executor); Ok(( - sc_client::Client::new(backend.clone(), executor, genesis_storage, fork_blocks, execution_extensions)?, + sc_client::Client::new( + backend.clone(), + executor, + genesis_storage, + fork_blocks, + bad_blocks, + execution_extensions, + )?, backend, )) } diff --git a/substrate/client/service/src/builder.rs b/substrate/client/service/src/builder.rs index 849203b09d..be7a6fb677 100644 --- a/substrate/client/service/src/builder.rs +++ b/substrate/client/service/src/builder.rs @@ -181,6 +181,12 @@ fn new_full_parts( .cloned() .unwrap_or_default(); + let bad_blocks = config.chain_spec + .extensions() + .get::>() + .cloned() + .unwrap_or_default(); + let (client, backend) = { let db_config = sc_client_db::DatabaseSettings { state_cache_size: config.state_cache_size, @@ -208,6 +214,7 @@ fn new_full_parts( executor, &config.chain_spec, fork_blocks, + bad_blocks, extensions, )? }; diff --git a/substrate/client/src/client.rs b/substrate/client/src/client.rs index 66e031db9f..234f86436e 100644 --- a/substrate/client/src/client.rs +++ b/substrate/client/src/client.rs @@ -69,7 +69,7 @@ pub use sc_client_api::{ }, client::{ ImportNotifications, FinalityNotification, FinalityNotifications, BlockImportNotification, - ClientInfo, BlockchainEvents, BlockBody, ProvideUncles, ForkBlocks, + ClientInfo, BlockchainEvents, BlockBody, ProvideUncles, BadBlocks, ForkBlocks, BlockOf, }, execution_extensions::{ExecutionExtensions, ExecutionStrategies}, @@ -101,6 +101,7 @@ pub struct Client where Block: BlockT { // holds the block hash currently being imported. TODO: replace this with block queue importing_block: RwLock>, fork_blocks: ForkBlocks, + bad_blocks: BadBlocks, execution_extensions: ExecutionExtensions, _phantom: PhantomData, } @@ -174,7 +175,14 @@ pub fn new_with_backend( { let call_executor = LocalCallExecutor::new(backend.clone(), executor); let extensions = ExecutionExtensions::new(Default::default(), keystore); - Client::new(backend, call_executor, build_genesis_storage, Default::default(), extensions) + Client::new( + backend, + call_executor, + build_genesis_storage, + Default::default(), + Default::default(), + extensions, + ) } impl BlockOf for Client where @@ -196,6 +204,7 @@ impl Client where executor: E, build_genesis_storage: S, fork_blocks: ForkBlocks, + bad_blocks: BadBlocks, execution_extensions: ExecutionExtensions, ) -> sp_blockchain::Result { if backend.blockchain().header(BlockId::Number(Zero::zero()))?.is_none() { @@ -225,6 +234,7 @@ impl Client where finality_notification_sinks: Default::default(), importing_block: Default::default(), fork_blocks, + bad_blocks, execution_extensions, _phantom: Default::default(), }) @@ -1486,6 +1496,8 @@ impl<'a, B, E, Block, RA> sp_consensus::BlockImport for &'a Client Result { let BlockCheckParams { hash, number, parent_hash, allow_missing_state, import_existing } = block; + // Check the block against white and black lists if any are defined + // (i.e. fork blocks and bad blocks respectively) let fork_block = self.fork_blocks.as_ref() .and_then(|fs| fs.iter().find(|(n, _)| *n == number)); @@ -1501,6 +1513,19 @@ impl<'a, B, E, Block, RA> sp_consensus::BlockImport for &'a Client::default(), //! Default::default(), //! Default::default(), +//! Default::default(), //! ); //! ``` //! @@ -98,7 +99,7 @@ pub use crate::{ new_in_mem, BlockBody, ImportNotifications, FinalityNotifications, BlockchainEvents, BlockImportNotification, Client, ClientInfo, ExecutionStrategies, FinalityNotification, - LongestChain, BlockOf, ProvideUncles, ForkBlocks, apply_aux, + LongestChain, BlockOf, ProvideUncles, BadBlocks, ForkBlocks, apply_aux, }, leaves::LeafSet, }; diff --git a/substrate/client/src/light/mod.rs b/substrate/client/src/light/mod.rs index 9ab56b824e..ed36bccc11 100644 --- a/substrate/client/src/light/mod.rs +++ b/substrate/client/src/light/mod.rs @@ -70,7 +70,14 @@ pub fn new_light( { let local_executor = LocalCallExecutor::new(backend.clone(), code_executor); let executor = GenesisCallExecutor::new(backend.clone(), local_executor); - Client::new(backend, executor, genesis_storage, Default::default(), Default::default()) + Client::new( + backend, + executor, + genesis_storage, + Default::default(), + Default::default(), + Default::default(), + ) } /// Create an instance of fetch data checker. diff --git a/substrate/test-utils/client/src/lib.rs b/substrate/test-utils/client/src/lib.rs index 665fdf621f..b9d857e897 100644 --- a/substrate/test-utils/client/src/lib.rs +++ b/substrate/test-utils/client/src/lib.rs @@ -204,6 +204,7 @@ impl TestClientBuilder executor, storage, Default::default(), + Default::default(), ExecutionExtensions::new( self.execution_strategies, self.keystore.clone(),