1
// Copyright (C) Moondance Labs Ltd.
2
// This file is part of Tanssi.
3

            
4
// Tanssi is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8

            
9
// Tanssi is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13

            
14
// You should have received a copy of the GNU General Public License
15
// along with Tanssi.  If not, see <http://www.gnu.org/licenses/>.
16

            
17
//! A collection of node-specific RPC methods.
18
//! Substrate provides the `sc-rpc` crate, which defines the core RPC layer
19
//! used by Substrate nodes. This file extends those RPC definitions with
20
//! capabilities that are specific to this project's runtime configuration.
21

            
22
#![warn(missing_docs)]
23

            
24
pub use sc_rpc::SubscriptionTaskExecutor;
25

            
26
use {
27
    container_chain_template_frontier_runtime::{opaque::Block, AccountId, Hash, Index},
28
    core::marker::PhantomData,
29
    cumulus_client_parachain_inherent::ParachainInherentData,
30
    cumulus_primitives_core::{ParaId, PersistedValidationData},
31
    cumulus_test_relay_sproof_builder::RelayStateSproofBuilder,
32
    fc_rpc::{
33
        EthApiServer, EthFilterApiServer, EthPubSubApiServer, EthTask, TxPool, TxPoolApiServer,
34
    },
35
    fc_storage::StorageOverride,
36
    fp_rpc::EthereumRuntimeRPCApi,
37
    frame_support::CloneNoBound,
38
    futures::StreamExt,
39
    jsonrpsee::RpcModule,
40
    manual_xcm_rpc::{ManualXcm, ManualXcmApiServer},
41
    sc_client_api::{
42
        backend::{Backend, StateBackend},
43
        client::BlockchainEvents,
44
        AuxStore, BlockOf, StorageProvider,
45
    },
46
    sc_consensus_manual_seal::rpc::{EngineCommand, ManualSeal, ManualSealApiServer},
47
    sc_network_sync::SyncingService,
48
    sc_service::TaskManager,
49
    sc_transaction_pool_api::TransactionPool,
50
    sp_api::{CallApiAt, ProvideRuntimeApi},
51
    sp_block_builder::BlockBuilder,
52
    sp_blockchain::{
53
        Backend as BlockchainBackend, Error as BlockChainError, HeaderBackend, HeaderMetadata,
54
    },
55
    sp_consensus_aura::SlotDuration,
56
    sp_core::H256,
57
    sp_runtime::traits::{BlakeTwo256, Block as BlockT, Header as HeaderT},
58
    std::{
59
        collections::BTreeMap,
60
        sync::{Arc, Mutex},
61
        time::Duration,
62
    },
63
    tc_service_container_chain_spawner::service::{
64
        ContainerChainClient, MinimalContainerRuntimeApi,
65
    },
66
};
67

            
68
pub struct DefaultEthConfig<C, BE>(std::marker::PhantomData<(C, BE)>);
69

            
70
impl<C, BE> fc_rpc::EthConfig<Block, C> for DefaultEthConfig<C, BE>
71
where
72
    C: StorageProvider<Block, BE> + Sync + Send + 'static,
73
    BE: Backend<Block> + 'static,
74
{
75
    type EstimateGasAdapter = ();
76
    type RuntimeStorageOverride =
77
        fc_rpc::frontier_backend_client::SystemAccountId20StorageOverride<Block, C, BE>;
78
}
79

            
80
mod eth;
81
pub use eth::*;
82
mod finality;
83

            
84
/// Full client dependencies.
85
pub struct FullDeps<C, P, BE> {
86
    /// The client instance to use.
87
    pub client: Arc<C>,
88
    /// Transaction pool instance.
89
    pub pool: Arc<P>,
90
    /// Graph pool instance.
91
    pub graph: Arc<P>,
92
    /// Network service
93
    pub network: Arc<dyn sc_network::service::traits::NetworkService>,
94
    /// Chain syncing service
95
    pub sync: Arc<SyncingService<Block>>,
96
    /// EthFilterApi pool.
97
    pub filter_pool: Option<FilterPool>,
98
    /// Frontier Backend.
99
    // TODO: log indexer?
100
    pub frontier_backend: Arc<dyn fc_api::Backend<Block>>,
101
    /// Backend.
102
    #[allow(dead_code)] // not used but keep nice type inference
103
    pub backend: Arc<BE>,
104
    /// Maximum number of logs in a query.
105
    pub max_past_logs: u32,
106
    /// Maximum block range in a query.
107
    pub max_block_range: u32,
108
    /// Maximum fee history cache size.
109
    pub fee_history_limit: u64,
110
    /// Fee history cache.
111
    pub fee_history_cache: FeeHistoryCache,
112
    /// Ethereum data access overrides.
113
    pub overrides: Arc<dyn StorageOverride<Block>>,
114
    /// Cache for Ethereum block data.
115
    pub block_data_cache: Arc<EthBlockDataCacheTask<Block>>,
116
    /// The Node authority flag
117
    pub is_authority: bool,
118
    /// Manual seal command sink
119
    pub command_sink: Option<futures::channel::mpsc::Sender<EngineCommand<Hash>>>,
120
    /// Channels for manual xcm messages (downward, hrmp)
121
    pub xcm_senders: Option<(flume::Sender<Vec<u8>>, flume::Sender<(ParaId, Vec<u8>)>)>,
122
}
123

            
124
/// Instantiate all Full RPC extensions.
125
308
pub fn create_full<C, P, BE>(
126
308
    deps: FullDeps<C, P, BE>,
127
308
    subscription_task_executor: SubscriptionTaskExecutor,
128
308
    pubsub_notification_sinks: Arc<
129
308
        fc_mapping_sync::EthereumBlockNotificationSinks<
130
308
            fc_mapping_sync::EthereumBlockNotification<Block>,
131
308
        >,
132
308
    >,
133
308
) -> Result<RpcModule<()>, Box<dyn std::error::Error + Send + Sync>>
134
308
where
135
308
    BE: Backend<Block> + 'static,
136
308
    BE::State: StateBackend<BlakeTwo256>,
137
308
    BE::Blockchain: BlockchainBackend<Block>,
138
308
    C: ProvideRuntimeApi<Block> + StorageProvider<Block, BE> + AuxStore,
139
308
    C: BlockchainEvents<Block>,
140
308
    C: HeaderBackend<Block> + HeaderMetadata<Block, Error = BlockChainError> + 'static,
141
308
    C: CallApiAt<Block>,
142
308
    C: Send + Sync + 'static,
143
308
    C::Api: RuntimeApiCollection,
144
308
    P: TransactionPool<Block = Block, Hash = <Block as BlockT>::Hash> + 'static,
145
308
{
146
    use {
147
        fc_rpc::{Eth, EthFilter, EthPubSub, Net, NetApiServer, Web3, Web3ApiServer},
148
        finality::{FrontierFinality, FrontierFinalityApiServer},
149
        substrate_frame_rpc_system::{System, SystemApiServer},
150
    };
151

            
152
308
    let mut io = RpcModule::new(());
153
308
    let FullDeps {
154
308
        client,
155
308
        pool,
156
308
        graph,
157
308
        network,
158
308
        sync,
159
308
        filter_pool,
160
308
        frontier_backend,
161
308
        backend: _,
162
308
        max_past_logs,
163
308
        max_block_range,
164
308
        fee_history_limit,
165
308
        fee_history_cache,
166
308
        overrides,
167
308
        block_data_cache,
168
308
        is_authority,
169
308
        command_sink,
170
308
        xcm_senders,
171
308
    } = deps;
172
308

            
173
308
    io.merge(System::new(Arc::clone(&client), Arc::clone(&pool)).into_rpc())?;
174

            
175
    // TODO: are we supporting signing?
176
308
    let signers = Vec::new();
177

            
178
    enum Never {}
179
    impl<T> fp_rpc::ConvertTransaction<T> for Never {
180
        fn convert_transaction(&self, _transaction: pallet_ethereum::Transaction) -> T {
181
            // The Never type is not instantiable, but this method requires the type to be
182
            // instantiated to be called (`&self` parameter), so if the code compiles we have the
183
            // guarantee that this function will never be called.
184
            unreachable!()
185
        }
186
    }
187
308
    let convert_transaction: Option<Never> = None;
188
308
    let authorities = vec![tc_consensus::get_aura_id_from_seed("alice")];
189
308
    let authorities_for_cdp = authorities.clone();
190
308

            
191
308
    let pending_create_inherent_data_providers = move |_, ()| {
192
4
        let authorities_for_cidp = authorities.clone();
193

            
194
4
        async move {
195
4
            let mocked_authorities_noting =
196
4
                ccp_authorities_noting_inherent::MockAuthoritiesNotingInherentDataProvider {
197
4
                    current_para_block: 1000,
198
4
                    relay_offset: 1000,
199
4
                    relay_blocks_per_para_block: 2,
200
4
                    orchestrator_para_id: 1000u32.into(),
201
4
                    container_para_id: 2000u32.into(),
202
4
                    authorities: authorities_for_cidp,
203
4
                };
204
4

            
205
4
            let timestamp = sp_timestamp::InherentDataProvider::from_system_time();
206
4
            // Create a dummy parachain inherent data provider which is required to pass
207
4
            // the checks by the para chain system. We use dummy values because in the 'pending context'
208
4
            // neither do we have access to the real values nor do we need them.
209
4
            let (relay_parent_storage_root, relay_chain_state) = RelayStateSproofBuilder {
210
4
                additional_key_values: mocked_authorities_noting.get_key_values(),
211
4
                ..Default::default()
212
4
            }
213
4
            .into_state_root_and_proof();
214
4
            let vfp = PersistedValidationData {
215
4
                // This is a hack to make `cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases`
216
4
                // happy. Relay parent number can't be bigger than u32::MAX.
217
4
                relay_parent_number: u32::MAX,
218
4
                relay_parent_storage_root,
219
4
                ..Default::default()
220
4
            };
221
4
            let parachain_inherent_data = ParachainInherentData {
222
4
                validation_data: vfp,
223
4
                relay_chain_state,
224
4
                downward_messages: Default::default(),
225
4
                horizontal_messages: Default::default(),
226
4
            };
227
4
            Ok((
228
4
                timestamp,
229
4
                parachain_inherent_data,
230
4
                mocked_authorities_noting,
231
4
            ))
232
4
        }
233
4
    };
234

            
235
308
    let pending_consensus_data_provider_frontier: Option<
236
308
        Box<(dyn fc_rpc::pending::ConsensusDataProvider<_>)>,
237
308
    > = Some(Box::new(
238
308
        tc_consensus::ContainerManualSealAuraConsensusDataProvider::new(
239
308
            SlotDuration::from_millis(container_chain_template_frontier_runtime::SLOT_DURATION),
240
308
            authorities_for_cdp,
241
308
        ),
242
308
    ));
243
308

            
244
308
    io.merge(
245
308
        Eth::<_, _, _, _, _, _, DefaultEthConfig<C, BE>>::new(
246
308
            Arc::clone(&client),
247
308
            Arc::clone(&pool),
248
308
            Arc::clone(&graph),
249
308
            convert_transaction,
250
308
            Arc::clone(&sync),
251
308
            signers,
252
308
            Arc::clone(&overrides),
253
308
            Arc::clone(&frontier_backend),
254
308
            is_authority,
255
308
            Arc::clone(&block_data_cache),
256
308
            fee_history_cache,
257
308
            fee_history_limit,
258
308
            10,
259
308
            None,
260
308
            pending_create_inherent_data_providers,
261
308
            pending_consensus_data_provider_frontier,
262
308
        )
263
308
        .into_rpc(),
264
308
    )?;
265

            
266
308
    let tx_pool: TxPool<Block, _, _> = TxPool::new(client.clone(), graph.clone());
267
308
    if let Some(filter_pool) = filter_pool {
268
308
        io.merge(
269
308
            EthFilter::new(
270
308
                client.clone(),
271
308
                frontier_backend.clone(),
272
308
                graph,
273
308
                filter_pool,
274
308
                500_usize, // max stored filters
275
308
                max_past_logs,
276
308
                max_block_range,
277
308
                block_data_cache,
278
308
            )
279
308
            .into_rpc(),
280
308
        )?;
281
    }
282

            
283
308
    io.merge(
284
308
        Net::new(
285
308
            Arc::clone(&client),
286
308
            network,
287
308
            // Whether to format the `peer_count` response as Hex (default) or not.
288
308
            true,
289
308
        )
290
308
        .into_rpc(),
291
308
    )?;
292

            
293
308
    if let Some(command_sink) = command_sink {
294
308
        io.merge(
295
308
            // We provide the rpc handler with the sending end of the channel to allow the rpc
296
308
            // send EngineCommands to the background block authorship task.
297
308
            ManualSeal::new(command_sink).into_rpc(),
298
308
        )?;
299
    };
300

            
301
308
    io.merge(Web3::new(Arc::clone(&client)).into_rpc())?;
302
308
    io.merge(
303
308
        EthPubSub::new(
304
308
            pool,
305
308
            Arc::clone(&client),
306
308
            sync,
307
308
            subscription_task_executor,
308
308
            overrides,
309
308
            pubsub_notification_sinks,
310
308
        )
311
308
        .into_rpc(),
312
308
    )?;
313
308
    io.merge(tx_pool.into_rpc())?;
314

            
315
308
    if let Some((downward_message_channel, hrmp_message_channel)) = xcm_senders {
316
308
        io.merge(
317
308
            ManualXcm {
318
308
                downward_message_channel,
319
308
                hrmp_message_channel,
320
308
            }
321
308
            .into_rpc(),
322
308
        )?;
323
    }
324

            
325
308
    io.merge(FrontierFinality::new(client.clone(), frontier_backend.clone()).into_rpc())?;
326

            
327
308
    Ok(io)
328
308
}
329

            
330
pub struct SpawnTasksParams<'a, B: BlockT, C, BE> {
331
    pub task_manager: &'a TaskManager,
332
    pub client: Arc<C>,
333
    pub substrate_backend: Arc<BE>,
334
    pub frontier_backend: Arc<fc_db::Backend<B, C>>,
335
    pub filter_pool: Option<FilterPool>,
336
    pub overrides: Arc<dyn StorageOverride<B>>,
337
    pub fee_history_limit: u64,
338
    pub fee_history_cache: FeeHistoryCache,
339
    /// Chain syncing service
340
    pub sync_service: Arc<SyncingService<B>>,
341
    /// Chain syncing service
342
    pub pubsub_notification_sinks: Arc<
343
        fc_mapping_sync::EthereumBlockNotificationSinks<
344
            fc_mapping_sync::EthereumBlockNotification<B>,
345
        >,
346
    >,
347
}
348

            
349
use fc_mapping_sync::{kv::MappingSyncWorker, SyncStrategy};
350
/// Spawn the tasks that are required to run Moonbeam.
351
154
pub fn spawn_essential_tasks<B, C, BE>(params: SpawnTasksParams<B, C, BE>)
352
154
where
353
154
    C: ProvideRuntimeApi<B> + BlockOf,
354
154
    C: HeaderBackend<B> + HeaderMetadata<B, Error = BlockChainError> + 'static,
355
154
    C: BlockchainEvents<B> + StorageProvider<B, BE>,
356
154
    C: Send + Sync + 'static,
357
154
    C::Api: EthereumRuntimeRPCApi<B>,
358
154
    C::Api: BlockBuilder<B>,
359
154
    B: BlockT<Hash = H256> + Send + Sync + 'static,
360
154
    B::Header: HeaderT<Number = u32>,
361
154
    BE: Backend<B> + 'static,
362
154
    BE::State: StateBackend<BlakeTwo256>,
363
154
{
364
154
    // Frontier offchain DB task. Essential.
365
154
    // Maps emulated ethereum data to substrate native data.
366
154
    match &*params.frontier_backend {
367
154
        fc_db::Backend::KeyValue(b) => {
368
154
            params.task_manager.spawn_essential_handle().spawn(
369
154
                "frontier-mapping-sync-worker",
370
154
                Some("frontier"),
371
154
                MappingSyncWorker::new(
372
154
                    params.client.import_notification_stream(),
373
154
                    Duration::new(6, 0),
374
154
                    params.client.clone(),
375
154
                    params.substrate_backend.clone(),
376
154
                    params.overrides.clone(),
377
154
                    b.clone(),
378
154
                    3,
379
154
                    0,
380
154
                    SyncStrategy::Parachain,
381
154
                    params.sync_service.clone(),
382
154
                    params.pubsub_notification_sinks.clone(),
383
154
                )
384
6430
                .for_each(|()| futures::future::ready(())),
385
154
            );
386
154
        }
387
        fc_db::Backend::Sql(b) => {
388
            params.task_manager.spawn_essential_handle().spawn_blocking(
389
                "frontier-mapping-sync-worker",
390
                Some("frontier"),
391
                fc_mapping_sync::sql::SyncWorker::run(
392
                    params.client.clone(),
393
                    params.substrate_backend.clone(),
394
                    b.clone(),
395
                    params.client.import_notification_stream(),
396
                    fc_mapping_sync::sql::SyncWorkerConfig {
397
                        read_notification_timeout: Duration::from_secs(10),
398
                        check_indexed_blocks_interval: Duration::from_secs(60),
399
                    },
400
                    fc_mapping_sync::SyncStrategy::Parachain,
401
                    params.sync_service.clone(),
402
                    params.pubsub_notification_sinks.clone(),
403
                ),
404
            );
405
        }
406
    }
407

            
408
    // Frontier `EthFilterApi` maintenance.
409
    // Manages the pool of user-created Filters.
410
154
    if let Some(filter_pool) = params.filter_pool {
411
154
        // Each filter is allowed to stay in the pool for 100 blocks.
412
154
        // TODO: Re-visit this assumption with parathreads, as they
413
154
        // might have a block every good amount of time, and can be abused
414
154
        // likely we will need to implement a time-based filter
415
154
        const FILTER_RETAIN_THRESHOLD: u64 = 100;
416
154
        params.task_manager.spawn_essential_handle().spawn(
417
154
            "frontier-filter-pool",
418
154
            Some("frontier"),
419
154
            EthTask::filter_pool_task(
420
154
                Arc::clone(&params.client),
421
154
                filter_pool,
422
154
                FILTER_RETAIN_THRESHOLD,
423
154
            ),
424
154
        );
425
154
    }
426

            
427
    // Spawn Frontier FeeHistory cache maintenance task.
428
154
    params.task_manager.spawn_essential_handle().spawn(
429
154
        "frontier-fee-history",
430
154
        Some("frontier"),
431
154
        EthTask::fee_history_task(
432
154
            Arc::clone(&params.client),
433
154
            Arc::clone(&params.overrides),
434
154
            params.fee_history_cache,
435
154
            params.fee_history_limit,
436
154
        ),
437
154
    );
438
154
}
439

            
440
/// A set of APIs that polkadot-like runtimes must implement.
441
///
442
/// This trait has no methods or associated type. It is a concise marker for all the trait bounds
443
/// that it contains.
444
pub trait RuntimeApiCollection:
445
    sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block>
446
    + sp_api::ApiExt<Block>
447
    + sp_block_builder::BlockBuilder<Block>
448
    + substrate_frame_rpc_system::AccountNonceApi<Block, AccountId, Index>
449
    + sp_api::Metadata<Block>
450
    + sp_offchain::OffchainWorkerApi<Block>
451
    + sp_session::SessionKeys<Block>
452
    + fp_rpc::ConvertTransactionRuntimeApi<Block>
453
    + fp_rpc::EthereumRuntimeRPCApi<Block>
454
    + cumulus_primitives_core::CollectCollationInfo<Block>
455
{
456
}
457

            
458
impl<Api> RuntimeApiCollection for Api where
459
    Api: sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block>
460
        + sp_api::ApiExt<Block>
461
        + sp_block_builder::BlockBuilder<Block>
462
        + substrate_frame_rpc_system::AccountNonceApi<Block, AccountId, Index>
463
        + sp_api::Metadata<Block>
464
        + sp_offchain::OffchainWorkerApi<Block>
465
        + sp_session::SessionKeys<Block>
466
        + fp_rpc::ConvertTransactionRuntimeApi<Block>
467
        + fp_rpc::EthereumRuntimeRPCApi<Block>
468
        + cumulus_primitives_core::CollectCollationInfo<Block>
469
{
470
}
471

            
472
tp_traits::alias!(
473
    pub trait FrontierRpcRuntimeApi:
474
        MinimalContainerRuntimeApi +
475
        sp_api::ConstructRuntimeApi<
476
            Block,
477
            ContainerChainClient<Self>,
478
            RuntimeApi:
479
                RuntimeApiCollection
480
        >
481
);
482

            
483
#[derive(CloneNoBound)]
484
pub struct GenerateFrontierRpcBuilder<RuntimeApi> {
485
    rpc_config: crate::cli::RpcConfig,
486
    phantom: PhantomData<RuntimeApi>,
487
}
488

            
489
impl<RuntimeApi> GenerateFrontierRpcBuilder<RuntimeApi> {
490
    pub fn new(rpc_config: crate::cli::RpcConfig) -> Self {
491
        Self {
492
            rpc_config,
493
            phantom: PhantomData,
494
        }
495
    }
496
}
497

            
498
const _: () = {
499
    use tc_service_container_chain_spawner::rpc::generate_rpc_builder::*;
500

            
501
    impl<RuntimeApi: FrontierRpcRuntimeApi> GenerateRpcBuilder<RuntimeApi>
502
        for GenerateFrontierRpcBuilder<RuntimeApi>
503
    {
504
        fn generate(
505
            &self,
506
            GenerateRpcBuilderParams {
507
                backend,
508
                client,
509
                network,
510
                container_chain_config,
511
                prometheus_registry,
512
                sync_service,
513
                task_manager,
514
                transaction_pool,
515
                ..
516
            }: GenerateRpcBuilderParams<RuntimeApi>,
517
        ) -> Result<CompleteRpcBuilder, ServiceError> {
518
            let max_past_logs = self.rpc_config.max_past_logs;
519
            let max_block_range = self.rpc_config.max_block_range;
520

            
521
            // Frontier specific stuff
522
            let filter_pool: Option<FilterPool> = Some(Arc::new(Mutex::new(BTreeMap::new())));
523
            let fee_history_cache: FeeHistoryCache = Arc::new(Mutex::new(BTreeMap::new()));
524
            let frontier_backend = Arc::new(fc_db::Backend::KeyValue(
525
                crate::service::open_frontier_backend(client.clone(), container_chain_config)?
526
                    .into(),
527
            ));
528
            let overrides = Arc::new(fc_rpc::StorageOverrideHandler::new(client.clone()));
529
            let fee_history_limit = self.rpc_config.fee_history_limit;
530

            
531
            let pubsub_notification_sinks: fc_mapping_sync::EthereumBlockNotificationSinks<
532
                fc_mapping_sync::EthereumBlockNotification<Block>,
533
            > = Default::default();
534
            let pubsub_notification_sinks = Arc::new(pubsub_notification_sinks);
535

            
536
            spawn_essential_tasks(SpawnTasksParams {
537
                task_manager,
538
                client: client.clone(),
539
                substrate_backend: backend.clone(),
540
                frontier_backend: frontier_backend.clone(),
541
                filter_pool: filter_pool.clone(),
542
                overrides: overrides.clone(),
543
                fee_history_limit,
544
                fee_history_cache: fee_history_cache.clone(),
545
                sync_service: sync_service.clone(),
546
                pubsub_notification_sinks: pubsub_notification_sinks.clone(),
547
            });
548

            
549
            let block_data_cache = Arc::new(fc_rpc::EthBlockDataCacheTask::new(
550
                task_manager.spawn_handle(),
551
                overrides.clone(),
552
                self.rpc_config.eth_log_block_cache,
553
                self.rpc_config.eth_statuses_cache,
554
                prometheus_registry.clone(),
555
            ));
556

            
557
            Ok(Box::new(move |subscription_task_executor| {
558
                let deps = crate::rpc::FullDeps {
559
                    backend: backend.clone(),
560
                    client: client.clone(),
561
                    filter_pool: filter_pool.clone(),
562
                    frontier_backend: match &*frontier_backend {
563
                        fc_db::Backend::KeyValue(b) => b.clone(),
564
                        fc_db::Backend::Sql(b) => b.clone(),
565
                    },
566
                    graph: transaction_pool.clone(),
567
                    pool: transaction_pool.clone(),
568
                    max_past_logs,
569
                    max_block_range,
570
                    fee_history_limit,
571
                    fee_history_cache: fee_history_cache.clone(),
572
                    network: Arc::new(network.clone()),
573
                    sync: sync_service.clone(),
574
                    block_data_cache: block_data_cache.clone(),
575
                    overrides: overrides.clone(),
576
                    is_authority: false,
577
                    command_sink: None,
578
                    xcm_senders: None,
579
                };
580
                crate::rpc::create_full(
581
                    deps,
582
                    subscription_task_executor,
583
                    pubsub_notification_sinks.clone(),
584
                )
585
                .map_err(Into::into)
586
            }))
587
        }
588
    }
589
};