astar_collator/local/
service.rs

1// This file is part of Astar.
2
3// Copyright (C) Stake Technologies Pte.Ltd.
4// SPDX-License-Identifier: GPL-3.0-or-later
5
6// Astar is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
10
11// Astar is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14// GNU General Public License for more details.
15
16// You should have received a copy of the GNU General Public License
17// along with Astar. If not, see <http://www.gnu.org/licenses/>.
18
19//! Local Service and ServiceFactory implementation. Specialized wrapper over substrate service.
20
21pub use crate::parachain::fake_runtime_api::RuntimeApi;
22use crate::{
23    evm_tracing_types::{EthApi as EthApiCmd, FrontierConfig},
24    rpc::tracing,
25};
26use cumulus_client_parachain_inherent::MockXcmConfig;
27use cumulus_primitives_aura::Slot;
28use cumulus_primitives_core::{
29    relay_chain,
30    relay_chain::{well_known_keys, AsyncBackingParams, HeadData, UpgradeGoAhead},
31    AbridgedHostConfiguration, CollectCollationInfo, InboundHrmpMessage, ParaId,
32    RelayParentOffsetApi,
33};
34use cumulus_primitives_parachain_inherent::{MessageQueueChain, ParachainInherentData};
35use cumulus_test_relay_sproof_builder::RelayStateSproofBuilder;
36use fc_consensus::FrontierBlockImport;
37use fc_rpc_core::types::{FeeHistoryCache, FilterPool};
38use fc_storage::StorageOverrideHandler;
39use futures::{FutureExt, StreamExt};
40use parity_scale_codec::Encode;
41use polkadot_core_primitives::InboundDownwardMessage;
42use polkadot_primitives::PersistedValidationData;
43use sc_client_api::{Backend, BlockchainEvents};
44use sc_executor::{HeapAllocStrategy, WasmExecutor, DEFAULT_HEAP_ALLOC_STRATEGY};
45use sc_network::NetworkBackend;
46use sc_service::{error::Error as ServiceError, Configuration, TaskManager};
47use sc_telemetry::{Telemetry, TelemetryWorker};
48use sc_transaction_pool_api::OffchainTransactionPoolFactory;
49use sp_api::ProvideRuntimeApi;
50use sp_blockchain::HeaderBackend;
51use sp_inherents::{InherentData, InherentDataProvider};
52use sp_runtime::traits::{Block as BlockT, Header as HeaderT, UniqueSaturatedInto};
53use std::{collections::BTreeMap, marker::PhantomData, ops::Sub, sync::Arc, time::Duration};
54
55use astar_primitives::*;
56
57/// Local pending inherent provider for ETH pending RPC in dev mode.
58pub struct LocalPendingInherentDataProvider<B, C> {
59    client: Arc<C>,
60    para_id: ParaId,
61    phantom_data: PhantomData<B>,
62}
63
64const RELAY_CHAIN_SLOT_DURATION_MILLIS: u64 = 6000;
65
66/// Inherent data provider that supplies mocked validation data.
67/// TODO: Use it from PolkadotSDK again after stable2603 uplift
68#[derive(Default)]
69pub struct MockValidationDataInherentDataProvider<R = ()> {
70    /// The current block number of the local block chain (the parachain).
71    pub current_para_block: u32,
72    /// The parachain ID of the parachain for that the inherent data is created.
73    pub para_id: ParaId,
74    /// The current block head data of the local block chain (the parachain).
75    pub current_para_block_head: Option<cumulus_primitives_core::relay_chain::HeadData>,
76    /// The relay block in which this parachain appeared to start. This will be the relay block
77    /// number in para block #P1.
78    pub relay_offset: u32,
79    /// The relay parent offset that determines how many relay parent descendants are required.
80    pub relay_parent_offset: u32,
81    /// The number of relay blocks that elapses between each parablock. Probably set this to 1 or 2
82    /// to simulate optimistic or realistic relay chain behavior.
83    pub relay_blocks_per_para_block: u32,
84    /// Number of parachain blocks per relay chain epoch
85    /// Mock epoch is computed by dividing `current_para_block` by this value.
86    pub para_blocks_per_relay_epoch: u32,
87    /// Function to mock BABE one epoch ago randomness.
88    pub relay_randomness_config: R,
89    /// XCM messages and associated configuration information.
90    pub xcm_config: MockXcmConfig,
91    /// Inbound downward XCM messages to be injected into the block.
92    pub raw_downward_messages: Vec<Vec<u8>>,
93    /// Inbound Horizontal messages sorted by channel.
94    pub raw_horizontal_messages: Vec<(ParaId, Vec<u8>)>,
95    /// Additional key-value pairs that should be injected.
96    pub additional_key_values: Option<Vec<(Vec<u8>, Vec<u8>)>>,
97    /// Whether upgrade go ahead should be set.
98    pub upgrade_go_ahead: Option<UpgradeGoAhead>,
99}
100
101/// Something that can generate randomness.
102pub trait GenerateRandomness<I> {
103    /// Generate the randomness using the given `input`.
104    fn generate_randomness(&self, input: I) -> relay_chain::Hash;
105}
106
107impl GenerateRandomness<u64> for () {
108    /// Default implementation uses relay epoch as randomness value
109    /// A more seemingly random implementation may hash the relay epoch instead
110    fn generate_randomness(&self, input: u64) -> relay_chain::Hash {
111        let mut mock_randomness: [u8; 32] = [0u8; 32];
112        mock_randomness[..8].copy_from_slice(&input.to_be_bytes());
113        mock_randomness.into()
114    }
115}
116
117#[async_trait::async_trait]
118impl<R: Send + Sync + GenerateRandomness<u64>> InherentDataProvider
119    for MockValidationDataInherentDataProvider<R>
120{
121    async fn provide_inherent_data(
122        &self,
123        inherent_data: &mut InherentData,
124    ) -> Result<(), sp_inherents::Error> {
125        // Use the "sproof" (spoof proof) builder to build valid mock state root and proof.
126        let mut sproof_builder = RelayStateSproofBuilder {
127            para_id: self.para_id,
128            ..Default::default()
129        };
130
131        // Calculate the mocked relay block based on the current para block
132        let relay_parent_number =
133            self.relay_offset + self.relay_blocks_per_para_block * self.current_para_block;
134        sproof_builder.current_slot = Slot::from(relay_parent_number as u64);
135
136        sproof_builder.upgrade_go_ahead = self.upgrade_go_ahead;
137        // Process the downward messages and set up the correct head
138        let mut downward_messages = Vec::new();
139        let mut dmq_mqc = MessageQueueChain::new(self.xcm_config.starting_dmq_mqc_head);
140        for msg in &self.raw_downward_messages {
141            let wrapped = InboundDownwardMessage {
142                sent_at: relay_parent_number,
143                msg: msg.clone(),
144            };
145
146            dmq_mqc.extend_downward(&wrapped);
147            downward_messages.push(wrapped);
148        }
149        sproof_builder.dmq_mqc_head = Some(dmq_mqc.head());
150
151        // Process the hrmp messages and set up the correct heads
152        // Begin by collecting them into a Map
153        let mut horizontal_messages = BTreeMap::<ParaId, Vec<InboundHrmpMessage>>::new();
154        for (para_id, msg) in &self.raw_horizontal_messages {
155            let wrapped = InboundHrmpMessage {
156                sent_at: relay_parent_number,
157                data: msg.clone(),
158            };
159
160            horizontal_messages
161                .entry(*para_id)
162                .or_default()
163                .push(wrapped);
164        }
165
166        // Now iterate again, updating the heads as we go
167        for (para_id, messages) in &horizontal_messages {
168            let mut channel_mqc = MessageQueueChain::new(
169                *self
170                    .xcm_config
171                    .starting_hrmp_mqc_heads
172                    .get(para_id)
173                    .unwrap_or(&relay_chain::Hash::default()),
174            );
175            for message in messages {
176                channel_mqc.extend_hrmp(message);
177            }
178            sproof_builder.upsert_inbound_channel(*para_id).mqc_head = Some(channel_mqc.head());
179        }
180
181        // Epoch is set equal to current para block / blocks per epoch
182        sproof_builder.current_epoch = if self.para_blocks_per_relay_epoch == 0 {
183            // do not divide by 0 => set epoch to para block number
184            self.current_para_block.into()
185        } else {
186            (self.current_para_block / self.para_blocks_per_relay_epoch).into()
187        };
188        // Randomness is set by randomness generator
189        sproof_builder.randomness = self
190            .relay_randomness_config
191            .generate_randomness(self.current_para_block.into());
192
193        if let Some(key_values) = &self.additional_key_values {
194            sproof_builder.additional_key_values = key_values.clone()
195        }
196
197        // Inject current para block head, if any
198        sproof_builder.included_para_head = self.current_para_block_head.clone();
199
200        let (relay_parent_storage_root, proof, relay_parent_descendants) =
201            sproof_builder.into_state_root_proof_and_descendants(self.relay_parent_offset.into());
202        let parachain_inherent_data = ParachainInherentData {
203            validation_data: PersistedValidationData {
204                parent_head: Default::default(),
205                relay_parent_storage_root,
206                relay_parent_number,
207                max_pov_size: Default::default(),
208            },
209            downward_messages,
210            horizontal_messages,
211            relay_chain_state: proof,
212            relay_parent_descendants,
213            collator_peer_id: None,
214        };
215
216        parachain_inherent_data
217            .provide_inherent_data(inherent_data)
218            .await
219    }
220
221    // Copied from the real implementation
222    async fn try_handle_error(
223        &self,
224        _: &sp_inherents::InherentIdentifier,
225        _: &[u8],
226    ) -> Option<Result<(), sp_inherents::Error>> {
227        None
228    }
229}
230
231fn build_local_mock_inherent_data(
232    para_id: ParaId,
233    current_para_block: u32,
234    current_para_block_head: Option<HeadData>,
235    relay_blocks_per_para_block: u32,
236    relay_slot: u64,
237    relay_parent_offset: u32,
238    upgrade_go_ahead: Option<UpgradeGoAhead>,
239) -> (
240    sp_timestamp::InherentDataProvider,
241    MockValidationDataInherentDataProvider<()>,
242) {
243    let relay_offset = relay_parent_offset.saturating_add(
244        (relay_slot as u32)
245            .saturating_sub(relay_blocks_per_para_block.saturating_mul(current_para_block)),
246    );
247
248    let local_host_config = AbridgedHostConfiguration {
249        max_code_size: 16 * 1024 * 1024, // 16 MiB (local dev only)
250        max_head_data_size: 1024 * 1024,
251        max_upward_queue_count: 8,
252        max_upward_queue_size: 1024,
253        max_upward_message_size: 256,
254        max_upward_message_num_per_candidate: 5,
255        hrmp_max_message_num_per_candidate: 5,
256        validation_upgrade_cooldown: 6,
257        validation_upgrade_delay: 6,
258        async_backing_params: AsyncBackingParams {
259            allowed_ancestry_len: 0,
260            max_candidate_depth: 0,
261        },
262    };
263
264    let mocked_parachain = MockValidationDataInherentDataProvider::<()> {
265        current_para_block,
266        para_id,
267        current_para_block_head,
268        relay_blocks_per_para_block,
269        relay_offset,
270        relay_parent_offset,
271        para_blocks_per_relay_epoch: 10,
272        upgrade_go_ahead,
273        additional_key_values: Some(vec![(
274            well_known_keys::ACTIVE_CONFIG.to_vec(),
275            local_host_config.encode(),
276        )]),
277        ..Default::default()
278    };
279
280    let timestamp = relay_slot
281        .saturating_add(u64::from(relay_parent_offset))
282        .saturating_mul(RELAY_CHAIN_SLOT_DURATION_MILLIS);
283    let timestamp_provider = sp_timestamp::InherentDataProvider::new(timestamp.into());
284
285    (timestamp_provider, mocked_parachain)
286}
287
288impl<B, C> LocalPendingInherentDataProvider<B, C> {
289    /// Creates a new instance with the given client and parachain ID.
290    pub fn new(client: Arc<C>, para_id: ParaId) -> Self {
291        Self {
292            client,
293            para_id,
294            phantom_data: Default::default(),
295        }
296    }
297}
298
299#[async_trait::async_trait]
300impl<B, C> sp_inherents::CreateInherentDataProviders<B, ()>
301    for LocalPendingInherentDataProvider<B, C>
302where
303    B: BlockT,
304    C: ProvideRuntimeApi<B> + HeaderBackend<B> + Send + Sync,
305    C::Api: RelayParentOffsetApi<B>,
306{
307    type InherentDataProviders = (
308        sp_timestamp::InherentDataProvider,
309        MockValidationDataInherentDataProvider<()>,
310    );
311
312    async fn create_inherent_data_providers(
313        &self,
314        parent: B::Hash,
315        _extra_args: (),
316    ) -> Result<Self::InherentDataProviders, Box<dyn std::error::Error + Send + Sync>> {
317        let relay_slot = std::time::SystemTime::now()
318            .duration_since(std::time::UNIX_EPOCH)
319            .expect("Current time is always after UNIX_EPOCH; qed")
320            .as_millis() as u64
321            / RELAY_CHAIN_SLOT_DURATION_MILLIS;
322
323        let current_para_block = self
324            .client
325            .header(parent)?
326            .map(|header| {
327                UniqueSaturatedInto::<u32>::unique_saturated_into(*header.number())
328                    .saturating_add(1)
329            })
330            .unwrap_or(1);
331
332        let current_para_block_head = self
333            .client
334            .header(parent)?
335            .map(|header| header.encode().into());
336
337        let relay_parent_offset = self.client.runtime_api().relay_parent_offset(parent)?;
338
339        let (timestamp_provider, mocked_parachain) = build_local_mock_inherent_data(
340            self.para_id,
341            current_para_block,
342            current_para_block_head,
343            1,
344            relay_slot,
345            relay_parent_offset,
346            None,
347        );
348
349        Ok((timestamp_provider, mocked_parachain))
350    }
351}
352
353/// Parachain host functions
354#[cfg(feature = "runtime-benchmarks")]
355pub type HostFunctions = (
356    frame_benchmarking::benchmarking::HostFunctions,
357    cumulus_client_service::ParachainHostFunctions,
358    moonbeam_primitives_ext::moonbeam_ext::HostFunctions,
359);
360
361/// Parachain host functions
362#[cfg(not(feature = "runtime-benchmarks"))]
363pub type HostFunctions = (
364    cumulus_client_service::ParachainHostFunctions,
365    moonbeam_primitives_ext::moonbeam_ext::HostFunctions,
366);
367
368type ParachainExecutor = WasmExecutor<HostFunctions>;
369
370type FullClient = sc_service::TFullClient<Block, RuntimeApi, ParachainExecutor>;
371type FullBackend = sc_service::TFullBackend<Block>;
372type FullSelectChain = sc_consensus::LongestChain<FullBackend, Block>;
373
374/// Build a partial chain component config
375pub fn new_partial(
376    config: &Configuration,
377    evm_tracing_config: &FrontierConfig,
378) -> Result<
379    sc_service::PartialComponents<
380        FullClient,
381        FullBackend,
382        FullSelectChain,
383        sc_consensus::DefaultImportQueue<Block>,
384        sc_transaction_pool::TransactionPoolHandle<Block, FullClient>,
385        (
386            FrontierBlockImport<Block, Arc<FullClient>, FullClient>,
387            Option<Telemetry>,
388            Arc<fc_db::Backend<Block, FullClient>>,
389        ),
390    >,
391    ServiceError,
392> {
393    let telemetry = config
394        .telemetry_endpoints
395        .clone()
396        .filter(|x| !x.is_empty())
397        .map(|endpoints| -> Result<_, sc_telemetry::Error> {
398            let worker = TelemetryWorker::new(16)?;
399            let telemetry = worker.handle().new_telemetry(endpoints);
400            Ok((worker, telemetry))
401        })
402        .transpose()?;
403
404    let heap_pages = config
405        .executor
406        .default_heap_pages
407        .map_or(DEFAULT_HEAP_ALLOC_STRATEGY, |h| HeapAllocStrategy::Static {
408            extra_pages: h as _,
409        });
410
411    let executor = ParachainExecutor::builder()
412        .with_execution_method(config.executor.wasm_method)
413        .with_onchain_heap_alloc_strategy(heap_pages)
414        .with_offchain_heap_alloc_strategy(heap_pages)
415        .with_max_runtime_instances(config.executor.max_runtime_instances)
416        .with_runtime_cache_size(config.executor.runtime_cache_size)
417        .build();
418
419    let (client, backend, keystore_container, task_manager) =
420        sc_service::new_full_parts_record_import::<Block, RuntimeApi, _>(
421            config,
422            telemetry.as_ref().map(|(_, telemetry)| telemetry.handle()),
423            executor,
424            true,
425        )?;
426    let client = Arc::new(client);
427    let telemetry = telemetry.map(|(worker, telemetry)| {
428        task_manager
429            .spawn_handle()
430            .spawn("telemetry", None, worker.run());
431        telemetry
432    });
433    let select_chain = sc_consensus::LongestChain::new(backend.clone());
434    let transaction_pool = sc_transaction_pool::Builder::new(
435        task_manager.spawn_essential_handle(),
436        client.clone(),
437        config.role.is_authority().into(),
438    )
439    .with_options(config.transaction_pool.clone())
440    .with_prometheus(config.prometheus_registry())
441    .build();
442    let frontier_backend = Arc::new(crate::rpc::open_frontier_backend(
443        client.clone(),
444        config,
445        evm_tracing_config,
446    )?);
447    let frontier_block_import = FrontierBlockImport::new(client.clone(), client.clone());
448
449    let import_queue = sc_consensus_manual_seal::import_queue(
450        Box::new(client.clone()),
451        &task_manager.spawn_essential_handle(),
452        config.prometheus_registry(),
453    );
454
455    Ok(sc_service::PartialComponents {
456        client,
457        backend,
458        task_manager,
459        import_queue,
460        keystore_container,
461        select_chain,
462        transaction_pool: transaction_pool.into(),
463        other: (frontier_block_import, telemetry, frontier_backend),
464    })
465}
466
467/// Builds a new local development service (parachain-oriented).
468pub fn start_node<N>(
469    mut config: Configuration,
470    evm_tracing_config: FrontierConfig,
471) -> Result<TaskManager, ServiceError>
472where
473    N: NetworkBackend<Block, <Block as BlockT>::Hash>,
474{
475    let sc_service::PartialComponents {
476        client,
477        backend,
478        mut task_manager,
479        import_queue,
480        keystore_container,
481        select_chain,
482        transaction_pool,
483        other: (block_import, mut telemetry, frontier_backend),
484    } = new_partial(&config, &evm_tracing_config)?;
485
486    // Dev node: no peers
487    config.network.default_peers_set.in_peers = 0;
488    config.network.default_peers_set.out_peers = 0;
489
490    let net_config = sc_network::config::FullNetworkConfiguration::<_, _, N>::new(
491        &config.network,
492        config.prometheus_registry().cloned(),
493    );
494
495    let metrics = N::register_notification_metrics(
496        config.prometheus_config.as_ref().map(|cfg| &cfg.registry),
497    );
498    let (network, system_rpc_tx, tx_handler_controller, sync_service) =
499        sc_service::build_network(sc_service::BuildNetworkParams {
500            config: &config,
501            net_config,
502            client: client.clone(),
503            transaction_pool: transaction_pool.clone(),
504            spawn_handle: task_manager.spawn_handle(),
505            import_queue,
506            block_announce_validator_builder: None,
507            warp_sync_config: None,
508            block_relay: None,
509            metrics,
510        })?;
511
512    if config.offchain_worker.enabled {
513        task_manager.spawn_handle().spawn(
514            "offchain-workers-runner",
515            "offchain-work",
516            sc_offchain::OffchainWorkers::new(sc_offchain::OffchainWorkerOptions {
517                runtime_api_provider: client.clone(),
518                keystore: Some(keystore_container.keystore()),
519                offchain_db: backend.offchain_storage(),
520                transaction_pool: Some(OffchainTransactionPoolFactory::new(
521                    transaction_pool.clone(),
522                )),
523                network_provider: Arc::new(network.clone()),
524                is_validator: config.role.is_authority(),
525                enable_http_requests: true,
526                custom_extensions: move |_| vec![],
527            })?
528            .run(client.clone(), task_manager.spawn_handle())
529            .boxed(),
530        );
531    }
532
533    let filter_pool: FilterPool = Arc::new(std::sync::Mutex::new(BTreeMap::new()));
534    let fee_history_cache: FeeHistoryCache = Arc::new(std::sync::Mutex::new(BTreeMap::new()));
535    let storage_override = Arc::new(StorageOverrideHandler::new(client.clone()));
536
537    // Sinks for pubsub notifications.
538    // Everytime a new subscription is created, a new mpsc channel is added to the sink pool.
539    // The MappingSyncWorker sends through the channel on block import and the subscription emits a notification to the subscriber on receiving a message through this channel.
540    // This way we avoid race conditions when using native substrate block import notification stream.
541    let pubsub_notification_sinks: fc_mapping_sync::EthereumBlockNotificationSinks<
542        fc_mapping_sync::EthereumBlockNotification<Block>,
543    > = Default::default();
544    let pubsub_notification_sinks = Arc::new(pubsub_notification_sinks);
545
546    let ethapi_cmd = evm_tracing_config.ethapi.clone();
547
548    let tracing_requesters =
549        if ethapi_cmd.contains(&EthApiCmd::Debug) || ethapi_cmd.contains(&EthApiCmd::Trace) {
550            tracing::spawn_tracing_tasks(
551                &evm_tracing_config,
552                config.prometheus_registry().cloned(),
553                tracing::SpawnTasksParams {
554                    task_manager: &task_manager,
555                    client: client.clone(),
556                    substrate_backend: backend.clone(),
557                    frontier_backend: frontier_backend.clone(),
558                    storage_override: storage_override.clone(),
559                },
560            )
561        } else {
562            tracing::RpcRequesters {
563                debug: None,
564                trace: None,
565            }
566        };
567
568    // Frontier offchain DB task. Essential.
569    // Maps emulated ethereum data to substrate native data.
570    match frontier_backend.as_ref() {
571        fc_db::Backend::KeyValue(ref b) => {
572            task_manager.spawn_essential_handle().spawn(
573                "frontier-mapping-sync-worker",
574                Some("frontier"),
575                fc_mapping_sync::kv::MappingSyncWorker::new(
576                    client.import_notification_stream(),
577                    Duration::new(6, 0),
578                    client.clone(),
579                    backend.clone(),
580                    storage_override.clone(),
581                    b.clone(),
582                    3,
583                    0,
584                    None,
585                    fc_mapping_sync::SyncStrategy::Parachain,
586                    sync_service.clone(),
587                    pubsub_notification_sinks.clone(),
588                )
589                .for_each(|()| futures::future::ready(())),
590            );
591        }
592        fc_db::Backend::Sql(ref b) => {
593            task_manager.spawn_essential_handle().spawn_blocking(
594                "frontier-mapping-sync-worker",
595                Some("frontier"),
596                fc_mapping_sync::sql::SyncWorker::run(
597                    client.clone(),
598                    backend.clone(),
599                    b.clone(),
600                    client.import_notification_stream(),
601                    fc_mapping_sync::sql::SyncWorkerConfig {
602                        read_notification_timeout: Duration::from_secs(10),
603                        check_indexed_blocks_interval: Duration::from_secs(60),
604                    },
605                    fc_mapping_sync::SyncStrategy::Parachain,
606                    sync_service.clone(),
607                    pubsub_notification_sinks.clone(),
608                ),
609            );
610        }
611    }
612
613    // Frontier `EthFilterApi` maintenance. Manages the pool of user-created Filters.
614    // Each filter is allowed to stay in the pool for 100 blocks.
615    const FILTER_RETAIN_THRESHOLD: u64 = 100;
616    task_manager.spawn_essential_handle().spawn(
617        "frontier-filter-pool",
618        Some("frontier"),
619        fc_rpc::EthTask::filter_pool_task(
620            client.clone(),
621            filter_pool.clone(),
622            FILTER_RETAIN_THRESHOLD,
623        ),
624    );
625
626    const FEE_HISTORY_LIMIT: u64 = 2048;
627    task_manager.spawn_essential_handle().spawn(
628        "frontier-fee-history",
629        Some("frontier"),
630        fc_rpc::EthTask::fee_history_task(
631            client.clone(),
632            storage_override.clone(),
633            fee_history_cache.clone(),
634            FEE_HISTORY_LIMIT,
635        ),
636    );
637
638    let role = config.role.clone();
639    let prometheus_registry = config.prometheus_registry().cloned();
640    let is_authority = config.role.is_authority();
641
642    let block_data_cache = Arc::new(fc_rpc::EthBlockDataCacheTask::new(
643        task_manager.spawn_handle(),
644        storage_override.clone(),
645        50,
646        50,
647        prometheus_registry.clone(),
648    ));
649
650    // Channel for the rpc handler to communicate with the authorship task.
651    let (command_sink, commands_stream) = futures::channel::mpsc::channel(1024);
652    let local_para_id = ParaId::from(
653        crate::parachain::chain_spec::Extensions::try_get(&*config.chain_spec)
654            .map(|e| e.para_id)
655            .unwrap_or(2000),
656    );
657
658    let rpc_extensions_builder = {
659        let client = client.clone();
660        let network = network.clone();
661        let transaction_pool = transaction_pool.clone();
662        let sync = sync_service.clone();
663        let pubsub_notification_sinks = pubsub_notification_sinks.clone();
664
665        Box::new(move |subscription| {
666            let deps = crate::rpc::FullDeps {
667                client: client.clone(),
668                pool: transaction_pool.clone(),
669                graph: transaction_pool.clone(),
670                network: network.clone(),
671                sync: sync.clone(),
672                is_authority,
673                frontier_backend: match *frontier_backend {
674                    fc_db::Backend::KeyValue(ref b) => b.clone(),
675                    fc_db::Backend::Sql(ref b) => b.clone(),
676                },
677                filter_pool: filter_pool.clone(),
678                fee_history_limit: FEE_HISTORY_LIMIT,
679                fee_history_cache: fee_history_cache.clone(),
680                block_data_cache: block_data_cache.clone(),
681                storage_override: storage_override.clone(),
682                enable_evm_rpc: true, // enable EVM RPC for dev node by default
683                command_sink: Some(command_sink.clone()),
684            };
685
686            crate::rpc::create_full_local_dev(
687                deps,
688                subscription,
689                pubsub_notification_sinks.clone(),
690                local_para_id,
691                crate::rpc::EvmTracingConfig {
692                    tracing_requesters: tracing_requesters.clone(),
693                    trace_filter_max_count: evm_tracing_config.ethapi_trace_max_count,
694                    trace_filter_max_block_range: evm_tracing_config.trace_filter_max_block_range,
695                    enable_txpool: ethapi_cmd.contains(&EthApiCmd::TxPool),
696                },
697            )
698            .map_err::<ServiceError, _>(Into::into)
699        })
700    };
701
702    let _rpc_handlers = sc_service::spawn_tasks(sc_service::SpawnTasksParams {
703        network: network.clone(),
704        client: client.clone(),
705        keystore: keystore_container.keystore(),
706        task_manager: &mut task_manager,
707        transaction_pool: transaction_pool.clone(),
708        rpc_builder: rpc_extensions_builder,
709        backend,
710        system_rpc_tx,
711        tx_handler_controller,
712        sync_service: sync_service.clone(),
713        config,
714        telemetry: telemetry.as_mut(),
715        tracing_execute_block: None,
716    })?;
717
718    if role.is_authority() {
719        let proposer_factory = sc_basic_authorship::ProposerFactory::new(
720            task_manager.spawn_handle(),
721            client.clone(),
722            transaction_pool.clone(),
723            prometheus_registry.as_ref(),
724            telemetry.as_ref().map(|x| x.handle()),
725        );
726
727        let slot_duration = sc_consensus_aura::slot_duration(&*client)?;
728
729        let para_id = local_para_id;
730        let initial_relay_slot = std::time::SystemTime::now()
731            .duration_since(std::time::UNIX_EPOCH)
732            .expect("Current time is always after UNIX_EPOCH; qed")
733            .sub(Duration::from_secs(2 * 60 * 60))
734            .as_millis() as u64
735            / RELAY_CHAIN_SLOT_DURATION_MILLIS;
736
737        let aura =
738            sc_consensus_manual_seal::run_manual_seal(sc_consensus_manual_seal::ManualSealParams {
739                block_import,
740                env: proposer_factory,
741                client: client.clone(),
742                pool: transaction_pool.clone(),
743                commands_stream,
744                select_chain,
745                consensus_data_provider: Some(Box::new(
746                    sc_consensus_manual_seal::consensus::aura::AuraConsensusDataProvider::new(
747                        client.clone(),
748                    ),
749                )),
750                create_inherent_data_providers: move |parent_hash, ()| {
751                    let client = client.clone();
752                    async move {
753                        let current_para_head = client
754                            .header(parent_hash)
755                            .expect("Header lookup should succeed")
756                            .expect("Header passed in as parent should be present in backend.");
757
758                        let should_send_go_ahead = client
759                            .runtime_api()
760                            .collect_collation_info(parent_hash, &current_para_head)
761                            .map(|info| info.new_validation_code.is_some())
762                            .unwrap_or_default();
763
764                        let current_para_block = UniqueSaturatedInto::<u32>::unique_saturated_into(
765                            *current_para_head.number(),
766                        ) + 1;
767
768                        let relay_blocks_per_para_block =
769                            (slot_duration.as_millis() / RELAY_CHAIN_SLOT_DURATION_MILLIS).max(1)
770                                as u32;
771                        let current_para_block_u64 = u64::from(current_para_block);
772                        let relay_blocks_per_para_block_u64 =
773                            u64::from(relay_blocks_per_para_block);
774                        let target_relay_slot = initial_relay_slot.saturating_add(
775                            current_para_block_u64.saturating_mul(relay_blocks_per_para_block_u64),
776                        );
777
778                        let current_para_block_head = Some(current_para_head.encode().into());
779                        let relay_parent_offset =
780                            client.runtime_api().relay_parent_offset(parent_hash)?;
781
782                        let (timestamp_provider, mocked_parachain) = build_local_mock_inherent_data(
783                            para_id,
784                            current_para_block,
785                            current_para_block_head,
786                            relay_blocks_per_para_block,
787                            target_relay_slot,
788                            relay_parent_offset,
789                            should_send_go_ahead.then_some(UpgradeGoAhead::GoAhead),
790                        );
791
792                        Ok((timestamp_provider, mocked_parachain))
793                    }
794                },
795            });
796
797        task_manager
798            .spawn_essential_handle()
799            .spawn_blocking("aura", Some("block-authoring"), aura);
800    }
801
802    Ok(task_manager)
803}