1use crate::rpc::{EthDeps, create_eth_rpc};
2use crate::service::{
3 EthConfiguration, FrontierPartialComponents, new_frontier_partial, spawn_frontier_tasks,
4};
5use clap::Parser;
6use domain_runtime_primitives::{Balance, Nonce};
7use domain_service::FullClient;
8use domain_service::providers::{BlockImportProvider, DefaultProvider, RpcProvider};
9use domain_service::rpc::FullDeps;
10use fc_consensus::FrontierBlockImport;
11use fc_rpc::EthConfig;
12use fc_storage::StorageOverrideHandler;
13use fp_rpc::{ConvertTransaction, ConvertTransactionRuntimeApi, EthereumRuntimeRPCApi};
14use jsonrpsee::RpcModule;
15use parity_scale_codec::{Decode, Encode};
16use sc_client_api::{AuxStore, Backend, BlockBackend, BlockchainEvents, StorageProvider};
17use sc_rpc::SubscriptionTaskExecutor;
18use sc_rpc_server::SubscriptionIdProvider;
19use sc_service::BasePath;
20use sc_transaction_pool_api::TransactionPool;
21use serde::de::DeserializeOwned;
22use sp_api::{ApiExt, CallApiAt, ConstructRuntimeApi, Core, ProvideRuntimeApi};
23use sp_block_builder::BlockBuilder;
24use sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata};
25use sp_core::H256;
26use sp_core::traits::SpawnEssentialNamed;
27use sp_inherents::CreateInherentDataProviders;
28use sp_runtime::traits::Block as BlockT;
29use std::env;
30use std::error::Error;
31use std::fmt::{Debug, Display};
32use std::marker::PhantomData;
33use std::path::Path;
34use std::sync::Arc;
35use substrate_frame_rpc_system::AccountNonceApi;
36
37pub struct EthProvider<CT, EC> {
39 eth_config: EthConfiguration,
40 base_path: Option<BasePath>,
41 marker: PhantomData<(CT, EC)>,
42}
43
44impl<CT, EC> EthProvider<CT, EC> {
45 pub fn new(base_path: Option<&Path>, eth_cli: impl Iterator<Item = String>) -> Self {
46 let eth_config = EthConfiguration::parse_from(env::args().take(1).chain(eth_cli));
47 Self::with_configuration(base_path, eth_config)
48 }
49
50 pub fn with_configuration(base_path: Option<&Path>, eth_config: EthConfiguration) -> Self {
51 Self {
52 eth_config,
53 base_path: base_path.map(|base_path| BasePath::new(base_path.join("evm"))),
54 marker: Default::default(),
55 }
56 }
57}
58
59impl<Block, RuntimeApi, CT, EC> BlockImportProvider<Block, FullClient<Block, RuntimeApi>>
60 for EthProvider<CT, EC>
61where
62 Block: BlockT,
63 RuntimeApi: ConstructRuntimeApi<Block, FullClient<Block, RuntimeApi>> + Send + Sync + 'static,
64 RuntimeApi::RuntimeApi:
65 ApiExt<Block> + Core<Block> + BlockBuilder<Block> + EthereumRuntimeRPCApi<Block>,
66{
67 type BI = FrontierBlockImport<
68 Block,
69 Arc<FullClient<Block, RuntimeApi>>,
70 FullClient<Block, RuntimeApi>,
71 >;
72
73 fn block_import(&self, client: Arc<FullClient<Block, RuntimeApi>>) -> Self::BI {
74 FrontierBlockImport::new(client.clone(), client)
75 }
76}
77
78impl<Block, Client, BE, TxPool, AccountId, CT, EC, CIDP>
79 RpcProvider<Block, Client, TxPool, BE, AccountId, CIDP> for EthProvider<CT, EC>
80where
81 Block: BlockT<Hash = H256>,
82 BE: Backend<Block> + 'static,
83 Client: ProvideRuntimeApi<Block>
84 + BlockchainEvents<Block>
85 + StorageProvider<Block, BE>
86 + HeaderBackend<Block>
87 + CallApiAt<Block>
88 + HeaderMetadata<Block, Error = BlockChainError>
89 + BlockBackend<Block>
90 + AuxStore
91 + Send
92 + Sync
93 + 'static,
94 Client::Api: pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi<Block, Balance>
95 + EthereumRuntimeRPCApi<Block>
96 + AccountNonceApi<Block, AccountId, Nonce>
97 + ConvertTransactionRuntimeApi<Block>,
98 Client::Api: BlockBuilder<Block>,
99 Client::Api: EthereumRuntimeRPCApi<Block>,
100 CT: ConvertTransaction<Block::Extrinsic> + Clone + Default + Send + Sync + 'static,
101 EC: EthConfig<Block, Client>,
102 TxPool: TransactionPool<Block = Block, Hash = H256> + Sync + Send + 'static,
103 AccountId: DeserializeOwned + Encode + Debug + Decode + Display + Clone + Sync + Send + 'static,
104 CIDP: CreateInherentDataProviders<Block, ()> + Send + Clone + 'static,
105{
106 type Deps = EthDeps<Client, TxPool, CT, Block, BE, CIDP>;
107
108 fn deps(
109 &self,
110 full_deps: FullDeps<Block, Client, TxPool, BE, CIDP>,
111 ) -> Result<Self::Deps, sc_service::Error> {
112 let client = full_deps.client.clone();
113 let storage_override = Arc::new(StorageOverrideHandler::new(client.clone()));
114 let base_path = match &self.base_path {
115 None => BasePath::new_temp_dir()?,
116 Some(base_path) => BasePath::new(base_path.path()),
117 };
118
119 let frontier_backend = Arc::new(fc_db::kv::Backend::open(
120 client,
121 &full_deps.database_source,
122 base_path.path(),
123 )?);
124
125 let FrontierPartialComponents {
126 filter_pool,
127 fee_history_cache,
128 fee_history_cache_limit,
129 } = new_frontier_partial(self.eth_config.fee_history_limit)?;
130
131 Ok(EthDeps {
132 full_deps: full_deps.clone(),
133 converter: Some(CT::default()),
134 enable_dev_signer: self.eth_config.enable_dev_signer,
135 sync: full_deps.sync.clone(),
136 frontier_backend,
137 storage_override: storage_override.clone(),
138 block_data_cache: Arc::new(fc_rpc::EthBlockDataCacheTask::new(
139 full_deps.task_spawner.clone(),
140 storage_override,
141 self.eth_config.eth_log_block_cache,
142 self.eth_config.eth_statuses_cache,
143 full_deps.prometheus_registry,
144 )),
145 filter_pool,
146 max_past_logs: self.eth_config.max_past_logs,
147 fee_history_cache,
148 fee_history_cache_limit,
149 execute_gas_limit_multiplier: self.eth_config.execute_gas_limit_multiplier,
150 forced_parent_hashes: None,
151 pending_inherent_data_provider: full_deps.create_inherent_data_provider,
152 })
153 }
154
155 fn rpc_id(&self) -> Option<Box<dyn SubscriptionIdProvider>> {
156 Some(Box::new(fc_rpc::EthereumSubIdProvider))
157 }
158
159 fn rpc_builder<SE>(
160 &self,
161 deps: Self::Deps,
162 subscription_task_executor: SubscriptionTaskExecutor,
163 essential_task_spawner: SE,
164 ) -> Result<RpcModule<()>, Box<dyn Error + Send + Sync>>
165 where
166 SE: SpawnEssentialNamed + Clone,
167 {
168 let default_provider = DefaultProvider;
169 let io = default_provider.rpc_builder(
170 deps.full_deps.clone(),
171 subscription_task_executor.clone(),
172 essential_task_spawner.clone(),
173 )?;
174
175 let pubsub_notification_sinks: fc_mapping_sync::EthereumBlockNotificationSinks<
180 fc_mapping_sync::EthereumBlockNotification<Block>,
181 > = Default::default();
182 let pubsub_notification_sinks = Arc::new(pubsub_notification_sinks);
183
184 let io = create_eth_rpc::<Client, BE, TxPool, CT, Block, EC, CIDP>(
185 io,
186 deps.clone(),
187 subscription_task_executor,
188 pubsub_notification_sinks.clone(),
189 )?;
190
191 spawn_frontier_tasks(
193 essential_task_spawner,
194 deps.full_deps.client,
195 deps.full_deps.backend,
196 deps.frontier_backend,
197 deps.storage_override,
198 FrontierPartialComponents {
199 filter_pool: deps.filter_pool,
200 fee_history_cache: deps.fee_history_cache,
201 fee_history_cache_limit: deps.fee_history_cache_limit,
202 },
203 deps.sync,
204 pubsub_notification_sinks,
205 );
206 Ok(io)
207 }
208}