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