// 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 polkadot_primitives::{
runtime_api::ParachainHost, AccountId, Balance, Block, BlockNumber, Hash, Header, Nonce,
};
use sc_client_api::{
AuxStore, Backend as BackendT, BlockchainEvents, KeysIter, PairsIter, UsageProvider,
};
use sc_executor::NativeElseWasmExecutor;
use sp_api::{CallApiAt, Encode, NumberFor, ProvideRuntimeApi};
use sp_blockchain::{HeaderBackend, HeaderMetadata};
use sp_consensus::BlockStatus;
use sp_runtime::{
generic::SignedBlock,
traits::{BlakeTwo256, Block as BlockT},
Justifications,
};
use sp_storage::{ChildInfo, StorageData, StorageKey};
use std::sync::Arc;
pub mod benchmarking;
pub type FullBackend = sc_service::TFullBackend;
pub type FullClient =
sc_service::TFullClient>;
#[cfg(not(any(
feature = "rococo",
feature = "kusama",
feature = "westend",
feature = "polkadot"
)))]
compile_error!("at least one runtime feature must be enabled");
/// The native executor instance for Polkadot.
#[cfg(feature = "polkadot")]
pub struct PolkadotExecutorDispatch;
#[cfg(feature = "polkadot")]
impl sc_executor::NativeExecutionDispatch for PolkadotExecutorDispatch {
type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions;
fn dispatch(method: &str, data: &[u8]) -> Option> {
polkadot_runtime::api::dispatch(method, data)
}
fn native_version() -> sc_executor::NativeVersion {
polkadot_runtime::native_version()
}
}
#[cfg(feature = "kusama")]
/// The native executor instance for Kusama.
pub struct KusamaExecutorDispatch;
#[cfg(feature = "kusama")]
impl sc_executor::NativeExecutionDispatch for KusamaExecutorDispatch {
type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions;
fn dispatch(method: &str, data: &[u8]) -> Option> {
kusama_runtime::api::dispatch(method, data)
}
fn native_version() -> sc_executor::NativeVersion {
kusama_runtime::native_version()
}
}
#[cfg(feature = "westend")]
/// The native executor instance for Westend.
pub struct WestendExecutorDispatch;
#[cfg(feature = "westend")]
impl sc_executor::NativeExecutionDispatch for WestendExecutorDispatch {
type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions;
fn dispatch(method: &str, data: &[u8]) -> Option> {
westend_runtime::api::dispatch(method, data)
}
fn native_version() -> sc_executor::NativeVersion {
westend_runtime::native_version()
}
}
#[cfg(feature = "rococo")]
/// The native executor instance for Rococo.
pub struct RococoExecutorDispatch;
#[cfg(feature = "rococo")]
impl sc_executor::NativeExecutionDispatch for RococoExecutorDispatch {
type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions;
fn dispatch(method: &str, data: &[u8]) -> Option> {
rococo_runtime::api::dispatch(method, data)
}
fn native_version() -> sc_executor::NativeVersion {
rococo_runtime::native_version()
}
}
/// 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_consensus_grandpa::GrandpaApi
+ ParachainHost
+ sp_block_builder::BlockBuilder
+ frame_system_rpc_runtime_api::AccountNonceApi
+ sp_mmr_primitives::MmrApi::Hash, BlockNumber>
+ pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi
+ sp_api::Metadata
+ sp_offchain::OffchainWorkerApi
+ sp_session::SessionKeys
+ sp_authority_discovery::AuthorityDiscoveryApi
+ sp_consensus_beefy::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_consensus_grandpa::GrandpaApi
+ ParachainHost
+ sp_block_builder::BlockBuilder
+ frame_system_rpc_runtime_api::AccountNonceApi
+ sp_mmr_primitives::MmrApi::Hash, BlockNumber>
+ pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi
+ sp_api::Metadata
+ sp_offchain::OffchainWorkerApi
+ sp_session::SessionKeys
+ sp_authority_discovery::AuthorityDiscoveryApi
+ sp_consensus_beefy::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
+ AuxStore
+ UsageProvider
+ HeaderMetadata
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
+ HeaderMetadata,
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;
}
/// Unwraps a [`Client`] into the concrete client type and
/// provides the concrete runtime as `runtime`.
macro_rules! with_client {
{
// The client instance that should be unwrapped.
$self:expr,
// The name that the unwrapped client will have.
$client:ident,
// NOTE: Using an expression here is fine since blocks are also expressions.
$code:expr
} => {
match $self {
#[cfg(feature = "polkadot")]
Client::Polkadot($client) => {
#[allow(unused_imports)]
use polkadot_runtime as runtime;
$code
},
#[cfg(feature = "westend")]
Client::Westend($client) => {
#[allow(unused_imports)]
use westend_runtime as runtime;
$code
},
#[cfg(feature = "kusama")]
Client::Kusama($client) => {
#[allow(unused_imports)]
use kusama_runtime as runtime;
$code
},
#[cfg(feature = "rococo")]
Client::Rococo($client) => {
#[allow(unused_imports)]
use rococo_runtime as runtime;
$code
},
}
}
}
// Make the macro available only within this crate.
pub(crate) use with_client;
/// A client instance of Polkadot.
///
/// See [`ExecuteWithClient`] for more information.
#[derive(Clone)]
pub enum Client {
#[cfg(feature = "polkadot")]
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,
hash: ::Hash,
) -> sp_blockchain::Result