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::{DenyUnsafe, SubscriptionTaskExecutor};
25

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

            
59
pub struct DefaultEthConfig<C, BE>(std::marker::PhantomData<(C, BE)>);
60

            
61
impl<C, BE> fc_rpc::EthConfig<Block, C> for DefaultEthConfig<C, BE>
62
where
63
    C: StorageProvider<Block, BE> + Sync + Send + 'static,
64
    BE: Backend<Block> + 'static,
65
{
66
    type EstimateGasAdapter = ();
67
    type RuntimeStorageOverride =
68
        fc_rpc::frontier_backend_client::SystemAccountId20StorageOverride<Block, C, BE>;
69
}
70

            
71
mod eth;
72
pub use eth::*;
73
mod finality;
74

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

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

            
147
260
    let mut io = RpcModule::new(());
148
260
    let FullDeps {
149
260
        client,
150
260
        pool,
151
260
        graph,
152
260
        deny_unsafe,
153
260
        network,
154
260
        sync,
155
260
        filter_pool,
156
260
        frontier_backend,
157
260
        backend: _,
158
260
        max_past_logs,
159
260
        fee_history_limit,
160
260
        fee_history_cache,
161
260
        overrides,
162
260
        block_data_cache,
163
260
        is_authority,
164
260
        command_sink,
165
260
        xcm_senders,
166
260
    } = deps;
167
260

            
168
260
    io.merge(System::new(Arc::clone(&client), Arc::clone(&pool), deny_unsafe).into_rpc())?;
169

            
170
    // TODO: are we supporting signing?
171
260
    let signers = Vec::new();
172

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

            
186
260
    let pending_create_inherent_data_providers = move |_, _| {
187
4
        let authorities_for_cidp = authorities.clone();
188

            
189
4
        async move {
190
4
            let mocked_authorities_noting =
191
4
                ccp_authorities_noting_inherent::MockAuthoritiesNotingInherentDataProvider {
192
4
                    current_para_block: 1000,
193
4
                    relay_offset: 1000,
194
4
                    relay_blocks_per_para_block: 2,
195
4
                    orchestrator_para_id: 1000u32.into(),
196
4
                    container_para_id: 2000u32.into(),
197
4
                    authorities: authorities_for_cidp,
198
4
                };
199
4

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

            
230
260
    let pending_consensus_data_provider_frontier: Option<
231
260
        Box<(dyn fc_rpc::pending::ConsensusDataProvider<_>)>,
232
260
    > = Some(Box::new(
233
260
        tc_consensus::ContainerManualSealAuraConsensusDataProvider::new(
234
260
            SlotDuration::from_millis(container_chain_template_frontier_runtime::SLOT_DURATION),
235
260
            authorities_for_cdp,
236
260
        ),
237
260
    ));
238
260

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

            
261
260
    let tx_pool = TxPool::new(client.clone(), graph.clone());
262
260
    if let Some(filter_pool) = filter_pool {
263
260
        io.merge(
264
260
            EthFilter::new(
265
260
                client.clone(),
266
260
                frontier_backend.clone(),
267
260
                graph,
268
260
                filter_pool,
269
260
                500_usize, // max stored filters
270
260
                max_past_logs,
271
260
                block_data_cache,
272
260
            )
273
260
            .into_rpc(),
274
260
        )?;
275
    }
276

            
277
260
    io.merge(
278
260
        Net::new(
279
260
            Arc::clone(&client),
280
260
            network,
281
260
            // Whether to format the `peer_count` response as Hex (default) or not.
282
260
            true,
283
260
        )
284
260
        .into_rpc(),
285
260
    )?;
286

            
287
260
    if let Some(command_sink) = command_sink {
288
260
        io.merge(
289
260
            // We provide the rpc handler with the sending end of the channel to allow the rpc
290
260
            // send EngineCommands to the background block authorship task.
291
260
            ManualSeal::new(command_sink).into_rpc(),
292
260
        )?;
293
    };
294

            
295
260
    io.merge(Web3::new(Arc::clone(&client)).into_rpc())?;
296
260
    io.merge(
297
260
        EthPubSub::new(
298
260
            pool,
299
260
            Arc::clone(&client),
300
260
            sync,
301
260
            subscription_task_executor,
302
260
            overrides,
303
260
            pubsub_notification_sinks,
304
260
        )
305
260
        .into_rpc(),
306
260
    )?;
307
260
    io.merge(tx_pool.into_rpc())?;
308

            
309
260
    if let Some((downward_message_channel, hrmp_message_channel)) = xcm_senders {
310
260
        io.merge(
311
260
            ManualXcm {
312
260
                downward_message_channel,
313
260
                hrmp_message_channel,
314
260
            }
315
260
            .into_rpc(),
316
260
        )?;
317
    }
318

            
319
260
    io.merge(FrontierFinality::new(client.clone(), frontier_backend.clone()).into_rpc())?;
320

            
321
260
    Ok(io)
322
260
}
323

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

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

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

            
421
    // Spawn Frontier FeeHistory cache maintenance task.
422
130
    params.task_manager.spawn_essential_handle().spawn(
423
130
        "frontier-fee-history",
424
130
        Some("frontier"),
425
130
        EthTask::fee_history_task(
426
130
            Arc::clone(&params.client),
427
130
            Arc::clone(&params.overrides),
428
130
            params.fee_history_cache,
429
130
            params.fee_history_limit,
430
130
        ),
431
130
    );
432
130
}
433

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

            
452
impl<Api> RuntimeApiCollection for Api where
453
    Api: sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block>
454
        + sp_api::ApiExt<Block>
455
        + sp_block_builder::BlockBuilder<Block>
456
        + substrate_frame_rpc_system::AccountNonceApi<Block, AccountId, Index>
457
        + sp_api::Metadata<Block>
458
        + sp_offchain::OffchainWorkerApi<Block>
459
        + sp_session::SessionKeys<Block>
460
        + fp_rpc::ConvertTransactionRuntimeApi<Block>
461
        + fp_rpc::EthereumRuntimeRPCApi<Block>
462
        + cumulus_primitives_core::CollectCollationInfo<Block>
463
{
464
}