// Copyright 2017-2018 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // Substrate is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . //! Substrate service components. use std::sync::Arc; use std::marker::PhantomData; use std::ops::Deref; use serde::{Serialize, de::DeserializeOwned}; use tokio::runtime::TaskExecutor; use chain_spec::ChainSpec; use client_db; use client::{self, Client}; use {error, Service}; use network::{self, OnDemand, import_queue::ImportQueue}; use substrate_executor::{NativeExecutor, NativeExecutionDispatch}; use transaction_pool::txpool::{self, Options as TransactionPoolOptions, Pool as TransactionPool}; use runtime_primitives::{traits::Block as BlockT, traits::Header as HeaderT, BuildStorage}; use config::Configuration; use primitives::{H256, Blake2Hasher}; // Type aliases. // These exist mainly to avoid typing `::Foo` all over the code. /// Network service type for a factory. pub type NetworkService = network::Service< ::Block, ::NetworkProtocol, <::Block as BlockT>::Hash, >; /// Code executor type for a factory. pub type CodeExecutor = NativeExecutor<::RuntimeDispatch>; /// Full client backend type for a factory. pub type FullBackend = client_db::Backend<::Block>; /// Full client executor type for a factory. pub type FullExecutor = client::LocalCallExecutor< client_db::Backend<::Block>, CodeExecutor, >; /// Light client backend type for a factory. pub type LightBackend = client::light::backend::Backend< client_db::light::LightStorage<::Block>, network::OnDemand<::Block, NetworkService>, >; /// Light client executor type for a factory. pub type LightExecutor = client::light::call_executor::RemoteCallExecutor< client::light::blockchain::Blockchain< client_db::light::LightStorage<::Block>, network::OnDemand<::Block, NetworkService> >, network::OnDemand<::Block, NetworkService>, Blake2Hasher, >; /// Full client type for a factory. pub type FullClient = Client, FullExecutor, ::Block>; /// Light client type for a factory. pub type LightClient = Client, LightExecutor, ::Block>; /// `ChainSpec` specialization for a factory. pub type FactoryChainSpec = ChainSpec<::Genesis>; /// `Genesis` specialization for a factory. pub type FactoryGenesis = ::Genesis; /// `Block` type for a factory. pub type FactoryBlock = ::Block; /// `Extrinsic` type for a factory. pub type FactoryExtrinsic = <::Block as BlockT>::Extrinsic; /// `Number` type for a factory. pub type FactoryBlockNumber = < as BlockT>::Header as HeaderT>::Number; /// Full `Configuration` type for a factory. pub type FactoryFullConfiguration = Configuration<::Configuration, FactoryGenesis>; /// Client type for `Components`. pub type ComponentClient = Client< ::Backend, ::Executor, FactoryBlock<::Factory> >; /// Block type for `Components` pub type ComponentBlock = <::Factory as ServiceFactory>::Block; /// Extrinsic hash type for `Components` pub type ComponentExHash = <::TransactionPoolApi as txpool::ChainApi>::Hash; /// Extrinsic type. pub type ComponentExtrinsic = as BlockT>::Extrinsic; /// Extrinsic pool API type for `Components`. pub type PoolApi = ::TransactionPoolApi; /// A set of traits for the runtime genesis config. pub trait RuntimeGenesis: Serialize + DeserializeOwned + BuildStorage {} impl RuntimeGenesis for T {} /// A collection of types and methods to build a service on top of the substrate service. pub trait ServiceFactory: 'static + Sized { /// Block type. type Block: BlockT; /// Network protocol extensions. type NetworkProtocol: network::specialization::Specialization; /// Chain runtime. type RuntimeDispatch: NativeExecutionDispatch + Send + Sync + 'static; /// Extrinsic pool backend type for the full client. type FullTransactionPoolApi: txpool::ChainApi::Hash, Block = Self::Block> + Send + 'static; /// Extrinsic pool backend type for the light client. type LightTransactionPoolApi: txpool::ChainApi::Hash, Block = Self::Block> + 'static; /// Genesis configuration for the runtime. type Genesis: RuntimeGenesis; /// Other configuration for service members. type Configuration: Default; /// Extended full service type. type FullService: Deref>> + Send + Sync + 'static; /// Extended light service type. type LightService: Deref>> + Send + Sync + 'static; /// ImportQueue for full client type FullImportQueue: network::import_queue::ImportQueue + 'static; /// ImportQueue for light clients type LightImportQueue: network::import_queue::ImportQueue + 'static; //TODO: replace these with a constructor trait. that TransactionPool implements. /// Extrinsic pool constructor for the full client. fn build_full_transaction_pool(config: TransactionPoolOptions, client: Arc>) -> Result, error::Error>; /// Extrinsic pool constructor for the light client. fn build_light_transaction_pool(config: TransactionPoolOptions, client: Arc>) -> Result, error::Error>; /// Build network protocol. fn build_network_protocol(config: &FactoryFullConfiguration) -> Result; /// Build full service. fn new_full(config: FactoryFullConfiguration, executor: TaskExecutor) -> Result; /// Build light service. fn new_light(config: FactoryFullConfiguration, executor: TaskExecutor) -> Result; /// ImportQueue for a full client fn build_full_import_queue( config: &FactoryFullConfiguration, _client: Arc> ) -> Result { if let Some(name) = config.chain_spec.consensus_engine() { match name { _ => Err(format!("Chain Specification defines unknown consensus engine '{}'", name).into()) } } else { Err("Chain Specification doesn't contain any consensus_engine name".into()) } } /// ImportQueue for a light client fn build_light_import_queue( config: &FactoryFullConfiguration, _client: Arc> ) -> Result { if let Some(name) = config.chain_spec.consensus_engine() { match name { _ => Err(format!("Chain Specification defines unknown consensus engine '{}'", name).into()) } } else { Err("Chain Specification doesn't contain any consensus_engine name".into()) } } } /// A collection of types and function to generalise over full / light client type. pub trait Components: 'static { /// Associated service factory. type Factory: ServiceFactory; /// Client backend. type Backend: 'static + client::backend::Backend, Blake2Hasher>; /// Client executor. type Executor: 'static + client::CallExecutor, Blake2Hasher> + Send + Sync + Clone; /// Extrinsic pool type. type TransactionPoolApi: 'static + txpool::ChainApi< Hash = <::Block as BlockT>::Hash, Block = FactoryBlock >; /// Our Import Queue type ImportQueue: ImportQueue> + 'static; /// Create client. fn build_client( config: &FactoryFullConfiguration, executor: CodeExecutor, ) -> Result<( Arc>, Option, NetworkService>>> ), error::Error>; /// Create extrinsic pool. fn build_transaction_pool(config: TransactionPoolOptions, client: Arc>) -> Result, error::Error>; /// instance of import queue for clients fn build_import_queue( config: &FactoryFullConfiguration, client: Arc> ) -> Result; } /// A struct that implement `Components` for the full client. pub struct FullComponents { _factory: PhantomData, } impl Components for FullComponents { type Factory = Factory; type Executor = FullExecutor; type Backend = FullBackend; type TransactionPoolApi = ::FullTransactionPoolApi; type ImportQueue = Factory::FullImportQueue; fn build_client( config: &FactoryFullConfiguration, executor: CodeExecutor, ) -> Result<( Arc>, Option, NetworkService>>> ), error::Error> { let db_settings = client_db::DatabaseSettings { cache_size: None, path: config.database_path.as_str().into(), pruning: config.pruning.clone(), }; Ok((Arc::new(client_db::new_client( db_settings, executor, &config.chain_spec, config.block_execution_strategy, config.api_execution_strategy, )?), None)) } fn build_transaction_pool(config: TransactionPoolOptions, client: Arc>) -> Result, error::Error> { Factory::build_full_transaction_pool(config, client) } fn build_import_queue( config: &FactoryFullConfiguration, client: Arc> ) -> Result { Factory::build_full_import_queue(config, client) } } /// A struct that implement `Components` for the light client. pub struct LightComponents { _factory: PhantomData, } impl Components for LightComponents { type Factory = Factory; type Executor = LightExecutor; type Backend = LightBackend; type TransactionPoolApi = ::LightTransactionPoolApi; type ImportQueue = ::LightImportQueue; fn build_client( config: &FactoryFullConfiguration, executor: CodeExecutor, ) -> Result<( Arc>, Option, NetworkService>>> ), error::Error> { let db_settings = client_db::DatabaseSettings { cache_size: None, path: config.database_path.as_str().into(), pruning: config.pruning.clone(), }; let db_storage = client_db::light::LightStorage::new(db_settings)?; let light_blockchain = client::light::new_light_blockchain(db_storage); let fetch_checker = Arc::new(client::light::new_fetch_checker::<_, Blake2Hasher>(executor)); let fetcher = Arc::new(network::OnDemand::new(fetch_checker)); let client_backend = client::light::new_light_backend(light_blockchain, fetcher.clone()); let client = client::light::new_light(client_backend, fetcher.clone(), &config.chain_spec)?; Ok((Arc::new(client), Some(fetcher))) } fn build_transaction_pool(config: TransactionPoolOptions, client: Arc>) -> Result, error::Error> { Factory::build_light_transaction_pool(config, client) } fn build_import_queue( config: &FactoryFullConfiguration, client: Arc> ) -> Result { Factory::build_light_import_queue(config, client) } }