1use crate::cli::Consensus;
19use futures::FutureExt;
20use minimal_template_runtime::{interface::OpaqueBlock as Block, RuntimeApi};
21use polkadot_sdk::{
22 sc_client_api::backend::Backend,
23 sc_executor::WasmExecutor,
24 sc_service::{error::Error as ServiceError, Configuration, TaskManager},
25 sc_telemetry::{Telemetry, TelemetryWorker},
26 sc_transaction_pool_api::OffchainTransactionPoolFactory,
27 sp_runtime::traits::Block as BlockT,
28 *,
29};
30use std::sync::Arc;
31
32type HostFunctions = sp_io::SubstrateHostFunctions;
33
34#[docify::export]
35pub(crate) type FullClient =
36 sc_service::TFullClient<Block, RuntimeApi, WasmExecutor<HostFunctions>>;
37
38type FullBackend = sc_service::TFullBackend<Block>;
39type FullSelectChain = sc_consensus::LongestChain<FullBackend, Block>;
40
41pub type Service = sc_service::PartialComponents<
43 FullClient,
44 FullBackend,
45 FullSelectChain,
46 sc_consensus::DefaultImportQueue<Block>,
47 sc_transaction_pool::TransactionPoolHandle<Block, FullClient>,
48 Option<Telemetry>,
49>;
50
51pub fn new_partial(config: &Configuration) -> Result<Service, ServiceError> {
52 let telemetry = config
53 .telemetry_endpoints
54 .clone()
55 .filter(|x| !x.is_empty())
56 .map(|endpoints| -> Result<_, sc_telemetry::Error> {
57 let worker = TelemetryWorker::new(16)?;
58 let telemetry = worker.handle().new_telemetry(endpoints);
59 Ok((worker, telemetry))
60 })
61 .transpose()?;
62
63 let executor = sc_service::new_wasm_executor(&config.executor);
64
65 let (client, backend, keystore_container, task_manager) =
66 sc_service::new_full_parts::<Block, RuntimeApi, _>(
67 config,
68 telemetry.as_ref().map(|(_, telemetry)| telemetry.handle()),
69 executor,
70 )?;
71 let client = Arc::new(client);
72
73 let telemetry = telemetry.map(|(worker, telemetry)| {
74 task_manager.spawn_handle().spawn("telemetry", None, worker.run());
75 telemetry
76 });
77
78 let select_chain = sc_consensus::LongestChain::new(backend.clone());
79
80 let transaction_pool = Arc::from(
81 sc_transaction_pool::Builder::new(
82 task_manager.spawn_essential_handle(),
83 client.clone(),
84 config.role.is_authority().into(),
85 )
86 .with_options(config.transaction_pool.clone())
87 .with_prometheus(config.prometheus_registry())
88 .build(),
89 );
90
91 let import_queue = sc_consensus_manual_seal::import_queue(
92 Box::new(client.clone()),
93 &task_manager.spawn_essential_handle(),
94 config.prometheus_registry(),
95 );
96
97 Ok(sc_service::PartialComponents {
98 client,
99 backend,
100 task_manager,
101 import_queue,
102 keystore_container,
103 select_chain,
104 transaction_pool,
105 other: (telemetry),
106 })
107}
108
109pub fn new_full<Network: sc_network::NetworkBackend<Block, <Block as BlockT>::Hash>>(
111 config: Configuration,
112 consensus: Consensus,
113) -> Result<TaskManager, ServiceError> {
114 let sc_service::PartialComponents {
115 client,
116 backend,
117 mut task_manager,
118 import_queue,
119 keystore_container,
120 select_chain,
121 transaction_pool,
122 other: mut telemetry,
123 } = new_partial(&config)?;
124
125 let net_config = sc_network::config::FullNetworkConfiguration::<
126 Block,
127 <Block as BlockT>::Hash,
128 Network,
129 >::new(
130 &config.network,
131 config.prometheus_config.as_ref().map(|cfg| cfg.registry.clone()),
132 );
133 let metrics = Network::register_notification_metrics(
134 config.prometheus_config.as_ref().map(|cfg| &cfg.registry),
135 );
136
137 let (network, system_rpc_tx, tx_handler_controller, sync_service) =
138 sc_service::build_network(sc_service::BuildNetworkParams {
139 config: &config,
140 net_config,
141 client: client.clone(),
142 transaction_pool: transaction_pool.clone(),
143 spawn_handle: task_manager.spawn_handle(),
144 import_queue,
145 block_announce_validator_builder: None,
146 warp_sync_config: None,
147 block_relay: None,
148 metrics,
149 })?;
150
151 if config.offchain_worker.enabled {
152 let offchain_workers =
153 sc_offchain::OffchainWorkers::new(sc_offchain::OffchainWorkerOptions {
154 runtime_api_provider: client.clone(),
155 is_validator: config.role.is_authority(),
156 keystore: Some(keystore_container.keystore()),
157 offchain_db: backend.offchain_storage(),
158 transaction_pool: Some(OffchainTransactionPoolFactory::new(
159 transaction_pool.clone(),
160 )),
161 network_provider: Arc::new(network.clone()),
162 enable_http_requests: true,
163 custom_extensions: |_| vec![],
164 })?;
165 task_manager.spawn_handle().spawn(
166 "offchain-workers-runner",
167 "offchain-worker",
168 offchain_workers.run(client.clone(), task_manager.spawn_handle()).boxed(),
169 );
170 }
171
172 let rpc_extensions_builder = {
173 let client = client.clone();
174 let pool = transaction_pool.clone();
175
176 Box::new(move |_| {
177 let deps = crate::rpc::FullDeps { client: client.clone(), pool: pool.clone() };
178 crate::rpc::create_full(deps).map_err(Into::into)
179 })
180 };
181
182 let prometheus_registry = config.prometheus_registry().cloned();
183
184 let _rpc_handlers = sc_service::spawn_tasks(sc_service::SpawnTasksParams {
185 network,
186 client: client.clone(),
187 keystore: keystore_container.keystore(),
188 task_manager: &mut task_manager,
189 transaction_pool: transaction_pool.clone(),
190 rpc_builder: rpc_extensions_builder,
191 backend,
192 system_rpc_tx,
193 tx_handler_controller,
194 sync_service,
195 config,
196 telemetry: telemetry.as_mut(),
197 })?;
198
199 let proposer = sc_basic_authorship::ProposerFactory::new(
200 task_manager.spawn_handle(),
201 client.clone(),
202 transaction_pool.clone(),
203 prometheus_registry.as_ref(),
204 telemetry.as_ref().map(|x| x.handle()),
205 );
206
207 match consensus {
208 Consensus::InstantSeal => {
209 let params = sc_consensus_manual_seal::InstantSealParams {
210 block_import: client.clone(),
211 env: proposer,
212 client,
213 pool: transaction_pool,
214 select_chain,
215 consensus_data_provider: None,
216 create_inherent_data_providers: move |_, ()| async move {
217 Ok(sp_timestamp::InherentDataProvider::from_system_time())
218 },
219 };
220
221 let authorship_future = sc_consensus_manual_seal::run_instant_seal(params);
222
223 task_manager.spawn_essential_handle().spawn_blocking(
224 "instant-seal",
225 None,
226 authorship_future,
227 );
228 },
229 Consensus::ManualSeal(block_time) => {
230 let (mut sink, commands_stream) = futures::channel::mpsc::channel(1024);
231 task_manager.spawn_handle().spawn("block_authoring", None, async move {
232 loop {
233 futures_timer::Delay::new(std::time::Duration::from_millis(block_time)).await;
234 sink.try_send(sc_consensus_manual_seal::EngineCommand::SealNewBlock {
235 create_empty: true,
236 finalize: true,
237 parent_hash: None,
238 sender: None,
239 })
240 .unwrap();
241 }
242 });
243
244 let params = sc_consensus_manual_seal::ManualSealParams {
245 block_import: client.clone(),
246 env: proposer,
247 client,
248 pool: transaction_pool,
249 select_chain,
250 commands_stream: Box::pin(commands_stream),
251 consensus_data_provider: None,
252 create_inherent_data_providers: move |_, ()| async move {
253 Ok(sp_timestamp::InherentDataProvider::from_system_time())
254 },
255 };
256 let authorship_future = sc_consensus_manual_seal::run_manual_seal(params);
257
258 task_manager.spawn_essential_handle().spawn_blocking(
259 "manual-seal",
260 None,
261 authorship_future,
262 );
263 },
264 _ => {},
265 }
266
267 Ok(task_manager)
268}