mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-09 20:11:09 +00:00
client: add a block blacklist extension (#4544)
* client: add a block blacklist extension * test-utils: fix client construction * client: fix rustdoc test
This commit is contained in:
@@ -22,7 +22,8 @@
|
||||
"tokenDecimals": 15,
|
||||
"tokenSymbol": "FIR"
|
||||
},
|
||||
"fork_blocks": null,
|
||||
"forkBlocks": null,
|
||||
"badBlocks": null,
|
||||
"consensusEngine": null,
|
||||
"genesis": {
|
||||
"raw": {
|
||||
@@ -119,4 +120,4 @@
|
||||
"children": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<Block>,
|
||||
/// Known bad block hashes.
|
||||
pub bad_blocks: sc_client::BadBlocks<Block>,
|
||||
}
|
||||
|
||||
/// Specialized `ChainSpec`.
|
||||
|
||||
@@ -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<Block> = mpsc::UnboundedReceiver<FinalityNotifica
|
||||
|
||||
/// Expected hashes of blocks at given heights.
|
||||
///
|
||||
/// This may be used as chain spec extension to filter out known, unwanted forks.
|
||||
/// This may be used as chain spec extension to set trusted checkpoints, i.e.
|
||||
/// the client will refuse to import a block with a different hash at the given
|
||||
/// height.
|
||||
pub type ForkBlocks<Block> = Option<Vec<(NumberFor<Block>, <Block as BlockT>::Hash)>>;
|
||||
|
||||
/// Known bad block hashes.
|
||||
///
|
||||
/// This may be used as chain spec extension to filter out known, unwanted forks.
|
||||
pub type BadBlocks<Block> = Option<HashSet<<Block as BlockT>::Hash>>;
|
||||
|
||||
/// Figure out the block type for a given type (for now, just a `Client`).
|
||||
pub trait BlockOf {
|
||||
/// The type of the block.
|
||||
|
||||
@@ -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<E, S, Block, RA>(
|
||||
executor: E,
|
||||
genesis_storage: S,
|
||||
fork_blocks: ForkBlocks<Block>,
|
||||
bad_blocks: BadBlocks<Block>,
|
||||
execution_extensions: ExecutionExtensions<Block>,
|
||||
) -> Result<(
|
||||
sc_client::Client<
|
||||
@@ -296,7 +297,14 @@ pub fn new_client<E, S, Block, RA>(
|
||||
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,
|
||||
))
|
||||
}
|
||||
|
||||
@@ -181,6 +181,12 @@ fn new_full_parts<TBl, TRtApi, TExecDisp, TCfg, TGen, TCSExt>(
|
||||
.cloned()
|
||||
.unwrap_or_default();
|
||||
|
||||
let bad_blocks = config.chain_spec
|
||||
.extensions()
|
||||
.get::<sc_client::BadBlocks<TBl>>()
|
||||
.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<TBl, TRtApi, TExecDisp, TCfg, TGen, TCSExt>(
|
||||
executor,
|
||||
&config.chain_spec,
|
||||
fork_blocks,
|
||||
bad_blocks,
|
||||
extensions,
|
||||
)?
|
||||
};
|
||||
|
||||
@@ -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<B, E, Block, RA> where Block: BlockT {
|
||||
// holds the block hash currently being imported. TODO: replace this with block queue
|
||||
importing_block: RwLock<Option<Block::Hash>>,
|
||||
fork_blocks: ForkBlocks<Block>,
|
||||
bad_blocks: BadBlocks<Block>,
|
||||
execution_extensions: ExecutionExtensions<Block>,
|
||||
_phantom: PhantomData<RA>,
|
||||
}
|
||||
@@ -174,7 +175,14 @@ pub fn new_with_backend<B, E, Block, S, RA>(
|
||||
{
|
||||
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<B, E, Block, RA> BlockOf for Client<B, E, Block, RA> where
|
||||
@@ -196,6 +204,7 @@ impl<B, E, Block, RA> Client<B, E, Block, RA> where
|
||||
executor: E,
|
||||
build_genesis_storage: S,
|
||||
fork_blocks: ForkBlocks<Block>,
|
||||
bad_blocks: BadBlocks<Block>,
|
||||
execution_extensions: ExecutionExtensions<Block>,
|
||||
) -> sp_blockchain::Result<Self> {
|
||||
if backend.blockchain().header(BlockId::Number(Zero::zero()))?.is_none() {
|
||||
@@ -225,6 +234,7 @@ impl<B, E, Block, RA> Client<B, E, Block, RA> 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<Block> for &'a Client<B, E,
|
||||
) -> Result<ImportResult, Self::Error> {
|
||||
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<Block> for &'a Client<B, E,
|
||||
}
|
||||
}
|
||||
|
||||
let bad_block = self.bad_blocks.as_ref()
|
||||
.filter(|bs| bs.contains(&hash))
|
||||
.is_some();
|
||||
|
||||
if bad_block {
|
||||
trace!(
|
||||
"Rejecting known bad block: #{} {:?}",
|
||||
number,
|
||||
hash,
|
||||
);
|
||||
return Ok(ImportResult::KnownBad);
|
||||
}
|
||||
|
||||
// Own status must be checked first. If the block and ancestry is pruned
|
||||
// this function must return `AlreadyInChain` rather than `MissingState`
|
||||
match self.block_status(&BlockId::Hash(hash))
|
||||
|
||||
@@ -68,6 +68,7 @@
|
||||
//! <Storage>::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,
|
||||
};
|
||||
|
||||
@@ -70,7 +70,14 @@ pub fn new_light<B, S, GS, RA, E>(
|
||||
{
|
||||
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.
|
||||
|
||||
@@ -204,6 +204,7 @@ impl<Executor, Backend, G: GenesisInit> TestClientBuilder<Executor, Backend, G>
|
||||
executor,
|
||||
storage,
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
ExecutionExtensions::new(
|
||||
self.execution_strategies,
|
||||
self.keystore.clone(),
|
||||
|
||||
Reference in New Issue
Block a user