// Copyright 2017-2020 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 . //! Polkadot Client //! //! Provides the [`AbstractClient`] trait that is a super trait that combines all the traits the client implements. //! There is also the [`Client`] enum that combines all the different clients into one common structure. use std::sync::Arc; use sp_api::{ProvideRuntimeApi, CallApiAt, NumberFor}; use sp_blockchain::HeaderBackend; use sp_runtime::{ Justifications, generic::{BlockId, SignedBlock}, traits::{Block as BlockT, BlakeTwo256}, }; use sc_client_api::{Backend as BackendT, BlockchainEvents, KeyIterator, AuxStore, UsageProvider}; use sp_storage::{StorageData, StorageKey, ChildInfo, PrefixedStorageKey}; use polkadot_primitives::v1::{Block, ParachainHost, AccountId, Nonce, Balance, Header, BlockNumber, Hash}; use sp_consensus::BlockStatus; use sc_executor::native_executor_instance; pub type FullBackend = sc_service::TFullBackend; pub type FullClient = sc_service::TFullClient; native_executor_instance!( pub PolkadotExecutor, polkadot_runtime::api::dispatch, polkadot_runtime::native_version, frame_benchmarking::benchmarking::HostFunctions, ); #[cfg(feature = "kusama")] native_executor_instance!( pub KusamaExecutor, kusama_runtime::api::dispatch, kusama_runtime::native_version, frame_benchmarking::benchmarking::HostFunctions, ); #[cfg(feature = "westend")] native_executor_instance!( pub WestendExecutor, westend_runtime::api::dispatch, westend_runtime::native_version, frame_benchmarking::benchmarking::HostFunctions, ); #[cfg(feature = "rococo")] native_executor_instance!( pub RococoExecutor, rococo_runtime::api::dispatch, rococo_runtime::native_version, frame_benchmarking::benchmarking::HostFunctions, ); /// A set of APIs that polkadot-like runtimes must implement. pub trait RuntimeApiCollection: sp_transaction_pool::runtime_api::TaggedTransactionQueue + sp_api::ApiExt + sp_consensus_babe::BabeApi + sp_finality_grandpa::GrandpaApi + ParachainHost + sp_block_builder::BlockBuilder + frame_system_rpc_runtime_api::AccountNonceApi + pallet_mmr_primitives::MmrApi::Hash> + pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi + sp_api::Metadata + sp_offchain::OffchainWorkerApi + sp_session::SessionKeys + sp_authority_discovery::AuthorityDiscoveryApi + beefy_primitives::BeefyApi where >::StateBackend: sp_api::StateBackend, {} impl RuntimeApiCollection for Api where Api: sp_transaction_pool::runtime_api::TaggedTransactionQueue + sp_api::ApiExt + sp_consensus_babe::BabeApi + sp_finality_grandpa::GrandpaApi + ParachainHost + sp_block_builder::BlockBuilder + frame_system_rpc_runtime_api::AccountNonceApi + pallet_mmr_primitives::MmrApi::Hash> + pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi + sp_api::Metadata + sp_offchain::OffchainWorkerApi + sp_session::SessionKeys + sp_authority_discovery::AuthorityDiscoveryApi + beefy_primitives::BeefyApi, >::StateBackend: sp_api::StateBackend, {} /// Trait that abstracts over all available client implementations. /// /// For a concrete type there exists [`Client`]. pub trait AbstractClient: BlockchainEvents + Sized + Send + Sync + ProvideRuntimeApi + HeaderBackend + CallApiAt< Block, StateBackend = Backend::State > + AuxStore + UsageProvider where Block: BlockT, Backend: BackendT, Backend::State: sp_api::StateBackend, Self::Api: RuntimeApiCollection, {} impl AbstractClient for Client where Block: BlockT, Backend: BackendT, Backend::State: sp_api::StateBackend, Client: BlockchainEvents + ProvideRuntimeApi + HeaderBackend + AuxStore + UsageProvider + Sized + Send + Sync + CallApiAt< Block, StateBackend = Backend::State >, Client::Api: RuntimeApiCollection, {} /// Execute something with the client instance. /// /// As there exist multiple chains inside Polkadot, like Polkadot itself, Kusama, Westend etc, /// there can exist different kinds of client types. As these client types differ in the generics /// that are being used, we can not easily return them from a function. For returning them from a /// function there exists [`Client`]. However, the problem on how to use this client instance still /// exists. This trait "solves" it in a dirty way. It requires a type to implement this trait and /// than the [`execute_with_client`](ExecuteWithClient::execute_with_client) function can be called /// with any possible client instance. /// /// In a perfect world, we could make a closure work in this way. pub trait ExecuteWithClient { /// The return type when calling this instance. type Output; /// Execute whatever should be executed with the given client instance. fn execute_with_client(self, client: Arc) -> Self::Output where >::StateBackend: sp_api::StateBackend, Backend: sc_client_api::Backend + 'static, Backend::State: sp_api::StateBackend, Api: crate::RuntimeApiCollection, Client: AbstractClient + 'static; } /// A handle to a Polkadot client instance. /// /// The Polkadot service supports multiple different runtimes (Westend, Polkadot itself, etc). As each runtime has a /// specialized client, we need to hide them behind a trait. This is this trait. /// /// When wanting to work with the inner client, you need to use `execute_with`. /// /// See [`ExecuteWithClient`](trait.ExecuteWithClient.html) for more information. pub trait ClientHandle { /// Execute the given something with the client. fn execute_with(&self, t: T) -> T::Output; } macro_rules! with_client { { $self:ident, $client:ident, { $( $code:tt )* } } => { match $self { Self::Polkadot($client) => { $( $code )* }, #[cfg(feature = "westend")] Self::Westend($client) => { $( $code )* }, #[cfg(feature = "kusama")] Self::Kusama($client) => { $( $code )* }, #[cfg(feature = "rococo")] Self::Rococo($client) => { $( $code )* }, } } } /// A client instance of Polkadot. /// /// See [`ExecuteWithClient`] for more information. #[derive(Clone)] pub enum Client { Polkadot(Arc>), #[cfg(feature = "westend")] Westend(Arc>), #[cfg(feature = "kusama")] Kusama(Arc>), #[cfg(feature = "rococo")] Rococo(Arc>), } impl ClientHandle for Client { fn execute_with(&self, t: T) -> T::Output { with_client! { self, client, { T::execute_with_client::<_, _, FullBackend>(t, client.clone()) } } } } impl UsageProvider for Client { fn usage_info(&self) -> sc_client_api::ClientInfo { with_client! { self, client, { client.usage_info() } } } } impl sc_client_api::BlockBackend for Client { fn block_body( &self, id: &BlockId ) -> sp_blockchain::Result::Extrinsic>>> { with_client! { self, client, { client.block_body(id) } } } fn block(&self, id: &BlockId) -> sp_blockchain::Result>> { with_client! { self, client, { client.block(id) } } } fn block_status(&self, id: &BlockId) -> sp_blockchain::Result { with_client! { self, client, { client.block_status(id) } } } fn justifications( &self, id: &BlockId ) -> sp_blockchain::Result> { with_client! { self, client, { client.justifications(id) } } } fn block_hash( &self, number: NumberFor ) -> sp_blockchain::Result::Hash>> { with_client! { self, client, { client.block_hash(number) } } } fn indexed_transaction( &self, id: &::Hash ) -> sp_blockchain::Result>> { with_client! { self, client, { client.indexed_transaction(id) } } } fn block_indexed_body( &self, id: &BlockId ) -> sp_blockchain::Result>>> { with_client! { self, client, { client.block_indexed_body(id) } } } } impl sc_client_api::StorageProvider for Client { fn storage( &self, id: &BlockId, key: &StorageKey, ) -> sp_blockchain::Result> { with_client! { self, client, { client.storage(id, key) } } } fn storage_keys( &self, id: &BlockId, key_prefix: &StorageKey, ) -> sp_blockchain::Result> { with_client! { self, client, { client.storage_keys(id, key_prefix) } } } fn storage_hash( &self, id: &BlockId, key: &StorageKey, ) -> sp_blockchain::Result::Hash>> { with_client! { self, client, { client.storage_hash(id, key) } } } fn storage_pairs( &self, id: &BlockId, key_prefix: &StorageKey, ) -> sp_blockchain::Result> { with_client! { self, client, { client.storage_pairs(id, key_prefix) } } } fn storage_keys_iter<'a>( &self, id: &BlockId, prefix: Option<&'a StorageKey>, start_key: Option<&StorageKey>, ) -> sp_blockchain::Result>::State, Block>> { with_client! { self, client, { client.storage_keys_iter(id, prefix, start_key) } } } fn child_storage( &self, id: &BlockId, child_info: &ChildInfo, key: &StorageKey, ) -> sp_blockchain::Result> { with_client! { self, client, { client.child_storage(id, child_info, key) } } } fn child_storage_keys( &self, id: &BlockId, child_info: &ChildInfo, key_prefix: &StorageKey, ) -> sp_blockchain::Result> { with_client! { self, client, { client.child_storage_keys(id, child_info, key_prefix) } } } fn child_storage_keys_iter<'a>( &self, id: &BlockId, child_info: ChildInfo, prefix: Option<&'a StorageKey>, start_key: Option<&StorageKey>, ) -> sp_blockchain::Result>::State, Block>> { with_client! { self, client, { client.child_storage_keys_iter(id, child_info, prefix, start_key) } } } fn child_storage_hash( &self, id: &BlockId, child_info: &ChildInfo, key: &StorageKey, ) -> sp_blockchain::Result::Hash>> { with_client! { self, client, { client.child_storage_hash(id, child_info, key) } } } fn max_key_changes_range( &self, first: NumberFor, last: BlockId, ) -> sp_blockchain::Result, BlockId)>> { with_client! { self, client, { client.max_key_changes_range(first, last) } } } fn key_changes( &self, first: NumberFor, last: BlockId, storage_key: Option<&PrefixedStorageKey>, key: &StorageKey, ) -> sp_blockchain::Result, u32)>> { with_client! { self, client, { client.key_changes(first, last, storage_key, key) } } } } impl sp_blockchain::HeaderBackend for Client { fn header(&self, id: BlockId) -> sp_blockchain::Result> { with_client! { self, client, { client.header(&id) } } } fn info(&self) -> sp_blockchain::Info { with_client! { self, client, { client.info() } } } fn status(&self, id: BlockId) -> sp_blockchain::Result { with_client! { self, client, { client.status(id) } } } fn number(&self, hash: Hash) -> sp_blockchain::Result> { with_client! { self, client, { client.number(hash) } } } fn hash(&self, number: BlockNumber) -> sp_blockchain::Result> { with_client! { self, client, { client.hash(number) } } } }