use std::{
collections::BTreeMap,
path::PathBuf,
sync::{Arc, Mutex},
time::Duration,
};
use futures::{future, prelude::*};
use sc_client_api::BlockchainEvents;
use sc_executor::NativeExecutionDispatch;
use sc_network_sync::SyncingService;
use sc_service::{error::Error as ServiceError, Configuration, TaskManager};
use sp_api::ConstructRuntimeApi;
pub use fc_consensus::FrontierBlockImport;
use fc_rpc::{EthTask, OverrideHandle};
pub use fc_rpc_core::types::{FeeHistoryCache, FeeHistoryCacheLimit, FilterPool};
use frontier_template_runtime::opaque::Block;
use crate::client::{FullBackend, FullClient};
pub type FrontierBackend = fc_db::Backend<Block>;
pub fn db_config_dir(config: &Configuration) -> PathBuf {
config.base_path.config_dir(config.chain_spec.id())
}
#[derive(Debug, Copy, Clone, Default, clap::ValueEnum)]
pub enum BackendType {
#[default]
KeyValue,
Sql,
}
#[derive(Clone, Debug, clap::Parser)]
pub struct EthConfiguration {
#[arg(long, default_value = "10000")]
pub max_past_logs: u32,
#[arg(long, default_value = "2048")]
pub fee_history_limit: u64,
#[arg(long)]
pub enable_dev_signer: bool,
#[arg(long, default_value = "1")]
pub target_gas_price: u64,
#[arg(long, default_value = "10")]
pub execute_gas_limit_multiplier: u64,
#[arg(long, default_value = "50")]
pub eth_log_block_cache: usize,
#[arg(long, default_value = "50")]
pub eth_statuses_cache: usize,
#[arg(long, value_enum, ignore_case = true, default_value_t = BackendType::default())]
pub frontier_backend_type: BackendType,
#[arg(long, default_value = "100")]
pub frontier_sql_backend_pool_size: u32,
#[arg(long, default_value = "10000000")]
pub frontier_sql_backend_num_ops_timeout: u32,
#[arg(long, default_value = "4")]
pub frontier_sql_backend_thread_count: u32,
#[arg(long, default_value = "209715200")]
pub frontier_sql_backend_cache_size: u64,
}
pub struct FrontierPartialComponents {
pub filter_pool: Option<FilterPool>,
pub fee_history_cache: FeeHistoryCache,
pub fee_history_cache_limit: FeeHistoryCacheLimit,
}
pub fn new_frontier_partial(
config: &EthConfiguration,
) -> Result<FrontierPartialComponents, ServiceError> {
Ok(FrontierPartialComponents {
filter_pool: Some(Arc::new(Mutex::new(BTreeMap::new()))),
fee_history_cache: Arc::new(Mutex::new(BTreeMap::new())),
fee_history_cache_limit: config.fee_history_limit,
})
}
pub trait EthCompatRuntimeApiCollection:
sp_api::ApiExt<Block>
+ fp_rpc::ConvertTransactionRuntimeApi<Block>
+ fp_rpc::EthereumRuntimeRPCApi<Block>
{
}
impl<Api> EthCompatRuntimeApiCollection for Api where
Api: sp_api::ApiExt<Block>
+ fp_rpc::ConvertTransactionRuntimeApi<Block>
+ fp_rpc::EthereumRuntimeRPCApi<Block>
{
}
pub async fn spawn_frontier_tasks<RuntimeApi, Executor>(
task_manager: &TaskManager,
client: Arc<FullClient<RuntimeApi, Executor>>,
backend: Arc<FullBackend>,
frontier_backend: FrontierBackend,
filter_pool: Option<FilterPool>,
overrides: Arc<OverrideHandle<Block>>,
fee_history_cache: FeeHistoryCache,
fee_history_cache_limit: FeeHistoryCacheLimit,
sync: Arc<SyncingService<Block>>,
pubsub_notification_sinks: Arc<
fc_mapping_sync::EthereumBlockNotificationSinks<
fc_mapping_sync::EthereumBlockNotification<Block>,
>,
>,
) where
RuntimeApi: ConstructRuntimeApi<Block, FullClient<RuntimeApi, Executor>>,
RuntimeApi: Send + Sync + 'static,
RuntimeApi::RuntimeApi: EthCompatRuntimeApiCollection,
Executor: NativeExecutionDispatch + 'static,
{
match frontier_backend {
fc_db::Backend::KeyValue(b) => {
task_manager.spawn_essential_handle().spawn(
"frontier-mapping-sync-worker",
Some("frontier"),
fc_mapping_sync::kv::MappingSyncWorker::new(
client.import_notification_stream(),
Duration::new(6, 0),
client.clone(),
backend,
overrides.clone(),
Arc::new(b),
3,
0,
fc_mapping_sync::SyncStrategy::Normal,
sync,
pubsub_notification_sinks,
)
.for_each(|()| future::ready(())),
);
}
fc_db::Backend::Sql(b) => {
task_manager.spawn_essential_handle().spawn_blocking(
"frontier-mapping-sync-worker",
Some("frontier"),
fc_mapping_sync::sql::SyncWorker::run(
client.clone(),
backend,
Arc::new(b),
client.import_notification_stream(),
fc_mapping_sync::sql::SyncWorkerConfig {
read_notification_timeout: Duration::from_secs(10),
check_indexed_blocks_interval: Duration::from_secs(60),
},
fc_mapping_sync::SyncStrategy::Parachain,
sync,
pubsub_notification_sinks,
),
);
}
}
if let Some(filter_pool) = filter_pool {
const FILTER_RETAIN_THRESHOLD: u64 = 100;
task_manager.spawn_essential_handle().spawn(
"frontier-filter-pool",
Some("frontier"),
EthTask::filter_pool_task(client.clone(), filter_pool, FILTER_RETAIN_THRESHOLD),
);
}
task_manager.spawn_essential_handle().spawn(
"frontier-fee-history",
Some("frontier"),
EthTask::fee_history_task(
client,
overrides,
fee_history_cache,
fee_history_cache_limit,
),
);
}