Implement runtime api client side directly in the runtime (#1094)

* Move `initialise_block` into `Core` trait as it is crucial calling the API functions

* Switch to first version of new runtime API implementation

* Fixes bug in tests

* Reenable asserts

* Directly use the `TestAPI` in the tests

* Start improving the api traits

:100644 100644 898aadc7 49217199 M	Cargo.lock
:100644 100644 61570436 465ed664 M	core/client/src/backend.rs
:100644 100644 5d0c886b 64d710fd M	core/client/src/block_builder.rs
:100644 100644 c447855e 5ecbe474 M	core/client/src/client.rs
:100644 100644 139cef13 f90dbf3d M	core/client/src/error.rs
:100644 100644 2800c503 3298e66a M	core/client/src/runtime_api.rs
:100644 100644 affa1c5c 809b08bc M	core/primitives/src/lib.rs
:100644 100644 2877dfa9 d5547413 M	core/sr-api/Cargo.toml
:100644 100644 9a49784d 6a625a03 M	core/sr-api/src/lib.rs
:100644 100644 7c28e1c7 a1a444a9 M	core/sr-primitives/src/traits.rs
:100644 100644 2e113ab6 dcc01a6d M	srml/metadata/Cargo.toml
:100644 100644 ea722a70 0809531a M	srml/metadata/src/lib.rs

* Refactoring

* Move `sr-api` into client and more refactoring

* Fixes tests

* Some documentation and cleanup

* Fixes compilation after rebase

* More refactoring and more documentation

* Makes `substrate-client` compilable on `wasm`

On `wasm` it basically just exports the runtime api stuff.

* Fixes grumbles

* Updates wasm files after rebasing the master

* Remove TODO comment

* Remove whitespaces

* Fixes after rebasing master

* Another rebase, another fix commit
This commit is contained in:
Bastian Köcher
2018-11-13 13:33:28 +01:00
committed by Gav Wood
parent 6e3c56c135
commit 9063d1acae
51 changed files with 2993 additions and 777 deletions
+186 -22
View File
@@ -16,21 +16,20 @@
//! Substrate service components.
use std::sync::Arc;
use std::marker::PhantomData;
use std::ops::Deref;
use std::{sync::Arc, net::SocketAddr, marker::PhantomData, ops::Deref};
use serde::{Serialize, de::DeserializeOwned};
use tokio::runtime::TaskExecutor;
use chain_spec::ChainSpec;
use chain_spec::{ChainSpec, Properties};
use client_db;
use client::{self, Client};
use {error, Service};
use client::{self, Client, runtime_api::{TaggedTransactionQueue, Metadata}};
use {error, Service, RpcConfig, maybe_start_server, TransactionPoolAdapter};
use network::{self, OnDemand, import_queue::ImportQueue};
use substrate_executor::{NativeExecutor, NativeExecutionDispatch};
use transaction_pool::txpool::{self, Options as TransactionPoolOptions, Pool as TransactionPool};
use runtime_primitives::{traits::Block as BlockT, traits::Header as HeaderT, BuildStorage};
use runtime_primitives::{traits::Block as BlockT, traits::Header as HeaderT, BuildStorage, generic::SignedBlock};
use config::Configuration;
use primitives::{H256, Blake2Hasher};
use primitives::{Blake2Hasher, H256};
use rpc;
// Type aliases.
// These exist mainly to avoid typing `<F as Factory>::Foo` all over the code.
@@ -70,10 +69,10 @@ pub type LightExecutor<F> = client::light::call_executor::RemoteCallExecutor<
>;
/// Full client type for a factory.
pub type FullClient<F> = Client<FullBackend<F>, FullExecutor<F>, <F as ServiceFactory>::Block>;
pub type FullClient<F> = Client<FullBackend<F>, FullExecutor<F>, <F as ServiceFactory>::Block, <F as ServiceFactory>::RuntimeApi>;
/// Light client type for a factory.
pub type LightClient<F> = Client<LightBackend<F>, LightExecutor<F>, <F as ServiceFactory>::Block>;
pub type LightClient<F> = Client<LightBackend<F>, LightExecutor<F>, <F as ServiceFactory>::Block, <F as ServiceFactory>::RuntimeApi>;
/// `ChainSpec` specialization for a factory.
pub type FactoryChainSpec<F> = ChainSpec<<F as ServiceFactory>::Genesis>;
@@ -97,7 +96,8 @@ pub type FactoryFullConfiguration<F> = Configuration<<F as ServiceFactory>::Conf
pub type ComponentClient<C> = Client<
<C as Components>::Backend,
<C as Components>::Executor,
FactoryBlock<<C as Components>::Factory>
FactoryBlock<<C as Components>::Factory>,
<C as Components>::RuntimeApi,
>;
/// Block type for `Components`
@@ -116,10 +116,114 @@ pub type PoolApi<C> = <C as Components>::TransactionPoolApi;
pub trait RuntimeGenesis: Serialize + DeserializeOwned + BuildStorage {}
impl<T: Serialize + DeserializeOwned + BuildStorage> RuntimeGenesis for T {}
/// Something that can start the RPC service.
pub trait StartRPC<C: Components> {
fn start_rpc(
client: Arc<Client<C::Backend, C::Executor, ComponentBlock<C>, C::RuntimeApi>>,
chain_name: String,
impl_name: &'static str,
impl_version: &'static str,
rpc_http: Option<SocketAddr>,
rpc_ws: Option<SocketAddr>,
properties: Properties,
task_executor: TaskExecutor,
transaction_pool: Arc<TransactionPool<C::TransactionPoolApi>>,
) -> Result<(Option<rpc::HttpServer>, Option<rpc::WsServer>), error::Error>;
}
impl<T: Components> StartRPC<Self> for T where
T::RuntimeApi: Metadata<ComponentBlock<T>>,
for<'de> SignedBlock<ComponentBlock<T>>: ::serde::Deserialize<'de>,
{
fn start_rpc(
client: Arc<Client<T::Backend, T::Executor, ComponentBlock<T>, T::RuntimeApi>>,
chain_name: String,
impl_name: &'static str,
impl_version: &'static str,
rpc_http: Option<SocketAddr>,
rpc_ws: Option<SocketAddr>,
properties: Properties,
task_executor: TaskExecutor,
transaction_pool: Arc<TransactionPool<T::TransactionPoolApi>>,
) -> Result<(Option<rpc::HttpServer>, Option<rpc::WsServer>), error::Error> {
let rpc_config = RpcConfig { properties, chain_name, impl_name, impl_version };
let handler = || {
let client = client.clone();
let subscriptions = rpc::apis::Subscriptions::new(task_executor.clone());
let chain = rpc::apis::chain::Chain::new(client.clone(), subscriptions.clone());
let state = rpc::apis::state::State::new(client.clone(), subscriptions.clone());
let author = rpc::apis::author::Author::new(
client.clone(), transaction_pool.clone(), subscriptions
);
rpc::rpc_handler::<ComponentBlock<T>, ComponentExHash<T>, _, _, _, _>(
state,
chain,
author,
rpc_config.clone(),
)
};
Ok((
maybe_start_server(rpc_http, |address| rpc::start_http(address, handler()))?,
maybe_start_server(rpc_ws, |address| rpc::start_ws(address, handler()))?,
))
}
}
/// Something that can create an instance of `network::Params`.
pub trait CreateNetworkParams<C: Components> {
fn create_network_params<S>(
client: Arc<Client<C::Backend, C::Executor, ComponentBlock<C>, C::RuntimeApi>>,
roles: network::Roles,
network_config: network::NetworkConfiguration,
on_demand: Option<Arc<OnDemand<FactoryBlock<C::Factory>, NetworkService<C::Factory>>>>,
transaction_pool_adapter: TransactionPoolAdapter<C>,
specialization: S,
) -> network::Params<ComponentBlock<C>, S, ComponentExHash<C>>;
}
impl<T: Components> CreateNetworkParams<Self> for T where
T::RuntimeApi: TaggedTransactionQueue<ComponentBlock<T>>
{
fn create_network_params<S>(
client: Arc<Client<T::Backend, T::Executor, ComponentBlock<T>, T::RuntimeApi>>,
roles: network::Roles,
network_config: network::NetworkConfiguration,
on_demand: Option<Arc<OnDemand<FactoryBlock<T::Factory>, NetworkService<T::Factory>>>>,
transaction_pool_adapter: TransactionPoolAdapter<T>,
specialization: S,
) -> network::Params<ComponentBlock<T>, S, ComponentExHash<T>> {
network::Params {
config: network::ProtocolConfig { roles },
network_config,
chain: client,
on_demand: on_demand.map(|d| d as Arc<network::OnDemandService<ComponentBlock<T>>>),
transaction_pool: Arc::new(transaction_pool_adapter),
specialization,
}
}
}
/// The super trait that combines all required traits a `Service` needs to implement.
pub trait ServiceTrait<C: Components>:
Deref<Target = Service<C>>
+ Send
+ Sync
+ 'static
+ StartRPC<C>
+ CreateNetworkParams<C>
{}
impl<C: Components, T> ServiceTrait<C> for T where
T: Deref<Target = Service<C>> + Send + Sync + 'static + StartRPC<C> + CreateNetworkParams<C>
{}
/// A collection of types and methods to build a service on top of the substrate service.
pub trait ServiceFactory: 'static + Sized {
/// Block type.
type Block: BlockT<Hash=H256>;
/// The type that implements the runtime API.
type RuntimeApi: Send + Sync;
/// Network protocol extensions.
type NetworkProtocol: network::specialization::Specialization<Self::Block>;
/// Chain runtime.
@@ -133,9 +237,9 @@ pub trait ServiceFactory: 'static + Sized {
/// Other configuration for service members.
type Configuration: Default;
/// Extended full service type.
type FullService: Deref<Target = Service<FullComponents<Self>>> + Send + Sync + 'static;
type FullService: ServiceTrait<FullComponents<Self>>;
/// Extended light service type.
type LightService: Deref<Target = Service<LightComponents<Self>>> + Send + Sync + 'static;
type LightService: ServiceTrait<LightComponents<Self>>;
/// ImportQueue for full client
type FullImportQueue: network::import_queue::ImportQueue<Self::Block> + 'static;
/// ImportQueue for light clients
@@ -192,7 +296,7 @@ pub trait ServiceFactory: 'static + Sized {
}
/// A collection of types and function to generalise over full / light client type.
pub trait Components: 'static {
pub trait Components: Sized + 'static {
/// Associated service factory.
type Factory: ServiceFactory;
/// Client backend.
@@ -204,6 +308,12 @@ pub trait Components: 'static {
Hash = <<Self::Factory as ServiceFactory>::Block as BlockT>::Hash,
Block = FactoryBlock<Self::Factory>
>;
/// The type that implements the runtime API.
type RuntimeApi: Send + Sync;
/// A type that can start the RPC.
type RPC: StartRPC<Self>;
/// A type that can create the network params.
type CreateNetworkParams: CreateNetworkParams<Self>;
/// Our Import Queue
type ImportQueue: ImportQueue<FactoryBlock<Self::Factory>> + 'static;
@@ -212,11 +322,13 @@ pub trait Components: 'static {
fn build_client(
config: &FactoryFullConfiguration<Self::Factory>,
executor: CodeExecutor<Self::Factory>,
)
-> Result<(
) -> Result<
(
Arc<ComponentClient<Self>>,
Option<Arc<OnDemand<FactoryBlock<Self::Factory>, NetworkService<Self::Factory>>>>
), error::Error>;
),
error::Error
>;
/// Create extrinsic pool.
fn build_transaction_pool(config: TransactionPoolOptions, client: Arc<ComponentClient<Self>>)
@@ -232,6 +344,29 @@ pub trait Components: 'static {
/// A struct that implement `Components` for the full client.
pub struct FullComponents<Factory: ServiceFactory> {
_factory: PhantomData<Factory>,
service: Service<FullComponents<Factory>>,
}
impl<Factory: ServiceFactory> FullComponents<Factory> {
pub fn new(
config: FactoryFullConfiguration<Factory>,
task_executor: TaskExecutor
) -> Result<Self, error::Error> {
Ok(
Self {
_factory: Default::default(),
service: Service::new(config, task_executor)?,
}
)
}
}
impl<Factory: ServiceFactory> Deref for FullComponents<Factory> {
type Target = Service<Self>;
fn deref(&self) -> &Self::Target {
&self.service
}
}
impl<Factory: ServiceFactory> Components for FullComponents<Factory> {
@@ -240,6 +375,9 @@ impl<Factory: ServiceFactory> Components for FullComponents<Factory> {
type Backend = FullBackend<Factory>;
type TransactionPoolApi = <Factory as ServiceFactory>::FullTransactionPoolApi;
type ImportQueue = Factory::FullImportQueue;
type RuntimeApi = Factory::RuntimeApi;
type RPC = Factory::FullService;
type CreateNetworkParams = Factory::FullService;
fn build_client(
config: &FactoryFullConfiguration<Factory>,
@@ -281,6 +419,29 @@ impl<Factory: ServiceFactory> Components for FullComponents<Factory> {
/// A struct that implement `Components` for the light client.
pub struct LightComponents<Factory: ServiceFactory> {
_factory: PhantomData<Factory>,
service: Service<LightComponents<Factory>>,
}
impl<Factory: ServiceFactory> LightComponents<Factory> {
pub fn new(
config: FactoryFullConfiguration<Factory>,
task_executor: TaskExecutor
) -> Result<Self, error::Error> {
Ok(
Self {
_factory: Default::default(),
service: Service::new(config, task_executor)?,
}
)
}
}
impl<Factory: ServiceFactory> Deref for LightComponents<Factory> {
type Target = Service<Self>;
fn deref(&self) -> &Self::Target {
&self.service
}
}
impl<Factory: ServiceFactory> Components for LightComponents<Factory> {
@@ -289,16 +450,19 @@ impl<Factory: ServiceFactory> Components for LightComponents<Factory> {
type Backend = LightBackend<Factory>;
type TransactionPoolApi = <Factory as ServiceFactory>::LightTransactionPoolApi;
type ImportQueue = <Factory as ServiceFactory>::LightImportQueue;
type RuntimeApi = Factory::RuntimeApi;
type RPC = Factory::LightService;
type CreateNetworkParams = Factory::LightService;
fn build_client(
config: &FactoryFullConfiguration<Factory>,
executor: CodeExecutor<Self::Factory>,
)
-> Result<(
Arc<ComponentClient<Self>>,
Option<Arc<OnDemand<FactoryBlock<Self::Factory>,
NetworkService<Self::Factory>>>>
), error::Error>
-> Result<
(
Arc<ComponentClient<Self>>,
Option<Arc<OnDemand<FactoryBlock<Self::Factory>, NetworkService<Self::Factory>>>>
), error::Error>
{
let db_settings = client_db::DatabaseSettings {
cache_size: None,