ChainSpec extensions (#3692)

* Add some chainspec tests and make sure we validate it.

* Manual implementation of Extension + Forks definitions.

* Move chain spec to separate crate.

* Allow using ChainSpec with extensions.

* Renames.

* Implement Extension derive.

* Implement Extension for Forks.

* Support specifying fork blocks.

* make for_blocks work

* Support forks correctly.

* Add a bunch of docs.

* Make fork blocks optional.

* Add missing docs.

* Fix build.

* Use struct for check_block params.

* Fix tests?

* Clean up.
This commit is contained in:
Tomasz Drwięga
2019-09-28 19:05:36 +02:00
committed by Gavin Wood
parent c555b9bf88
commit 667ee95f5d
39 changed files with 1368 additions and 336 deletions
+28 -7
View File
@@ -47,7 +47,7 @@ use state_machine::{
};
use executor::{RuntimeVersion, RuntimeInfo};
use consensus::{
Error as ConsensusError, BlockStatus, BlockImportParams,
Error as ConsensusError, BlockStatus, BlockImportParams, BlockCheckParams,
ImportResult, BlockOrigin, ForkChoiceStrategy,
SelectChain, self,
};
@@ -87,6 +87,11 @@ type StorageUpdate<B, Block> = <
>::State as state_machine::Backend<Blake2Hasher>>::Transaction;
type ChangesUpdate<Block> = ChangesTrieTransaction<Blake2Hasher, NumberFor<Block>>;
/// Expected hashes of blocks at given heights.
///
/// This may be used as chain spec extension to filter out known, unwanted forks.
pub type ForkBlocks<Block> = Option<HashMap<NumberFor<Block>, <Block as BlockT>::Hash>>;
/// Execution strategies settings.
#[derive(Debug, Clone)]
pub struct ExecutionStrategies {
@@ -123,6 +128,7 @@ pub struct Client<B, E, Block, RA> where Block: BlockT {
finality_notification_sinks: Mutex<Vec<mpsc::UnboundedSender<FinalityNotification<Block>>>>,
// holds the block hash currently being imported. TODO: replace this with block queue
importing_block: RwLock<Option<Block::Hash>>,
fork_blocks: ForkBlocks<Block>,
execution_strategies: ExecutionStrategies,
_phantom: PhantomData<RA>,
}
@@ -263,7 +269,7 @@ pub fn new_with_backend<B, E, Block, S, RA>(
B: backend::LocalBackend<Block, Blake2Hasher>
{
let call_executor = LocalCallExecutor::new(backend.clone(), executor, keystore);
Client::new(backend, call_executor, build_genesis_storage, Default::default())
Client::new(backend, call_executor, build_genesis_storage, Default::default(), Default::default())
}
/// Figure out the block type for a given type (for now, just a `Client`).
@@ -290,6 +296,7 @@ impl<B, E, Block, RA> Client<B, E, Block, RA> where
backend: Arc<B>,
executor: E,
build_genesis_storage: S,
fork_blocks: ForkBlocks<Block>,
execution_strategies: ExecutionStrategies
) -> error::Result<Self> {
if backend.blockchain().header(BlockId::Number(Zero::zero()))?.is_none() {
@@ -318,6 +325,7 @@ impl<B, E, Block, RA> Client<B, E, Block, RA> where
import_notification_sinks: Default::default(),
finality_notification_sinks: Default::default(),
importing_block: Default::default(),
fork_blocks,
execution_strategies,
_phantom: Default::default(),
})
@@ -1499,9 +1507,22 @@ impl<'a, B, E, Block, RA> consensus::BlockImport<Block> for &'a Client<B, E, Blo
/// Check block preconditions.
fn check_block(
&mut self,
hash: Block::Hash,
parent_hash: Block::Hash,
block: BlockCheckParams<Block>,
) -> Result<ImportResult, Self::Error> {
let BlockCheckParams { hash, number, parent_hash } = block;
if let Some(h) = self.fork_blocks.as_ref().and_then(|x| x.get(&number)) {
if &hash != h {
trace!(
"Rejecting block from known invalid fork. Got {:?}, expected: {:?} at height {}",
hash,
h,
number
);
return Ok(ImportResult::KnownBad);
}
}
match self.block_status(&BlockId::Hash(parent_hash))
.map_err(|e| ConsensusError::ClientImport(e.to_string()))?
{
@@ -1518,6 +1539,7 @@ impl<'a, B, E, Block, RA> consensus::BlockImport<Block> for &'a Client<B, E, Blo
BlockStatus::KnownBad => return Ok(ImportResult::KnownBad),
}
Ok(ImportResult::imported(false))
}
}
@@ -1539,10 +1561,9 @@ impl<B, E, Block, RA> consensus::BlockImport<Block> for Client<B, E, Block, RA>
fn check_block(
&mut self,
hash: Block::Hash,
parent_hash: Block::Hash,
block: BlockCheckParams<Block>,
) -> Result<ImportResult, Self::Error> {
(&*self).check_block(hash, parent_hash)
(&*self).check_block(block)
}
}