Rewrite client handling (#1531)

* Rewrite client handling

We are supporting muliple polkadot-like chains and all have different
client types. This pr reworks the client handling by having all of them
in one enum combined. Besides that, there is added a special trait
`ExecuteWithClient` to use the internal client.

* Apply suggestions from code review

Co-authored-by: Robert Habermeier <rphmeier@gmail.com>

* Up the versions

* Fix Cargo.lock

* Fix merge conflict

* ......................

* ....v2

* yep

* I'm dumb...

* Browser lol

Co-authored-by: Robert Habermeier <rphmeier@gmail.com>
This commit is contained in:
Bastian Köcher
2020-08-04 14:53:47 +02:00
committed by GitHub
parent 07a9d2de3f
commit c01aa8bae8
10 changed files with 365 additions and 382 deletions
+111 -14
View File
@@ -14,40 +14,137 @@
// You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
//! Polkadot Client meta trait
//! Polkadot Client abstractions.
use sp_api::{ProvideRuntimeApi, ConstructRuntimeApi, CallApiAt};
use std::sync::Arc;
use sp_api::{ProvideRuntimeApi, CallApiAt};
use sp_blockchain::HeaderBackend;
use sp_runtime::traits::Block as BlockT;
use sp_runtime::traits::{Block as BlockT, BlakeTwo256};
use sc_client_api::{Backend as BackendT, BlockchainEvents};
use polkadot_primitives::v0::{Block, ParachainHost, AccountId, Nonce, Balance};
/// Polkadot client abstraction, this super trait only pulls in functionality required for
/// polkadot internal crates like polkadot-collator.
pub trait PolkadotClient<Block, Backend, Runtime>:
/// A set of APIs that polkadot-like runtimes must implement.
pub trait RuntimeApiCollection:
sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block>
+ sp_api::ApiExt<Block, Error = sp_blockchain::Error>
+ babe_primitives::BabeApi<Block>
+ grandpa_primitives::GrandpaApi<Block>
+ ParachainHost<Block>
+ sp_block_builder::BlockBuilder<Block>
+ system_rpc_runtime_api::AccountNonceApi<Block, AccountId, Nonce>
+ pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<Block, Balance>
+ sp_api::Metadata<Block>
+ sp_offchain::OffchainWorkerApi<Block>
+ sp_session::SessionKeys<Block>
+ authority_discovery_primitives::AuthorityDiscoveryApi<Block>
where
<Self as sp_api::ApiExt<Block>>::StateBackend: sp_api::StateBackend<BlakeTwo256>,
{}
impl<Api> RuntimeApiCollection for Api
where
Api:
sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block>
+ sp_api::ApiExt<Block, Error = sp_blockchain::Error>
+ babe_primitives::BabeApi<Block>
+ grandpa_primitives::GrandpaApi<Block>
+ ParachainHost<Block>
+ sp_block_builder::BlockBuilder<Block>
+ system_rpc_runtime_api::AccountNonceApi<Block, AccountId, Nonce>
+ pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<Block, Balance>
+ sp_api::Metadata<Block>
+ sp_offchain::OffchainWorkerApi<Block>
+ sp_session::SessionKeys<Block>
+ authority_discovery_primitives::AuthorityDiscoveryApi<Block>,
<Self as sp_api::ApiExt<Block>>::StateBackend: sp_api::StateBackend<BlakeTwo256>,
{}
/// Trait that abstracts over all available client implementations.
///
/// For a concrete type there exists [`Client`].
pub trait AbstractClient<Block, Backend>:
BlockchainEvents<Block> + Sized + Send + Sync
+ ProvideRuntimeApi<Block, Api = Runtime::RuntimeApi>
+ ProvideRuntimeApi<Block>
+ HeaderBackend<Block>
+ CallApiAt<
Block,
Error = sp_blockchain::Error,
StateBackend = Backend ::State
StateBackend = Backend::State
>
where
Block: BlockT,
Backend: BackendT<Block>,
Runtime: ConstructRuntimeApi<Block, Self>
Backend::State: sp_api::StateBackend<BlakeTwo256>,
Self::Api: RuntimeApiCollection<StateBackend = Backend::State>,
{}
impl<Block, Backend, Runtime, Client> PolkadotClient<Block, Backend, Runtime> for Client
impl<Block, Backend, Client> AbstractClient<Block, Backend> for Client
where
Block: BlockT,
Runtime: ConstructRuntimeApi<Block, Self>,
Backend: BackendT<Block>,
Client: BlockchainEvents<Block> + ProvideRuntimeApi<Block, Api = Runtime::RuntimeApi> + HeaderBackend<Block>
Backend::State: sp_api::StateBackend<BlakeTwo256>,
Client: BlockchainEvents<Block> + ProvideRuntimeApi<Block> + HeaderBackend<Block>
+ Sized + Send + Sync
+ CallApiAt<
Block,
Error = sp_blockchain::Error,
StateBackend = Backend ::State
>
StateBackend = Backend::State
>,
Client::Api: RuntimeApiCollection<StateBackend = Backend::State>,
{}
/// 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<Client, Api, Backend>(self, client: Arc<Client>) -> Self::Output
where
<Api as sp_api::ApiExt<Block>>::StateBackend: sp_api::StateBackend<BlakeTwo256>,
Backend: sc_client_api::Backend<Block>,
Backend::State: sp_api::StateBackend<BlakeTwo256>,
Api: crate::RuntimeApiCollection<StateBackend = Backend::State>,
Client: AbstractClient<Block, Backend, Api = Api> + 'static;
}
/// A client instance of Polkadot.
///
/// See [`ExecuteWithClient`] for more information.
#[derive(Clone)]
pub enum Client {
Polkadot(Arc<crate::FullClient<polkadot_runtime::RuntimeApi, crate::PolkadotExecutor>>),
Westend(Arc<crate::FullClient<westend_runtime::RuntimeApi, crate::WestendExecutor>>),
Kusama(Arc<crate::FullClient<kusama_runtime::RuntimeApi, crate::KusamaExecutor>>),
Rococo(Arc<crate::FullClient<rococo_runtime::RuntimeApi, crate::RococoExecutor>>),
}
impl Client {
/// Execute the given something with the client.
pub fn execute_with<T: ExecuteWithClient>(&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())
},
Self::Rococo(client) => {
T::execute_with_client::<_, _, crate::FullBackend>(t, client.clone())
}
}
}
}
+67 -142
View File
@@ -22,7 +22,7 @@ mod client;
use std::sync::Arc;
use std::time::Duration;
use polkadot_primitives::v0::{self as parachain, Hash, BlockId, AccountId, Nonce, Balance};
use polkadot_primitives::v0::{self as parachain, Hash, BlockId};
#[cfg(feature = "full-node")]
use polkadot_network::{legacy::gossip::Known, protocol as network_protocol};
use service::{error::Error as ServiceError};
@@ -52,7 +52,7 @@ pub use polkadot_runtime;
pub use kusama_runtime;
pub use westend_runtime;
use prometheus_endpoint::Registry;
pub use self::client::PolkadotClient;
pub use self::client::*;
native_executor_instance!(
pub PolkadotExecutor,
@@ -82,42 +82,6 @@ native_executor_instance!(
frame_benchmarking::benchmarking::HostFunctions,
);
/// A set of APIs that polkadot-like runtimes must implement.
pub trait RuntimeApiCollection:
sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block>
+ sp_api::ApiExt<Block, Error = sp_blockchain::Error>
+ babe_primitives::BabeApi<Block>
+ grandpa_primitives::GrandpaApi<Block>
+ ParachainHost<Block>
+ sp_block_builder::BlockBuilder<Block>
+ system_rpc_runtime_api::AccountNonceApi<Block, AccountId, Nonce>
+ pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<Block, Balance>
+ sp_api::Metadata<Block>
+ sp_offchain::OffchainWorkerApi<Block>
+ sp_session::SessionKeys<Block>
+ authority_discovery_primitives::AuthorityDiscoveryApi<Block>
where
<Self as sp_api::ApiExt<Block>>::StateBackend: sp_api::StateBackend<BlakeTwo256>,
{}
impl<Api> RuntimeApiCollection for Api
where
Api:
sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block>
+ sp_api::ApiExt<Block, Error = sp_blockchain::Error>
+ babe_primitives::BabeApi<Block>
+ grandpa_primitives::GrandpaApi<Block>
+ ParachainHost<Block>
+ sp_block_builder::BlockBuilder<Block>
+ system_rpc_runtime_api::AccountNonceApi<Block, AccountId, Nonce>
+ pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<Block, Balance>
+ sp_api::Metadata<Block>
+ sp_offchain::OffchainWorkerApi<Block>
+ sp_session::SessionKeys<Block>
+ authority_discovery_primitives::AuthorityDiscoveryApi<Block>,
<Self as sp_api::ApiExt<Block>>::StateBackend: sp_api::StateBackend<BlakeTwo256>,
{}
/// Can be called for a `Configuration` to check if it is a configuration for the `Kusama` network.
pub trait IdentifyVariant {
/// Returns if this is a configuration for the `Kusama` network.
@@ -732,11 +696,7 @@ pub fn polkadot_new_full(
)
-> Result<(
TaskManager,
Arc<impl PolkadotClient<
Block,
FullBackend,
polkadot_runtime::RuntimeApi
>>,
Arc<impl AbstractClient<Block, FullBackend>>,
FullNodeHandles,
), ServiceError>
{
@@ -764,12 +724,7 @@ pub fn kusama_new_full(
grandpa_pause: Option<(u32, u32)>,
) -> Result<(
TaskManager,
Arc<impl PolkadotClient<
Block,
FullBackend,
kusama_runtime::RuntimeApi
>
>,
Arc<impl AbstractClient<Block, FullBackend>>,
FullNodeHandles
), ServiceError>
{
@@ -798,11 +753,7 @@ pub fn westend_new_full(
)
-> Result<(
TaskManager,
Arc<impl PolkadotClient<
Block,
FullBackend,
westend_runtime::RuntimeApi
>>,
Arc<impl AbstractClient<Block, FullBackend>>,
FullNodeHandles,
), ServiceError>
{
@@ -831,11 +782,7 @@ pub fn rococo_new_full(
)
-> Result<(
TaskManager,
Arc<impl PolkadotClient<
Block,
TFullBackend<Block>,
rococo_runtime::RuntimeApi
>>,
Arc<impl AbstractClient<Block, TFullBackend<Block>>>,
FullNodeHandles,
), ServiceError>
{
@@ -863,90 +810,68 @@ pub struct FullNodeHandles {
pub validation_service_handle: Option<consensus::ServiceHandle>,
}
/// A builder for a node.
pub struct NodeBuilder {
/// Build a new light node.
pub fn build_light(config: Configuration) -> Result<(TaskManager, Arc<RpcHandlers>), ServiceError> {
if config.chain_spec.is_kusama() {
new_light::<kusama_runtime::RuntimeApi, KusamaExecutor>(config)
} else if config.chain_spec.is_westend() {
new_light::<westend_runtime::RuntimeApi, WestendExecutor>(config)
} else if config.chain_spec.is_rococo() {
new_light::<rococo_runtime::RuntimeApi, RococoExecutor>(config)
} else {
new_light::<polkadot_runtime::RuntimeApi, PolkadotExecutor>(config)
}
}
/// Build a new full node.
#[cfg(feature = "full-node")]
pub fn build_full(
config: Configuration,
}
impl NodeBuilder {
/// Create a new node builder.
pub fn new(config: Configuration) -> Self {
Self {
collating_for: Option<(CollatorId, parachain::Id)>,
max_block_data_size: Option<u64>,
authority_discovery_disabled: bool,
slot_duration: u64,
grandpa_pause: Option<(u32, u32)>,
) -> Result<(TaskManager, Client, FullNodeHandles), ServiceError> {
if config.chain_spec.is_kusama() {
new_full::<kusama_runtime::RuntimeApi, KusamaExecutor>(
config,
}
}
/// Build a new light node.
pub fn build_light(self) -> Result<(TaskManager, Arc<RpcHandlers>), ServiceError> {
if self.config.chain_spec.is_kusama() {
new_light::<kusama_runtime::RuntimeApi, KusamaExecutor>(
self.config,
)
} else if self.config.chain_spec.is_westend() {
new_light::<westend_runtime::RuntimeApi, WestendExecutor>(
self.config,
)
} else if self.config.chain_spec.is_rococo() {
new_light::<rococo_runtime::RuntimeApi, RococoExecutor>(
self.config,
)
} else {
new_light::<polkadot_runtime::RuntimeApi, PolkadotExecutor>(
self.config,
)
}
}
/// Build a new full node.
#[cfg(feature = "full-node")]
pub fn build_full(
self,
collating_for: Option<(CollatorId, parachain::Id)>,
max_block_data_size: Option<u64>,
authority_discovery_disabled: bool,
slot_duration: u64,
grandpa_pause: Option<(u32, u32)>,
) -> Result<TaskManager, ServiceError> {
if self.config.chain_spec.is_kusama() {
new_full::<kusama_runtime::RuntimeApi, KusamaExecutor>(
self.config,
collating_for,
max_block_data_size,
authority_discovery_disabled,
slot_duration,
grandpa_pause,
false,
).map(|(task_manager, _, _, _, _)| task_manager)
} else if self.config.chain_spec.is_westend() {
new_full::<westend_runtime::RuntimeApi, WestendExecutor>(
self.config,
collating_for,
max_block_data_size,
authority_discovery_disabled,
slot_duration,
grandpa_pause,
false,
).map(|(task_manager, _, _, _, _)| task_manager)
} else if self.config.chain_spec.is_rococo() {
new_full::<rococo_runtime::RuntimeApi, RococoExecutor>(
self.config,
collating_for,
max_block_data_size,
authority_discovery_disabled,
slot_duration,
grandpa_pause,
false,
).map(|(task_manager, _, _, _, _)| task_manager)
} else {
new_full::<polkadot_runtime::RuntimeApi, PolkadotExecutor>(
self.config,
collating_for,
max_block_data_size,
authority_discovery_disabled,
slot_duration,
grandpa_pause,
false,
).map(|(task_manager, _, _, _, _)| task_manager)
}
collating_for,
max_block_data_size,
authority_discovery_disabled,
slot_duration,
grandpa_pause,
false,
).map(|(task_manager, client, handles, _, _)| (task_manager, Client::Kusama(client), handles))
} else if config.chain_spec.is_westend() {
new_full::<westend_runtime::RuntimeApi, WestendExecutor>(
config,
collating_for,
max_block_data_size,
authority_discovery_disabled,
slot_duration,
grandpa_pause,
false,
).map(|(task_manager, client, handles, _, _)| (task_manager, Client::Westend(client), handles))
} else if config.chain_spec.is_rococo() {
new_full::<rococo_runtime::RuntimeApi, RococoExecutor>(
config,
collating_for,
max_block_data_size,
authority_discovery_disabled,
slot_duration,
grandpa_pause,
false,
).map(|(task_manager, client, handles, _, _)| (task_manager, Client::Rococo(client), handles))
} else {
new_full::<polkadot_runtime::RuntimeApi, PolkadotExecutor>(
config,
collating_for,
max_block_data_size,
authority_discovery_disabled,
slot_duration,
grandpa_pause,
false,
).map(|(task_manager, client, handles, _, _)| (task_manager, Client::Polkadot(client), handles))
}
}