// 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 meta trait use std::sync::Arc; use sp_api::{ProvideRuntimeApi, CallApiAt, NumberFor}; use sp_blockchain::HeaderBackend; use sp_runtime::{ Justification, generic::{BlockId, SignedBlock}, traits::{Block as BlockT, BlakeTwo256}, }; use sc_client_api::{Backend as BackendT, BlockchainEvents, KeyIterator}; use sp_storage::{StorageData, StorageKey, ChildInfo, PrefixedStorageKey}; use polkadot_primitives::v1::{Block, ParachainHost, AccountId, Nonce, Balance}; use consensus_common::BlockStatus; /// A set of APIs that polkadot-like runtimes must implement. pub trait RuntimeApiCollection: sp_transaction_pool::runtime_api::TaggedTransactionQueue + sp_api::ApiExt + babe_primitives::BabeApi + grandpa_primitives::GrandpaApi + ParachainHost + sp_block_builder::BlockBuilder + frame_system_rpc_runtime_api::AccountNonceApi + pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi + sp_api::Metadata + sp_offchain::OffchainWorkerApi + sp_session::SessionKeys + authority_discovery_primitives::AuthorityDiscoveryApi where >::StateBackend: sp_api::StateBackend, {} impl RuntimeApiCollection for Api where Api: sp_transaction_pool::runtime_api::TaggedTransactionQueue + sp_api::ApiExt + babe_primitives::BabeApi + grandpa_primitives::GrandpaApi + ParachainHost + sp_block_builder::BlockBuilder + frame_system_rpc_runtime_api::AccountNonceApi + pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi + sp_api::Metadata + sp_offchain::OffchainWorkerApi + sp_session::SessionKeys + authority_discovery_primitives::AuthorityDiscoveryApi, >::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, Error = sp_blockchain::Error, StateBackend = Backend::State > 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 + Sized + Send + Sync + CallApiAt< Block, Error = sp_blockchain::Error, 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, 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; } /// A client instance of Polkadot. /// /// See [`ExecuteWithClient`] for more information. #[derive(Clone)] pub enum Client { Polkadot(Arc>), Westend(Arc>), Kusama(Arc>), } impl ClientHandle for Client { fn execute_with(&self, t: T) -> T::Output { match self { Self::Polkadot(client) => { T::execute_with_client::<_, _, crate::FullBackend>(t, client.clone()) }, Self::Westend(client) => { T::execute_with_client::<_, _, crate::FullBackend>(t, client.clone()) }, Self::Kusama(client) => { T::execute_with_client::<_, _, crate::FullBackend>(t, client.clone()) }, } } } impl sc_client_api::UsageProvider for Client { fn usage_info(&self) -> sc_client_api::ClientInfo { match self { Self::Polkadot(client) => client.usage_info(), Self::Westend(client) => client.usage_info(), Self::Kusama(client) => client.usage_info(), } } } impl sc_client_api::BlockBackend for Client { fn block_body( &self, id: &BlockId ) -> sp_blockchain::Result::Extrinsic>>> { match self { Self::Polkadot(client) => client.block_body(id), Self::Westend(client) => client.block_body(id), Self::Kusama(client) => client.block_body(id), } } fn block(&self, id: &BlockId) -> sp_blockchain::Result>> { match self { Self::Polkadot(client) => client.block(id), Self::Westend(client) => client.block(id), Self::Kusama(client) => client.block(id), } } fn block_status(&self, id: &BlockId) -> sp_blockchain::Result { match self { Self::Polkadot(client) => client.block_status(id), Self::Westend(client) => client.block_status(id), Self::Kusama(client) => client.block_status(id), } } fn justification( &self, id: &BlockId ) -> sp_blockchain::Result> { match self { Self::Polkadot(client) => client.justification(id), Self::Westend(client) => client.justification(id), Self::Kusama(client) => client.justification(id), } } fn block_hash( &self, number: NumberFor ) -> sp_blockchain::Result::Hash>> { match self { Self::Polkadot(client) => client.block_hash(number), Self::Westend(client) => client.block_hash(number), Self::Kusama(client) => client.block_hash(number), } } } impl sc_client_api::StorageProvider for Client { fn storage( &self, id: &BlockId, key: &StorageKey, ) -> sp_blockchain::Result> { match self { Self::Polkadot(client) => client.storage(id, key), Self::Westend(client) => client.storage(id, key), Self::Kusama(client) => client.storage(id, key), } } fn storage_keys( &self, id: &BlockId, key_prefix: &StorageKey, ) -> sp_blockchain::Result> { match self { Self::Polkadot(client) => client.storage_keys(id, key_prefix), Self::Westend(client) => client.storage_keys(id, key_prefix), Self::Kusama(client) => client.storage_keys(id, key_prefix), } } fn storage_hash( &self, id: &BlockId, key: &StorageKey, ) -> sp_blockchain::Result::Hash>> { match self { Self::Polkadot(client) => client.storage_hash(id, key), Self::Westend(client) => client.storage_hash(id, key), Self::Kusama(client) => client.storage_hash(id, key), } } fn storage_pairs( &self, id: &BlockId, key_prefix: &StorageKey, ) -> sp_blockchain::Result> { match self { Self::Polkadot(client) => client.storage_pairs(id, key_prefix), Self::Westend(client) => client.storage_pairs(id, key_prefix), Self::Kusama(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>> { match self { Self::Polkadot(client) => client.storage_keys_iter(id, prefix, start_key), Self::Westend(client) => client.storage_keys_iter(id, prefix, start_key), Self::Kusama(client) => client.storage_keys_iter(id, prefix, start_key), } } fn child_storage( &self, id: &BlockId, child_info: &ChildInfo, key: &StorageKey, ) -> sp_blockchain::Result> { match self { Self::Polkadot(client) => client.child_storage(id, child_info, key), Self::Westend(client) => client.child_storage(id, child_info, key), Self::Kusama(client) => client.child_storage(id, child_info, key), } } fn child_storage_keys( &self, id: &BlockId, child_info: &ChildInfo, key_prefix: &StorageKey, ) -> sp_blockchain::Result> { match self { Self::Polkadot(client) => client.child_storage_keys(id, child_info, key_prefix), Self::Westend(client) => client.child_storage_keys(id, child_info, key_prefix), Self::Kusama(client) => client.child_storage_keys(id, child_info, key_prefix), } } fn child_storage_hash( &self, id: &BlockId, child_info: &ChildInfo, key: &StorageKey, ) -> sp_blockchain::Result::Hash>> { match self { Self::Polkadot(client) => client.child_storage_hash(id, child_info, key), Self::Westend(client) => client.child_storage_hash(id, child_info, key), Self::Kusama(client) => client.child_storage_hash(id, child_info, key), } } fn max_key_changes_range( &self, first: NumberFor, last: BlockId, ) -> sp_blockchain::Result, BlockId)>> { match self { Self::Polkadot(client) => client.max_key_changes_range(first, last), Self::Westend(client) => client.max_key_changes_range(first, last), Self::Kusama(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)>> { match self { Self::Polkadot(client) => client.key_changes(first, last, storage_key, key), Self::Westend(client) => client.key_changes(first, last, storage_key, key), Self::Kusama(client) => client.key_changes(first, last, storage_key, key), } } }