1pub mod tracing;
20
21use std::{sync::Arc, time::Duration};
22
23use fp_rpc::EthereumRuntimeRPCApi;
24use sp_block_builder::BlockBuilder;
25
26use crate::client::RuntimeApiCollection;
27use crate::RELAY_CHAIN_SLOT_DURATION_MILLIS;
28use cumulus_primitives_core::{ParaId, PersistedValidationData};
29use cumulus_primitives_parachain_inherent::ParachainInherentData;
30use cumulus_test_relay_sproof_builder::RelayStateSproofBuilder;
31use fc_mapping_sync::{kv::MappingSyncWorker, SyncStrategy};
32use fc_rpc::{pending::ConsensusDataProvider, EthBlockDataCacheTask, EthTask, StorageOverride};
33use fc_rpc_core::types::{FeeHistoryCache, FilterPool, TransactionRequest};
34use futures::StreamExt;
35use jsonrpsee::RpcModule;
36use moonbeam_cli_opt::EthApi as EthApiCmd;
37use moonbeam_core_primitives::{Block, Hash};
38use parity_scale_codec::Encode;
39use sc_client_api::{
40 backend::{AuxStore, Backend, StateBackend, StorageProvider},
41 client::BlockchainEvents,
42 BlockOf,
43};
44use sc_consensus_manual_seal::rpc::{EngineCommand, ManualSeal, ManualSealApiServer};
45use sc_network::service::traits::NetworkService;
46use sc_network_sync::SyncingService;
47use sc_rpc::SubscriptionTaskExecutor;
48use sc_service::TaskManager;
49use sc_transaction_pool_api::TransactionPool;
50use sp_api::{CallApiAt, ProvideRuntimeApi};
51use sp_blockchain::{
52 Backend as BlockchainBackend, Error as BlockChainError, HeaderBackend, HeaderMetadata,
53};
54use sp_core::H256;
55use sp_runtime::traits::{BlakeTwo256, Block as BlockT, Header as HeaderT};
56use sp_timestamp::Timestamp;
57use std::collections::BTreeMap;
58
59pub struct MoonbeamEGA;
60
61impl fc_rpc::EstimateGasAdapter for MoonbeamEGA {
62 fn adapt_request(mut request: TransactionRequest) -> TransactionRequest {
63 use sp_core::H160;
66 const BATCH_PRECOMPILE_ADDRESS: H160 = H160(hex_literal::hex!(
67 "0000000000000000000000000000000000000808"
68 ));
69 const BATCH_PRECOMPILE_BATCH_ALL_SELECTOR: [u8; 4] = hex_literal::hex!("96e292b8");
70 if request.to == Some(BATCH_PRECOMPILE_ADDRESS) {
71 match (&mut request.data.input, &mut request.data.data) {
72 (Some(ref mut input), _) => {
73 if input.0.len() >= 4 {
74 input.0[..4].copy_from_slice(&BATCH_PRECOMPILE_BATCH_ALL_SELECTOR);
75 }
76 }
77 (None, Some(ref mut data)) => {
78 if data.0.len() >= 4 {
79 data.0[..4].copy_from_slice(&BATCH_PRECOMPILE_BATCH_ALL_SELECTOR);
80 }
81 }
82 (_, _) => {}
83 };
84 }
85 request
86 }
87}
88
89pub struct MoonbeamEthConfig<C, BE>(std::marker::PhantomData<(C, BE)>);
90
91impl<C, BE> fc_rpc::EthConfig<Block, C> for MoonbeamEthConfig<C, BE>
92where
93 C: sc_client_api::StorageProvider<Block, BE> + Sync + Send + 'static,
94 BE: Backend<Block> + 'static,
95{
96 type EstimateGasAdapter = MoonbeamEGA;
97 type RuntimeStorageOverride =
98 fc_rpc::frontier_backend_client::SystemAccountId20StorageOverride<Block, C, BE>;
99}
100
101pub struct FullDeps<C, P, BE> {
103 pub client: Arc<C>,
105 pub pool: Arc<P>,
107 pub graph: Arc<P>,
109 pub is_authority: bool,
111 pub network: Arc<dyn NetworkService>,
113 pub sync: Arc<SyncingService<Block>>,
115 pub filter_pool: Option<FilterPool>,
117 pub ethapi_cmd: Vec<EthApiCmd>,
119 pub frontier_backend: Arc<dyn fc_api::Backend<Block>>,
121 pub backend: Arc<BE>,
123 pub command_sink: Option<futures::channel::mpsc::Sender<EngineCommand<Hash>>>,
125 pub max_past_logs: u32,
127 pub max_block_range: u32,
129 pub fee_history_limit: u64,
131 pub fee_history_cache: FeeHistoryCache,
133 pub dev_rpc_data: Option<(
135 flume::Sender<Vec<u8>>,
136 flume::Sender<(ParaId, Vec<u8>)>,
137 Arc<std::sync::atomic::AtomicU32>,
138 )>,
139 pub overrides: Arc<dyn StorageOverride<Block>>,
141 pub block_data_cache: Arc<EthBlockDataCacheTask<Block>>,
143 pub forced_parent_hashes: Option<BTreeMap<H256, H256>>,
145}
146
147pub struct TracingConfig {
148 pub tracing_requesters: crate::rpc::tracing::RpcRequesters,
149 pub trace_filter_max_count: u32,
150}
151
152pub fn create_full<C, P, BE>(
154 deps: FullDeps<C, P, BE>,
155 subscription_task_executor: SubscriptionTaskExecutor,
156 maybe_tracing_config: Option<TracingConfig>,
157 pubsub_notification_sinks: Arc<
158 fc_mapping_sync::EthereumBlockNotificationSinks<
159 fc_mapping_sync::EthereumBlockNotification<Block>,
160 >,
161 >,
162 pending_consenus_data_provider: Box<dyn ConsensusDataProvider<Block>>,
163 para_id: ParaId,
164) -> Result<RpcModule<()>, Box<dyn std::error::Error + Send + Sync>>
165where
166 BE: Backend<Block> + 'static,
167 BE::State: StateBackend<BlakeTwo256>,
168 BE::Blockchain: BlockchainBackend<Block>,
169 C: ProvideRuntimeApi<Block> + StorageProvider<Block, BE> + AuxStore,
170 C: BlockchainEvents<Block>,
171 C: HeaderBackend<Block> + HeaderMetadata<Block, Error = BlockChainError> + 'static,
172 C: CallApiAt<Block>,
173 C: Send + Sync + 'static,
174 C::Api: RuntimeApiCollection,
175 P: TransactionPool<Block = Block, Hash = <Block as BlockT>::Hash> + 'static,
176{
177 use fc_rpc::{
178 Eth, EthApiServer, EthFilter, EthFilterApiServer, EthPubSub, EthPubSubApiServer, Net,
179 NetApiServer, TxPool, TxPoolApiServer, Web3, Web3ApiServer,
180 };
181 use moonbeam_dev_rpc::{DevApiServer, DevRpc};
182 use moonbeam_finality_rpc::{MoonbeamFinality, MoonbeamFinalityApiServer};
183 use moonbeam_rpc_debug::{Debug, DebugServer};
184 use moonbeam_rpc_trace::{Trace, TraceServer};
185 use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApiServer};
186 use substrate_frame_rpc_system::{System, SystemApiServer};
187
188 let mut io = RpcModule::new(());
189 let FullDeps {
190 client,
191 pool,
192 graph,
193 is_authority,
194 network,
195 sync,
196 filter_pool,
197 ethapi_cmd,
198 command_sink,
199 frontier_backend,
200 backend: _,
201 max_past_logs,
202 max_block_range,
203 fee_history_limit,
204 fee_history_cache,
205 dev_rpc_data,
206 overrides,
207 block_data_cache,
208 forced_parent_hashes,
209 } = deps;
210
211 io.merge(System::new(Arc::clone(&client), Arc::clone(&pool)).into_rpc())?;
212 io.merge(TransactionPayment::new(Arc::clone(&client)).into_rpc())?;
213
214 let signers = Vec::new();
216
217 enum Never {}
218 impl<T> fp_rpc::ConvertTransaction<T> for Never {
219 fn convert_transaction(&self, _transaction: pallet_ethereum::Transaction) -> T {
220 unreachable!()
224 }
225 }
226 let convert_transaction: Option<Never> = None;
227
228 let client_for_cidp = client.clone();
230
231 let pending_create_inherent_data_providers = move |block, _| {
232 let timestamp = sp_timestamp::InherentDataProvider::new(
234 Timestamp::current()
235 .saturating_add(RELAY_CHAIN_SLOT_DURATION_MILLIS.saturating_mul(100))
236 .into(),
237 );
238
239 let maybe_current_para_head = client_for_cidp.expect_header(block);
240 async move {
241 let current_para_block_head = Some(polkadot_primitives::HeadData(
242 maybe_current_para_head?.encode(),
243 ));
244
245 let builder = RelayStateSproofBuilder {
246 para_id,
247 current_slot: polkadot_primitives::Slot::from(
249 timestamp
250 .timestamp()
251 .as_millis()
252 .saturating_div(RELAY_CHAIN_SLOT_DURATION_MILLIS),
253 ),
254 included_para_head: current_para_block_head,
255 ..Default::default()
256 };
257
258 let (relay_parent_storage_root, relay_chain_state) =
262 builder.into_state_root_and_proof();
263
264 let vfp = PersistedValidationData {
265 relay_parent_number: u32::MAX,
268 relay_parent_storage_root,
269 ..Default::default()
270 };
271 let parachain_inherent_data = ParachainInherentData {
272 validation_data: vfp,
273 relay_chain_state,
274 downward_messages: Default::default(),
275 horizontal_messages: Default::default(),
276 relay_parent_descendants: Default::default(),
277 collator_peer_id: None,
278 };
279
280 Ok((timestamp, parachain_inherent_data))
281 }
282 };
283
284 io.merge(
285 Eth::<_, _, _, _, _, _, MoonbeamEthConfig<_, _>>::new(
286 Arc::clone(&client.clone()),
287 Arc::clone(&pool),
288 graph.clone(),
289 convert_transaction,
290 Arc::clone(&sync),
291 signers,
292 Arc::clone(&overrides),
293 Arc::clone(&frontier_backend),
294 is_authority,
295 Arc::clone(&block_data_cache),
296 fee_history_cache,
297 fee_history_limit,
298 10,
299 forced_parent_hashes,
300 pending_create_inherent_data_providers,
301 Some(pending_consenus_data_provider),
302 )
303 .replace_config::<MoonbeamEthConfig<C, BE>>()
304 .into_rpc(),
305 )?;
306
307 if let Some(filter_pool) = filter_pool {
308 io.merge(
309 EthFilter::new(
310 client.clone(),
311 frontier_backend.clone(),
312 graph.clone(),
313 filter_pool,
314 500_usize, max_past_logs,
316 max_block_range,
317 block_data_cache,
318 )
319 .into_rpc(),
320 )?;
321 }
322
323 io.merge(
324 Net::new(
325 Arc::clone(&client),
326 network.clone(),
327 true,
329 )
330 .into_rpc(),
331 )?;
332
333 io.merge(Web3::new(Arc::clone(&client)).into_rpc())?;
334 io.merge(
335 EthPubSub::new(
336 pool,
337 Arc::clone(&client),
338 sync.clone(),
339 subscription_task_executor,
340 overrides,
341 pubsub_notification_sinks.clone(),
342 )
343 .into_rpc(),
344 )?;
345
346 if ethapi_cmd.contains(&EthApiCmd::Txpool) {
347 io.merge(TxPool::new(Arc::clone(&client), graph).into_rpc())?;
348 }
349
350 io.merge(MoonbeamFinality::new(client.clone(), frontier_backend.clone()).into_rpc())?;
351
352 if let Some(command_sink) = command_sink {
353 io.merge(
354 ManualSeal::new(command_sink).into_rpc(),
357 )?;
358 };
359
360 if let Some((downward_message_channel, hrmp_message_channel, additional_relay_offset)) =
361 dev_rpc_data
362 {
363 io.merge(
364 DevRpc {
365 downward_message_channel,
366 hrmp_message_channel,
367 additional_relay_offset,
368 }
369 .into_rpc(),
370 )?;
371 }
372
373 if let Some(tracing_config) = maybe_tracing_config {
374 if let Some(trace_filter_requester) = tracing_config.tracing_requesters.trace {
375 io.merge(
376 Trace::new(
377 client,
378 trace_filter_requester,
379 tracing_config.trace_filter_max_count,
380 )
381 .into_rpc(),
382 )?;
383 }
384
385 if let Some(debug_requester) = tracing_config.tracing_requesters.debug {
386 io.merge(Debug::new(debug_requester).into_rpc())?;
387 }
388 }
389
390 Ok(io)
391}
392
393pub struct SpawnTasksParams<'a, B: BlockT, C, BE> {
394 pub task_manager: &'a TaskManager,
395 pub client: Arc<C>,
396 pub substrate_backend: Arc<BE>,
397 pub frontier_backend: Arc<fc_db::Backend<B, C>>,
398 pub filter_pool: Option<FilterPool>,
399 pub overrides: Arc<dyn StorageOverride<B>>,
400 pub fee_history_limit: u64,
401 pub fee_history_cache: FeeHistoryCache,
402}
403
404pub fn spawn_essential_tasks<B, C, BE>(
406 params: SpawnTasksParams<B, C, BE>,
407 sync: Arc<SyncingService<B>>,
408 pubsub_notification_sinks: Arc<
409 fc_mapping_sync::EthereumBlockNotificationSinks<
410 fc_mapping_sync::EthereumBlockNotification<B>,
411 >,
412 >,
413) where
414 C: ProvideRuntimeApi<B> + BlockOf,
415 C: HeaderBackend<B> + HeaderMetadata<B, Error = BlockChainError> + 'static,
416 C: BlockchainEvents<B> + StorageProvider<B, BE>,
417 C: Send + Sync + 'static,
418 C::Api: EthereumRuntimeRPCApi<B>,
419 C::Api: BlockBuilder<B>,
420 B: BlockT<Hash = H256> + Send + Sync + 'static,
421 B::Header: HeaderT<Number = u32>,
422 BE: Backend<B> + 'static,
423 BE::State: StateBackend<BlakeTwo256>,
424{
425 match *params.frontier_backend {
428 fc_db::Backend::KeyValue(ref b) => {
429 params.task_manager.spawn_essential_handle().spawn(
430 "frontier-mapping-sync-worker",
431 Some("frontier"),
432 MappingSyncWorker::new(
433 params.client.import_notification_stream(),
434 Duration::new(6, 0),
435 params.client.clone(),
436 params.substrate_backend.clone(),
437 params.overrides.clone(),
438 b.clone(),
439 3,
440 0,
441 SyncStrategy::Parachain,
442 sync.clone(),
443 pubsub_notification_sinks.clone(),
444 )
445 .for_each(|()| futures::future::ready(())),
446 );
447 }
448 fc_db::Backend::Sql(ref b) => {
449 params.task_manager.spawn_essential_handle().spawn_blocking(
450 "frontier-mapping-sync-worker",
451 Some("frontier"),
452 fc_mapping_sync::sql::SyncWorker::run(
453 params.client.clone(),
454 params.substrate_backend.clone(),
455 b.clone(),
456 params.client.import_notification_stream(),
457 fc_mapping_sync::sql::SyncWorkerConfig {
458 read_notification_timeout: Duration::from_secs(10),
459 check_indexed_blocks_interval: Duration::from_secs(60),
460 },
461 fc_mapping_sync::SyncStrategy::Parachain,
462 sync.clone(),
463 pubsub_notification_sinks.clone(),
464 ),
465 );
466 }
467 }
468
469 if let Some(filter_pool) = params.filter_pool {
472 const FILTER_RETAIN_THRESHOLD: u64 = 100;
474 params.task_manager.spawn_essential_handle().spawn(
475 "frontier-filter-pool",
476 Some("frontier"),
477 EthTask::filter_pool_task(
478 Arc::clone(¶ms.client),
479 filter_pool,
480 FILTER_RETAIN_THRESHOLD,
481 ),
482 );
483 }
484
485 params.task_manager.spawn_essential_handle().spawn(
487 "frontier-fee-history",
488 Some("frontier"),
489 EthTask::fee_history_task(
490 Arc::clone(¶ms.client),
491 Arc::clone(¶ms.overrides),
492 params.fee_history_cache,
493 params.fee_history_limit,
494 ),
495 );
496}