1use fc_rpc::{
22 Eth, EthApiServer, EthBlockDataCacheTask, EthFilter, EthFilterApiServer, EthPubSub,
23 EthPubSubApiServer, Net, NetApiServer, TxPool, TxPoolApiServer, Web3, Web3ApiServer,
24};
25use fc_rpc_core::types::{FeeHistoryCache, FilterPool};
26use fc_storage::{StorageOverride, StorageOverrideHandler};
27use jsonrpsee::RpcModule;
28use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApiServer};
29use std::path::Path;
30
31use cumulus_primitives_core::ParaId;
32use sc_client_api::{
33 AuxStore, Backend, BlockchainEvents, StateBackend, StorageProvider, UsageProvider,
34};
35use sc_consensus_manual_seal::rpc::ManualSealApiServer;
36use sc_network::service::traits::NetworkService;
37use sc_network_sync::SyncingService;
38use sc_rpc::dev::DevApiServer;
39pub use sc_rpc::SubscriptionTaskExecutor;
40use sc_transaction_pool_api::TransactionPool;
41use sp_api::{CallApiAt, ProvideRuntimeApi};
42use sp_block_builder::BlockBuilder;
43use sp_blockchain::{
44 Backend as BlockchainBackend, Error as BlockChainError, HeaderBackend, HeaderMetadata,
45};
46use sp_consensus_aura::{sr25519::AuthorityId as AuraId, AuraApi};
47use sp_inherents::CreateInherentDataProviders;
48use sp_runtime::traits::{BlakeTwo256, Block as BlockT};
49use std::sync::Arc;
50use substrate_frame_rpc_system::{System, SystemApiServer};
51
52use moonbeam_rpc_debug::{Debug, DebugServer};
53use moonbeam_rpc_trace::{Trace, TraceServer};
54
55use crate::evm_tracing_types::{FrontierBackendConfig, FrontierConfig};
56use astar_primitives::*;
57
58pub mod tracing;
59
60type HashFor<Block> = <Block as BlockT>::Hash;
61
62#[derive(Clone)]
63pub struct EvmTracingConfig {
64 pub tracing_requesters: tracing::RpcRequesters,
65 pub trace_filter_max_count: u32,
66 pub enable_txpool: bool,
67}
68
69#[derive(Debug, Copy, Clone, Default, clap::ValueEnum)]
71pub enum FrontierBackendType {
72 #[default]
74 KeyValue,
75 Sql,
77}
78
79pub fn open_frontier_backend<C, BE>(
82 client: Arc<C>,
83 config: &sc_service::Configuration,
84 rpc_config: &FrontierConfig,
85) -> Result<fc_db::Backend<Block, C>, String>
86where
87 C: ProvideRuntimeApi<Block> + StorageProvider<Block, BE> + AuxStore,
88 C: HeaderBackend<Block> + HeaderMetadata<Block, Error = BlockChainError>,
89 C: Send + Sync + 'static,
90 C::Api: fp_rpc::EthereumRuntimeRPCApi<Block>,
91 BE: Backend<Block> + 'static,
92 BE::State: StateBackend<BlakeTwo256>,
93{
94 let config_dir = config.base_path.config_dir(config.chain_spec.id());
95 let path = config_dir.join("frontier").join("db");
96
97 let frontier_backend = match rpc_config.frontier_backend_config {
98 FrontierBackendConfig::KeyValue => {
99 fc_db::Backend::KeyValue(Arc::new(fc_db::kv::Backend::<Block, C>::new(
100 client,
101 &fc_db::kv::DatabaseSettings {
102 source: fc_db::DatabaseSource::RocksDb {
103 path,
104 cache_size: 0,
105 },
106 },
107 )?))
108 }
109 FrontierBackendConfig::Sql {
110 pool_size,
111 num_ops_timeout,
112 thread_count,
113 cache_size,
114 } => {
115 let overrides = Arc::new(StorageOverrideHandler::new(client.clone()));
116 std::fs::create_dir_all(&path).expect("failed creating sql db directory");
117 let backend = futures::executor::block_on(fc_db::sql::Backend::new(
118 fc_db::sql::BackendConfig::Sqlite(fc_db::sql::SqliteBackendConfig {
119 path: Path::new("sqlite:///")
120 .join(path)
121 .join("frontier.db3")
122 .to_str()
123 .expect("frontier sql path error"),
124 create_if_missing: true,
125 thread_count: thread_count,
126 cache_size: cache_size,
127 }),
128 pool_size,
129 std::num::NonZeroU32::new(num_ops_timeout),
130 overrides.clone(),
131 ))
132 .unwrap_or_else(|err| panic!("failed creating sql backend: {:?}", err));
133 fc_db::Backend::Sql(Arc::new(backend))
134 }
135 };
136
137 Ok(frontier_backend)
138}
139
140pub struct AstarEthConfig<C, BE>(std::marker::PhantomData<(C, BE)>);
141
142impl<C, BE> fc_rpc::EthConfig<Block, C> for AstarEthConfig<C, BE>
143where
144 C: sc_client_api::StorageProvider<Block, BE> + Sync + Send + 'static,
145 BE: Backend<Block> + 'static,
146{
147 type EstimateGasAdapter = ();
150 type RuntimeStorageOverride =
152 fc_rpc::frontier_backend_client::SystemAccountId32StorageOverride<Block, C, BE>;
153}
154
155pub struct FullDeps<C, P> {
157 pub client: Arc<C>,
159 pub pool: Arc<P>,
161 pub graph: Arc<P>,
163 pub network: Arc<dyn NetworkService>,
165 pub sync: Arc<SyncingService<Block>>,
167 pub is_authority: bool,
169 pub frontier_backend: Arc<dyn fc_api::Backend<Block>>,
171 pub filter_pool: FilterPool,
173 pub fee_history_limit: u64,
175 pub fee_history_cache: FeeHistoryCache,
177 pub storage_override: Arc<dyn StorageOverride<Block>>,
179 pub block_data_cache: Arc<EthBlockDataCacheTask<Block>>,
181 pub enable_evm_rpc: bool,
183 pub command_sink:
185 Option<futures::channel::mpsc::Sender<sc_consensus_manual_seal::EngineCommand<Hash>>>,
186}
187
188pub fn create_full<C, P, BE>(
190 deps: FullDeps<C, P>,
191 subscription_task_executor: SubscriptionTaskExecutor,
192 pubsub_notification_sinks: Arc<
193 fc_mapping_sync::EthereumBlockNotificationSinks<
194 fc_mapping_sync::EthereumBlockNotification<Block>,
195 >,
196 >,
197 tracing_config: EvmTracingConfig,
198) -> Result<RpcModule<()>, Box<dyn std::error::Error + Send + Sync>>
199where
200 C: ProvideRuntimeApi<Block>
201 + HeaderBackend<Block>
202 + UsageProvider<Block>
203 + CallApiAt<Block>
204 + AuxStore
205 + StorageProvider<Block, BE>
206 + HeaderMetadata<Block, Error = BlockChainError>
207 + BlockchainEvents<Block>
208 + Send
209 + Sync
210 + 'static,
211 C: sc_client_api::BlockBackend<Block>,
212 C::Api: substrate_frame_rpc_system::AccountNonceApi<Block, AccountId, Nonce>
213 + pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi<Block, Balance>
214 + fp_rpc::ConvertTransactionRuntimeApi<Block>
215 + fp_rpc::EthereumRuntimeRPCApi<Block>
216 + BlockBuilder<Block>
217 + AuraApi<Block, AuraId>
218 + moonbeam_rpc_primitives_debug::DebugRuntimeApi<Block>
219 + moonbeam_rpc_primitives_txpool::TxPoolRuntimeApi<Block>,
220 P: TransactionPool<Block = Block, Hash = HashFor<Block>> + Sync + Send + 'static,
221 BE: Backend<Block> + 'static,
222 BE::State: StateBackend<BlakeTwo256>,
223 BE::Blockchain: BlockchainBackend<Block>,
224{
225 let client = Arc::clone(&deps.client);
226 let graph = Arc::clone(&deps.graph);
227
228 let mut io = create_full_rpc(deps, subscription_task_executor, pubsub_notification_sinks)?;
229
230 if tracing_config.enable_txpool {
231 io.merge(TxPool::new(Arc::clone(&client), graph).into_rpc())?;
232 }
233
234 if let Some(trace_filter_requester) = tracing_config.tracing_requesters.trace {
235 io.merge(
236 Trace::new(
237 client,
238 trace_filter_requester,
239 tracing_config.trace_filter_max_count,
240 )
241 .into_rpc(),
242 )?;
243 }
244
245 if let Some(debug_requester) = tracing_config.tracing_requesters.debug {
246 io.merge(Debug::new(debug_requester).into_rpc())?;
247 }
248
249 Ok(io)
250}
251
252pub fn create_full_local_dev<C, P, BE>(
257 deps: FullDeps<C, P>,
258 subscription_task_executor: SubscriptionTaskExecutor,
259 pubsub_notification_sinks: Arc<
260 fc_mapping_sync::EthereumBlockNotificationSinks<
261 fc_mapping_sync::EthereumBlockNotification<Block>,
262 >,
263 >,
264 local_para_id: ParaId,
265 tracing_config: EvmTracingConfig,
266) -> Result<RpcModule<()>, Box<dyn std::error::Error + Send + Sync>>
267where
268 C: ProvideRuntimeApi<Block>
269 + HeaderBackend<Block>
270 + UsageProvider<Block>
271 + CallApiAt<Block>
272 + AuxStore
273 + StorageProvider<Block, BE>
274 + HeaderMetadata<Block, Error = BlockChainError>
275 + BlockchainEvents<Block>
276 + Send
277 + Sync
278 + 'static,
279 C: sc_client_api::BlockBackend<Block>,
280 C::Api: substrate_frame_rpc_system::AccountNonceApi<Block, AccountId, Nonce>
281 + pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi<Block, Balance>
282 + fp_rpc::ConvertTransactionRuntimeApi<Block>
283 + fp_rpc::EthereumRuntimeRPCApi<Block>
284 + BlockBuilder<Block>
285 + AuraApi<Block, AuraId>
286 + moonbeam_rpc_primitives_debug::DebugRuntimeApi<Block>
287 + moonbeam_rpc_primitives_txpool::TxPoolRuntimeApi<Block>,
288 P: TransactionPool<Block = Block, Hash = HashFor<Block>> + Sync + Send + 'static,
289 BE: Backend<Block> + 'static,
290 BE::State: StateBackend<BlakeTwo256>,
291 BE::Blockchain: BlockchainBackend<Block>,
292{
293 let client = Arc::clone(&deps.client);
294 let graph = Arc::clone(&deps.graph);
295
296 let mut io = create_full_rpc_local_dev(
297 deps,
298 subscription_task_executor,
299 pubsub_notification_sinks,
300 local_para_id,
301 )?;
302
303 if tracing_config.enable_txpool {
304 io.merge(TxPool::new(Arc::clone(&client), graph).into_rpc())?;
305 }
306
307 if let Some(trace_filter_requester) = tracing_config.tracing_requesters.trace {
308 io.merge(
309 Trace::new(
310 client,
311 trace_filter_requester,
312 tracing_config.trace_filter_max_count,
313 )
314 .into_rpc(),
315 )?;
316 }
317
318 if let Some(debug_requester) = tracing_config.tracing_requesters.debug {
319 io.merge(Debug::new(debug_requester).into_rpc())?;
320 }
321
322 Ok(io)
323}
324
325fn create_full_rpc_local_dev<C, P, BE>(
326 deps: FullDeps<C, P>,
327 subscription_task_executor: SubscriptionTaskExecutor,
328 pubsub_notification_sinks: Arc<
329 fc_mapping_sync::EthereumBlockNotificationSinks<
330 fc_mapping_sync::EthereumBlockNotification<Block>,
331 >,
332 >,
333 local_para_id: ParaId,
334) -> Result<RpcModule<()>, Box<dyn std::error::Error + Send + Sync>>
335where
336 C: ProvideRuntimeApi<Block>
337 + UsageProvider<Block>
338 + HeaderBackend<Block>
339 + CallApiAt<Block>
340 + AuxStore
341 + StorageProvider<Block, BE>
342 + HeaderMetadata<Block, Error = BlockChainError>
343 + BlockchainEvents<Block>
344 + Send
345 + Sync
346 + 'static,
347 C: sc_client_api::BlockBackend<Block>,
348 C::Api: substrate_frame_rpc_system::AccountNonceApi<Block, AccountId, Nonce>
349 + pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi<Block, Balance>
350 + fp_rpc::ConvertTransactionRuntimeApi<Block>
351 + fp_rpc::EthereumRuntimeRPCApi<Block>
352 + BlockBuilder<Block>
353 + AuraApi<Block, AuraId>,
354 P: TransactionPool<Block = Block, Hash = HashFor<Block>> + Sync + Send + 'static,
355 BE: Backend<Block> + 'static,
356 BE::State: StateBackend<BlakeTwo256>,
357 BE::Blockchain: BlockchainBackend<Block>,
358{
359 create_full_rpc_with_pending_provider(
360 deps,
361 subscription_task_executor,
362 pubsub_notification_sinks,
363 |client| crate::local::LocalPendingInherentDataProvider::new(client, local_para_id),
364 )
365}
366
367fn create_full_rpc<C, P, BE>(
368 deps: FullDeps<C, P>,
369 subscription_task_executor: SubscriptionTaskExecutor,
370 pubsub_notification_sinks: Arc<
371 fc_mapping_sync::EthereumBlockNotificationSinks<
372 fc_mapping_sync::EthereumBlockNotification<Block>,
373 >,
374 >,
375) -> Result<RpcModule<()>, Box<dyn std::error::Error + Send + Sync>>
376where
377 C: ProvideRuntimeApi<Block>
378 + UsageProvider<Block>
379 + HeaderBackend<Block>
380 + CallApiAt<Block>
381 + AuxStore
382 + StorageProvider<Block, BE>
383 + HeaderMetadata<Block, Error = BlockChainError>
384 + BlockchainEvents<Block>
385 + Send
386 + Sync
387 + 'static,
388 C: sc_client_api::BlockBackend<Block>,
389 C::Api: substrate_frame_rpc_system::AccountNonceApi<Block, AccountId, Nonce>
390 + pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi<Block, Balance>
391 + fp_rpc::ConvertTransactionRuntimeApi<Block>
392 + fp_rpc::EthereumRuntimeRPCApi<Block>
393 + BlockBuilder<Block>
394 + AuraApi<Block, AuraId>,
395 P: TransactionPool<Block = Block, Hash = HashFor<Block>> + Sync + Send + 'static,
396 BE: Backend<Block> + 'static,
397 BE::State: StateBackend<BlakeTwo256>,
398 BE::Blockchain: BlockchainBackend<Block>,
399{
400 create_full_rpc_with_pending_provider(
401 deps,
402 subscription_task_executor,
403 pubsub_notification_sinks,
404 crate::parachain::PendingCrateInherentDataProvider::new,
405 )
406}
407
408fn create_full_rpc_with_pending_provider<C, P, BE, CIDP, F>(
409 deps: FullDeps<C, P>,
410 subscription_task_executor: SubscriptionTaskExecutor,
411 pubsub_notification_sinks: Arc<
412 fc_mapping_sync::EthereumBlockNotificationSinks<
413 fc_mapping_sync::EthereumBlockNotification<Block>,
414 >,
415 >,
416 make_pending_inherent_data_provider: F,
417) -> Result<RpcModule<()>, Box<dyn std::error::Error + Send + Sync>>
418where
419 C: ProvideRuntimeApi<Block>
420 + UsageProvider<Block>
421 + HeaderBackend<Block>
422 + CallApiAt<Block>
423 + AuxStore
424 + StorageProvider<Block, BE>
425 + HeaderMetadata<Block, Error = BlockChainError>
426 + BlockchainEvents<Block>
427 + Send
428 + Sync
429 + 'static,
430 C: sc_client_api::BlockBackend<Block>,
431 C::Api: substrate_frame_rpc_system::AccountNonceApi<Block, AccountId, Nonce>
432 + pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi<Block, Balance>
433 + fp_rpc::ConvertTransactionRuntimeApi<Block>
434 + fp_rpc::EthereumRuntimeRPCApi<Block>
435 + BlockBuilder<Block>
436 + AuraApi<Block, AuraId>,
437 P: TransactionPool<Block = Block, Hash = HashFor<Block>> + Sync + Send + 'static,
438 BE: Backend<Block> + 'static,
439 BE::State: StateBackend<BlakeTwo256>,
440 BE::Blockchain: BlockchainBackend<Block>,
441 CIDP: CreateInherentDataProviders<Block, ()> + Send + Sync + 'static,
442 F: FnOnce(Arc<C>) -> CIDP,
443{
444 let mut io = RpcModule::new(());
445 let FullDeps {
446 client,
447 pool,
448 graph,
449 network,
450 sync,
451 is_authority,
452 frontier_backend,
453 filter_pool,
454 fee_history_limit,
455 fee_history_cache,
456 storage_override,
457 block_data_cache,
458 enable_evm_rpc,
459 command_sink,
460 } = deps;
461
462 io.merge(System::new(client.clone(), pool.clone()).into_rpc())?;
463 io.merge(TransactionPayment::new(client.clone()).into_rpc())?;
464 io.merge(sc_rpc::dev::Dev::new(client.clone()).into_rpc())?;
465
466 if let Some(command_sink) = command_sink {
467 io.merge(sc_consensus_manual_seal::rpc::ManualSeal::new(command_sink).into_rpc())?;
468 }
469
470 if !enable_evm_rpc {
471 return Ok(io);
472 }
473
474 let no_tx_converter: Option<fp_rpc::NoTransactionConverter> = None;
475
476 io.merge(
477 Eth::<_, _, _, _, _, _, ()>::new(
478 client.clone(),
479 pool.clone(),
480 graph.clone(),
481 no_tx_converter,
482 sync.clone(),
483 Default::default(),
484 storage_override.clone(),
485 frontier_backend.clone(),
486 is_authority,
487 block_data_cache.clone(),
488 fee_history_cache,
489 fee_history_limit,
490 10,
492 None,
493 make_pending_inherent_data_provider(client.clone()),
494 Some(Box::new(
495 crate::parachain::AuraConsensusDataProviderFallback::new(client.clone()),
496 )),
497 )
498 .replace_config::<AstarEthConfig<C, BE>>()
499 .into_rpc(),
500 )?;
501
502 let max_past_logs: u32 = 10_000;
503 let max_block_range: u32 = 1024;
504 let max_stored_filters: usize = 500;
505 io.merge(
506 EthFilter::new(
507 client.clone(),
508 frontier_backend,
509 graph.clone(),
510 filter_pool,
511 max_stored_filters,
512 max_past_logs,
513 max_block_range,
514 block_data_cache,
515 )
516 .into_rpc(),
517 )?;
518
519 io.merge(Net::new(client.clone(), network.clone(), true).into_rpc())?;
520
521 io.merge(Web3::new(client.clone()).into_rpc())?;
522
523 io.merge(
524 EthPubSub::new(
525 pool,
526 client.clone(),
527 sync,
528 subscription_task_executor,
529 storage_override,
530 pubsub_notification_sinks,
531 )
532 .into_rpc(),
533 )?;
534
535 Ok(io)
536}