// Copyright 2017 Parity Technologies (UK) Ltd. // This file is part of Polkadot. // Polkadot 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. // Polkadot 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 Polkadot. If not, see . #![warn(unused_extern_crates)] //! Polkadot service. Specialized wrapper over substrate service. extern crate ed25519; extern crate polkadot_primitives; extern crate polkadot_runtime; extern crate polkadot_executor; extern crate polkadot_api; extern crate polkadot_consensus as consensus; extern crate polkadot_transaction_pool as transaction_pool; extern crate polkadot_network; extern crate substrate_primitives as primitives; extern crate substrate_network as network; extern crate substrate_codec as codec; extern crate substrate_client as client; extern crate substrate_service as service; extern crate tokio; #[macro_use] extern crate log; #[macro_use] extern crate hex_literal; pub mod chain_spec; use std::sync::Arc; use std::collections::HashMap; use codec::Encode; use transaction_pool::TransactionPool; use polkadot_api::{PolkadotApi, light::RemotePolkadotApiWrapper}; use polkadot_primitives::{Block, BlockId, Hash}; use polkadot_runtime::GenesisConfig; use client::Client; use polkadot_network::{PolkadotProtocol, consensus::ConsensusNetwork}; use tokio::runtime::TaskExecutor; pub use service::{Configuration, Roles, PruningMode, ExtrinsicPoolOptions, ErrorKind, Error, ComponentBlock, LightComponents, FullComponents}; pub use client::ExecutionStrategy; /// Specialised polkadot `ChainSpec`. pub type ChainSpec = service::ChainSpec; /// Polkadot client type for specialised `Components`. pub type ComponentClient = Client<::Backend, ::Executor, Block>; pub type NetworkService = network::Service::NetworkProtocol>; /// A collection of type to generalise Polkadot specific components over full / light client. pub trait Components: service::Components { /// Polkadot API. type Api: 'static + PolkadotApi + Send + Sync; /// Client backend. type Backend: 'static + client::backend::Backend; /// Client executor. type Executor: 'static + client::CallExecutor + Send + Sync; } impl Components for service::LightComponents { type Api = RemotePolkadotApiWrapper< as service::Components>::Backend, as service::Components>::Executor, >; type Executor = service::LightExecutor; type Backend = service::LightBackend; } impl Components for service::FullComponents { type Api = service::FullClient; type Executor = service::FullExecutor; type Backend = service::FullBackend; } /// Polkadot config for the substrate service. pub struct Factory; impl service::ServiceFactory for Factory { type Block = Block; type NetworkProtocol = PolkadotProtocol; type RuntimeDispatch = polkadot_executor::Executor; type FullExtrinsicPool = TransactionPoolAdapter< service::FullBackend, service::FullExecutor, service::FullClient >; type LightExtrinsicPool = TransactionPoolAdapter< service::LightBackend, service::LightExecutor, RemotePolkadotApiWrapper, service::LightExecutor> >; type Genesis = GenesisConfig; const NETWORK_PROTOCOL_ID: network::ProtocolId = ::polkadot_network::DOT_PROTOCOL_ID; fn build_full_extrinsic_pool(config: ExtrinsicPoolOptions, client: Arc>) -> Result { let api = client.clone(); Ok(TransactionPoolAdapter { pool: Arc::new(TransactionPool::new(config, api)), client: client, imports_external_transactions: true, }) } fn build_light_extrinsic_pool(config: ExtrinsicPoolOptions, client: Arc>) -> Result { let api = Arc::new(RemotePolkadotApiWrapper(client.clone())); Ok(TransactionPoolAdapter { pool: Arc::new(TransactionPool::new(config, api)), client: client, imports_external_transactions: false, }) } } /// Polkadot service. pub struct Service { inner: service::Service, client: Arc>, network: Arc, api: Arc<::Api>, _consensus: Option, } impl Service { pub fn client(&self) -> Arc> { self.client.clone() } pub fn network(&self) -> Arc { self.network.clone() } pub fn api(&self) -> Arc<::Api> { self.api.clone() } } /// Creates light client and register protocol with the network service pub fn new_light(config: Configuration, executor: TaskExecutor) -> Result>, Error> { let service = service::Service::>::new(config, executor)?; let api = Arc::new(RemotePolkadotApiWrapper(service.client())); Ok(Service { client: service.client(), network: service.network(), api: api, inner: service, _consensus: None, }) } /// Creates full client and register protocol with the network service pub fn new_full(config: Configuration, executor: TaskExecutor) -> Result>, Error> { let is_validator = (config.roles & Roles::AUTHORITY) == Roles::AUTHORITY; let service = service::Service::>::new(config, executor.clone())?; // Spin consensus service if configured let consensus = if is_validator { // Load the first available key let key = service.keystore().load(&service.keystore().contents()?[0], "")?; info!("Using authority key {}", key.public()); let client = service.client(); let consensus_net = ConsensusNetwork::new(service.network(), client.clone()); Some(consensus::Service::new( client.clone(), client.clone(), consensus_net, service.extrinsic_pool(), executor, ::std::time::Duration::from_millis(4000), // TODO: dynamic key, )) } else { None }; Ok(Service { client: service.client(), network: service.network(), api: service.client(), inner: service, _consensus: consensus, }) } /// Creates bare client without any networking. pub fn new_client(config: Configuration) -> Result>>, Error> { service::new_client::(config) } impl ::std::ops::Deref for Service { type Target = service::Service; fn deref(&self) -> &Self::Target { &self.inner } } /// Transaction pool adapter. pub struct TransactionPoolAdapter where A: Send + Sync, E: Send + Sync { imports_external_transactions: bool, pool: Arc>, client: Arc>, } impl TransactionPoolAdapter where A: Send + Sync, B: client::backend::Backend + Send + Sync, E: client::CallExecutor + Send + Sync, { fn best_block_id(&self) -> Option { self.client.info() .map(|info| BlockId::hash(info.chain.best_hash)) .map_err(|e| { debug!("Error getting best block: {:?}", e); }) .ok() } } impl network::TransactionPool for TransactionPoolAdapter where B: client::backend::Backend + Send + Sync, E: client::CallExecutor + Send + Sync, A: polkadot_api::PolkadotApi + Send + Sync, { fn transactions(&self) -> Vec<(Hash, Vec)> { let best_block_id = match self.best_block_id() { Some(id) => id, None => return vec![], }; self.pool.cull_and_get_pending(best_block_id, |pending| pending .map(|t| { let hash = t.hash().clone(); (hash, t.primitive_extrinsic()) }) .collect() ).unwrap_or_else(|e| { warn!("Error retrieving pending set: {}", e); vec![] }) } fn import(&self, transaction: &Vec) -> Option { if !self.imports_external_transactions { return None; } let encoded = transaction.encode(); if let Some(uxt) = codec::Decode::decode(&mut &encoded[..]) { let best_block_id = self.best_block_id()?; match self.pool.import_unchecked_extrinsic(best_block_id, uxt) { Ok(xt) => Some(*xt.hash()), Err(e) => match *e.kind() { transaction_pool::ErrorKind::AlreadyImported(hash) => Some(hash[..].into()), _ => { debug!("Error adding transaction to the pool: {:?}", e); None }, } } } else { debug!("Error decoding transaction"); None } } fn on_broadcasted(&self, propagations: HashMap>) { self.pool.on_broadcasted(propagations) } } impl service::ExtrinsicPool for TransactionPoolAdapter where B: client::backend::Backend + Send + Sync + 'static, E: client::CallExecutor + Send + Sync + 'static, A: polkadot_api::PolkadotApi + Send + Sync + 'static, { type Api = TransactionPool; fn prune_imported(&self, hash: &Hash) { let block = BlockId::hash(*hash); if let Err(e) = self.pool.cull(block) { warn!("Culling error: {:?}", e); } if let Err(e) = self.pool.retry_verification(block) { warn!("Re-verifying error: {:?}", e); } } fn api(&self) -> Arc { self.pool.clone() } }