1use std::{
2 collections::BTreeMap,
3 path::PathBuf,
4 sync::{Arc, Mutex},
5 time::Duration,
6};
7
8use futures::{future, prelude::*};
9use sc_client_api::BlockchainEvents;
11use sc_executor::HostFunctions;
12use sc_network_sync::SyncingService;
13use sc_service::{error::Error as ServiceError, Configuration, TaskManager};
14use sp_api::ConstructRuntimeApi;
15use sp_core::H256;
16use sp_runtime::traits::Block as BlockT;
17pub use fc_consensus::FrontierBlockImport;
19use fc_rpc::EthTask;
20pub use fc_rpc_core::types::{FeeHistoryCache, FeeHistoryCacheLimit, FilterPool};
21pub use fc_storage::{StorageOverride, StorageOverrideHandler};
22
23use crate::client::{FullBackend, FullClient};
24
25pub type FrontierBackend<B, C> = fc_db::Backend<B, C>;
27
28pub fn db_config_dir(config: &Configuration) -> PathBuf {
29 config.base_path.config_dir(config.chain_spec.id())
30}
31
32#[derive(Debug, Copy, Clone, Default, clap::ValueEnum)]
34pub enum BackendType {
35 #[default]
37 KeyValue,
38 Sql,
40}
41
42#[derive(Clone, Debug, clap::Parser)]
44pub struct EthConfiguration {
45 #[arg(long, default_value = "10000")]
47 pub max_past_logs: u32,
48
49 #[arg(long, default_value = "2048")]
51 pub fee_history_limit: u64,
52
53 #[arg(long)]
54 pub enable_dev_signer: bool,
55
56 #[arg(long, default_value = "1")]
58 pub target_gas_price: u64,
59
60 #[arg(long, default_value = "10")]
63 pub execute_gas_limit_multiplier: u64,
64
65 #[arg(long, default_value = "50")]
67 pub eth_log_block_cache: usize,
68
69 #[arg(long, default_value = "50")]
71 pub eth_statuses_cache: usize,
72
73 #[arg(long, value_enum, ignore_case = true, default_value_t = BackendType::default())]
75 pub frontier_backend_type: BackendType,
76
77 #[arg(long, default_value = "100")]
79 pub frontier_sql_backend_pool_size: u32,
80
81 #[arg(long, default_value = "10000000")]
83 pub frontier_sql_backend_num_ops_timeout: u32,
84
85 #[arg(long, default_value = "4")]
87 pub frontier_sql_backend_thread_count: u32,
88
89 #[arg(long, default_value = "209715200")]
92 pub frontier_sql_backend_cache_size: u64,
93}
94
95pub struct FrontierPartialComponents {
96 pub filter_pool: Option<FilterPool>,
97 pub fee_history_cache: FeeHistoryCache,
98 pub fee_history_cache_limit: FeeHistoryCacheLimit,
99}
100
101pub fn new_frontier_partial(
102 config: &EthConfiguration,
103) -> Result<FrontierPartialComponents, ServiceError> {
104 Ok(FrontierPartialComponents {
105 filter_pool: Some(Arc::new(Mutex::new(BTreeMap::new()))),
106 fee_history_cache: Arc::new(Mutex::new(BTreeMap::new())),
107 fee_history_cache_limit: config.fee_history_limit,
108 })
109}
110
111pub trait EthCompatRuntimeApiCollection<Block: BlockT>:
113 sp_api::ApiExt<Block>
114 + fp_rpc::ConvertTransactionRuntimeApi<Block>
115 + fp_rpc::EthereumRuntimeRPCApi<Block>
116{
117}
118
119impl<Block, Api> EthCompatRuntimeApiCollection<Block> for Api
120where
121 Block: BlockT,
122 Api: sp_api::ApiExt<Block>
123 + fp_rpc::ConvertTransactionRuntimeApi<Block>
124 + fp_rpc::EthereumRuntimeRPCApi<Block>,
125{
126}
127
128pub async fn spawn_frontier_tasks<B, RA, HF>(
129 task_manager: &TaskManager,
130 client: Arc<FullClient<B, RA, HF>>,
131 backend: Arc<FullBackend<B>>,
132 frontier_backend: Arc<FrontierBackend<B, FullClient<B, RA, HF>>>,
133 filter_pool: Option<FilterPool>,
134 storage_override: Arc<dyn StorageOverride<B>>,
135 fee_history_cache: FeeHistoryCache,
136 fee_history_cache_limit: FeeHistoryCacheLimit,
137 sync: Arc<SyncingService<B>>,
138 pubsub_notification_sinks: Arc<
139 fc_mapping_sync::EthereumBlockNotificationSinks<
140 fc_mapping_sync::EthereumBlockNotification<B>,
141 >,
142 >,
143) where
144 B: BlockT<Hash = H256>,
145 RA: ConstructRuntimeApi<B, FullClient<B, RA, HF>>,
146 RA: Send + Sync + 'static,
147 RA::RuntimeApi: EthCompatRuntimeApiCollection<B>,
148 HF: HostFunctions + 'static,
149{
150 match &*frontier_backend {
152 fc_db::Backend::KeyValue(b) => {
153 task_manager.spawn_essential_handle().spawn(
154 "frontier-mapping-sync-worker",
155 Some("frontier"),
156 fc_mapping_sync::kv::MappingSyncWorker::new(
157 client.import_notification_stream(),
158 Duration::new(6, 0),
159 client.clone(),
160 backend,
161 storage_override.clone(),
162 b.clone(),
163 3,
164 0u32.into(),
165 fc_mapping_sync::SyncStrategy::Normal,
166 sync,
167 pubsub_notification_sinks,
168 )
169 .for_each(|()| future::ready(())),
170 );
171 }
172 fc_db::Backend::Sql(b) => {
173 task_manager.spawn_essential_handle().spawn_blocking(
174 "frontier-mapping-sync-worker",
175 Some("frontier"),
176 fc_mapping_sync::sql::SyncWorker::run(
177 client.clone(),
178 backend,
179 b.clone(),
180 client.import_notification_stream(),
181 fc_mapping_sync::sql::SyncWorkerConfig {
182 read_notification_timeout: Duration::from_secs(30),
183 check_indexed_blocks_interval: Duration::from_secs(60),
184 },
185 fc_mapping_sync::SyncStrategy::Parachain,
186 sync,
187 pubsub_notification_sinks,
188 ),
189 );
190 }
191 }
192
193 if let Some(filter_pool) = filter_pool {
195 const FILTER_RETAIN_THRESHOLD: u64 = 100;
197 task_manager.spawn_essential_handle().spawn(
198 "frontier-filter-pool",
199 Some("frontier"),
200 EthTask::filter_pool_task(client.clone(), filter_pool, FILTER_RETAIN_THRESHOLD),
201 );
202 }
203
204 task_manager.spawn_essential_handle().spawn(
206 "frontier-fee-history",
207 Some("frontier"),
208 EthTask::fee_history_task(
209 client,
210 storage_override,
211 fee_history_cache,
212 fee_history_cache_limit,
213 ),
214 );
215}