// This file is part of Substrate.
// Copyright (C) 2017-2020 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
// This program 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.
// This program 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 this program. If not, see .
use crate::{
Service, NetworkStatus, NetworkState, error::Error, DEFAULT_PROTOCOL_ID, MallocSizeOfWasm,
start_rpc_servers, build_network_future, TransactionPoolAdapter, TaskManager, SpawnTaskHandle,
status_sinks, metrics::MetricsService,
client::{light, Client, ClientConfig},
config::{Configuration, KeystoreConfig, PrometheusConfig, OffchainWorkerConfig},
};
use sc_client_api::{
self, light::RemoteBlockchain, execution_extensions::ExtensionsFactory,
ExecutorProvider, CallExecutor, ForkBlocks, BadBlocks, CloneableSpawn, UsageProvider,
backend::RemoteBackend,
};
use sp_utils::mpsc::{tracing_unbounded, TracingUnboundedSender, TracingUnboundedReceiver};
use sc_chain_spec::get_extension;
use sp_consensus::{
block_validation::{BlockAnnounceValidator, DefaultBlockAnnounceValidator},
import_queue::ImportQueue,
};
use futures::{
Future, FutureExt, StreamExt,
future::ready,
};
use jsonrpc_pubsub::manager::SubscriptionManager;
use sc_keystore::Store as Keystore;
use log::{info, warn, error};
use sc_network::config::{Role, FinalityProofProvider, OnDemand, BoxFinalityProofRequestBuilder};
use sc_network::NetworkService;
use parking_lot::{Mutex, RwLock};
use sp_runtime::generic::BlockId;
use sp_runtime::traits::{
Block as BlockT, NumberFor, SaturatedConversion, HashFor,
};
use sp_api::ProvideRuntimeApi;
use sc_executor::{NativeExecutor, NativeExecutionDispatch, RuntimeInfo};
use std::{
collections::HashMap,
io::{Read, Write, Seek},
marker::PhantomData, sync::Arc, pin::Pin
};
use wasm_timer::SystemTime;
use sc_telemetry::{telemetry, SUBSTRATE_INFO};
use sp_transaction_pool::{LocalTransactionPool, MaintainedTransactionPool};
use prometheus_endpoint::Registry;
use sc_client_db::{Backend, DatabaseSettings};
use sp_core::traits::CodeExecutor;
use sp_runtime::BuildStorage;
use sc_client_api::execution_extensions::ExecutionExtensions;
use sp_core::storage::Storage;
pub type BackgroundTask = Pin + Send>>;
/// Aggregator for the components required to build a service.
///
/// # Usage
///
/// Call [`ServiceBuilder::new_full`] or [`ServiceBuilder::new_light`], then call the various
/// `with_` methods to add the required components that you built yourself:
///
/// - [`with_select_chain`](ServiceBuilder::with_select_chain)
/// - [`with_import_queue`](ServiceBuilder::with_import_queue)
/// - [`with_finality_proof_provider`](ServiceBuilder::with_finality_proof_provider)
/// - [`with_transaction_pool`](ServiceBuilder::with_transaction_pool)
///
/// After this is done, call [`build`](ServiceBuilder::build) to construct the service.
///
/// The order in which the `with_*` methods are called doesn't matter, as the correct binding of
/// generics is done when you call `build`.
///
pub struct ServiceBuilder
{
config: Configuration,
pub (crate) client: Arc,
backend: Arc,
task_manager: TaskManager,
keystore: Arc>,
fetcher: Option,
select_chain: Option,
pub (crate) import_queue: TImpQu,
finality_proof_request_builder: Option,
finality_proof_provider: Option,
transaction_pool: Arc,
rpc_extensions_builder: Box + Send>,
remote_backend: Option>>,
marker: PhantomData<(TBl, TRtApi)>,
block_announce_validator_builder: Option) -> Box + Send> + Send>>,
informant_prefix: String,
}
/// A utility trait for building an RPC extension given a `DenyUnsafe` instance.
/// This is useful since at service definition time we don't know whether the
/// specific interface where the RPC extension will be exposed is safe or not.
/// This trait allows us to lazily build the RPC extension whenever we bind the
/// service to an interface.
pub trait RpcExtensionBuilder {
/// The type of the RPC extension that will be built.
type Output: sc_rpc::RpcExtension;
/// Returns an instance of the RPC extension for a particular `DenyUnsafe`
/// value, e.g. the RPC extension might not expose some unsafe methods.
fn build(&self, deny: sc_rpc::DenyUnsafe) -> Self::Output;
}
impl RpcExtensionBuilder for F where
F: Fn(sc_rpc::DenyUnsafe) -> R,
R: sc_rpc::RpcExtension,
{
type Output = R;
fn build(&self, deny: sc_rpc::DenyUnsafe) -> Self::Output {
(*self)(deny)
}
}
/// A utility struct for implementing an `RpcExtensionBuilder` given a cloneable
/// `RpcExtension`, the resulting builder will simply ignore the provided
/// `DenyUnsafe` instance and return a static `RpcExtension` instance.
struct NoopRpcExtensionBuilder(R);
impl RpcExtensionBuilder for NoopRpcExtensionBuilder where
R: Clone + sc_rpc::RpcExtension,
{
type Output = R;
fn build(&self, _deny: sc_rpc::DenyUnsafe) -> Self::Output {
self.0.clone()
}
}
impl From for NoopRpcExtensionBuilder where
R: sc_rpc::RpcExtension,
{
fn from(e: R) -> NoopRpcExtensionBuilder {
NoopRpcExtensionBuilder(e)
}
}
/// Full client type.
pub type TFullClient = Client<
TFullBackend,
TFullCallExecutor,
TBl,
TRtApi,
>;
/// Full client backend type.
pub type TFullBackend = sc_client_db::Backend;
/// Full client call executor type.
pub type TFullCallExecutor = crate::client::LocalCallExecutor<
sc_client_db::Backend,
NativeExecutor,
>;
/// Light client type.
pub type TLightClient = Client<
TLightBackend,
TLightCallExecutor,
TBl,
TRtApi,
>;
/// Light client backend type.
pub type TLightBackend = sc_light::Backend<
sc_client_db::light::LightStorage,
HashFor,
>;
/// Light call executor type.
pub type TLightCallExecutor = sc_light::GenesisCallExecutor<
sc_light::Backend<
sc_client_db::light::LightStorage,
HashFor
>,
crate::client::LocalCallExecutor<
sc_light::Backend<
sc_client_db::light::LightStorage,
HashFor
>,
NativeExecutor
>,
>;
type TFullParts = (
TFullClient,
Arc>,
Arc>,
TaskManager,
);
/// Creates a new full client for the given config.
pub fn new_full_client(
config: &Configuration,
) -> Result, Error> where
TBl: BlockT,
TExecDisp: NativeExecutionDispatch + 'static,
{
new_full_parts(config).map(|parts| parts.0)
}
fn new_full_parts(
config: &Configuration,
) -> Result, Error> where
TBl: BlockT,
TExecDisp: NativeExecutionDispatch + 'static,
{
let keystore = match &config.keystore {
KeystoreConfig::Path { path, password } => Keystore::open(
path.clone(),
password.clone()
)?,
KeystoreConfig::InMemory => Keystore::new_in_memory(),
};
let task_manager = {
let registry = config.prometheus_config.as_ref().map(|cfg| &cfg.registry);
TaskManager::new(config.task_executor.clone(), registry)?
};
let executor = NativeExecutor::::new(
config.wasm_method,
config.default_heap_pages,
config.max_runtime_instances,
);
let chain_spec = &config.chain_spec;
let fork_blocks = get_extension::>(chain_spec.extensions())
.cloned()
.unwrap_or_default();
let bad_blocks = get_extension::>(chain_spec.extensions())
.cloned()
.unwrap_or_default();
let (client, backend) = {
let db_config = sc_client_db::DatabaseSettings {
state_cache_size: config.state_cache_size,
state_cache_child_ratio:
config.state_cache_child_ratio.map(|v| (v, 100)),
pruning: config.pruning.clone(),
source: config.database.clone(),
};
let extensions = sc_client_api::execution_extensions::ExecutionExtensions::new(
config.execution_strategies.clone(),
Some(keystore.clone()),
);
new_client(
db_config,
executor,
chain_spec.as_storage_builder(),
fork_blocks,
bad_blocks,
extensions,
Box::new(task_manager.spawn_handle()),
config.prometheus_config.as_ref().map(|config| config.registry.clone()),
ClientConfig {
offchain_worker_enabled : config.offchain_worker.enabled ,
offchain_indexing_api: config.offchain_worker.indexing_enabled,
},
)?
};
Ok((client, backend, keystore, task_manager))
}
/// Create an instance of db-backed client.
pub fn new_client(
settings: DatabaseSettings,
executor: E,
genesis_storage: &dyn BuildStorage,
fork_blocks: ForkBlocks,
bad_blocks: BadBlocks,
execution_extensions: ExecutionExtensions,
spawn_handle: Box,
prometheus_registry: Option,
config: ClientConfig,
) -> Result<(
crate::client::Client<
Backend,
crate::client::LocalCallExecutor, E>,
Block,
RA,
>,
Arc>,
),
sp_blockchain::Error,
>
where
Block: BlockT,
E: CodeExecutor + RuntimeInfo,
{
const CANONICALIZATION_DELAY: u64 = 4096;
let backend = Arc::new(Backend::new(settings, CANONICALIZATION_DELAY)?);
let executor = crate::client::LocalCallExecutor::new(backend.clone(), executor, spawn_handle, config.clone());
Ok((
crate::client::Client::new(
backend.clone(),
executor,
genesis_storage,
fork_blocks,
bad_blocks,
execution_extensions,
prometheus_registry,
config,
)?,
backend,
))
}
impl ServiceBuilder<(), (), (), (), (), (), (), (), (), (), ()> {
/// Start the service builder with a configuration.
pub fn new_full(
config: Configuration,
) -> Result,
Arc>,
(),
(),
BoxFinalityProofRequestBuilder,
Arc>,
(),
(),
TFullBackend,
>, Error> {
let (client, backend, keystore, task_manager) = new_full_parts(&config)?;
let client = Arc::new(client);
Ok(ServiceBuilder {
config,
client,
backend,
keystore,
task_manager,
fetcher: None,
select_chain: None,
import_queue: (),
finality_proof_request_builder: None,
finality_proof_provider: None,
transaction_pool: Arc::new(()),
rpc_extensions_builder: Box::new(|_| ()),
remote_backend: None,
block_announce_validator_builder: None,
informant_prefix: Default::default(),
marker: PhantomData,
})
}
/// Start the service builder with a configuration.
pub fn new_light(
config: Configuration,
) -> Result,
Arc>,
(),
(),
BoxFinalityProofRequestBuilder,
Arc>,
(),
(),
TLightBackend,
>, Error> {
let task_manager = {
let registry = config.prometheus_config.as_ref().map(|cfg| &cfg.registry);
TaskManager::new(config.task_executor.clone(), registry)?
};
let keystore = match &config.keystore {
KeystoreConfig::Path { path, password } => Keystore::open(
path.clone(),
password.clone()
)?,
KeystoreConfig::InMemory => Keystore::new_in_memory(),
};
let executor = NativeExecutor::::new(
config.wasm_method,
config.default_heap_pages,
config.max_runtime_instances,
);
let db_storage = {
let db_settings = sc_client_db::DatabaseSettings {
state_cache_size: config.state_cache_size,
state_cache_child_ratio:
config.state_cache_child_ratio.map(|v| (v, 100)),
pruning: config.pruning.clone(),
source: config.database.clone(),
};
sc_client_db::light::LightStorage::new(db_settings)?
};
let light_blockchain = sc_light::new_light_blockchain(db_storage);
let fetch_checker = Arc::new(
sc_light::new_fetch_checker::<_, TBl, _>(
light_blockchain.clone(),
executor.clone(),
Box::new(task_manager.spawn_handle()),
),
);
let fetcher = Arc::new(sc_network::config::OnDemand::new(fetch_checker));
let backend = sc_light::new_light_backend(light_blockchain);
let remote_blockchain = backend.remote_blockchain();
let client = Arc::new(light::new_light(
backend.clone(),
config.chain_spec.as_storage_builder(),
executor,
Box::new(task_manager.spawn_handle()),
config.prometheus_config.as_ref().map(|config| config.registry.clone()),
)?);
Ok(ServiceBuilder {
config,
client,
backend,
task_manager,
keystore,
fetcher: Some(fetcher.clone()),
select_chain: None,
import_queue: (),
finality_proof_request_builder: None,
finality_proof_provider: None,
transaction_pool: Arc::new(()),
rpc_extensions_builder: Box::new(|_| ()),
remote_backend: Some(remote_blockchain),
block_announce_validator_builder: None,
informant_prefix: Default::default(),
marker: PhantomData,
})
}
}
impl
ServiceBuilder<
TBl,
TRtApi,
TCl,
TFchr,
TSc,
TImpQu,
TFprb,
TFpp,
TExPool,
TRpc,
Backend
>
{
/// Returns a reference to the configuration that was stored in this builder.
pub fn config(&self) -> &Configuration {
&self.config
}
/// Returns a reference to the optional prometheus registry that was stored in this builder.
pub fn prometheus_registry(&self) -> Option<&Registry> {
self.config.prometheus_config.as_ref().map(|config| &config.registry)
}
/// Returns a reference to the client that was stored in this builder.
pub fn client(&self) -> &Arc {
&self.client
}
/// Returns a reference to the backend that was used in this builder.
pub fn backend(&self) -> &Arc {
&self.backend
}
/// Returns a reference to the select-chain that was stored in this builder.
pub fn select_chain(&self) -> Option<&TSc> {
self.select_chain.as_ref()
}
/// Returns a reference to the keystore
pub fn keystore(&self) -> Arc> {
self.keystore.clone()
}
/// Returns a reference to the transaction pool stored in this builder
pub fn pool(&self) -> Arc {
self.transaction_pool.clone()
}
/// Returns a reference to the fetcher, only available if builder
/// was created with `new_light`.
pub fn fetcher(&self) -> Option
where TFchr: Clone
{
self.fetcher.clone()
}
/// Returns a reference to the remote_backend, only available if builder
/// was created with `new_light`.
pub fn remote_backend(&self) -> Option>> {
self.remote_backend.clone()
}
/// Defines which head-of-chain strategy to use.
pub fn with_opt_select_chain(
self,
select_chain_builder: impl FnOnce(
&Configuration, &Arc,
) -> Result