datahaven/operator/node/src/eth.rs
Steve Degosserie 5a7983f0d8
chore: ♻️ Add missing license header in operator & AVS contracts source code (#285)
Co-authored-by: Ahmad Kaouk <56095276+ahmadkaouk@users.noreply.github.com>
2025-11-10 12:56:41 +01:00

259 lines
8.7 KiB
Rust

// Copyright 2025 DataHaven
// This file is part of DataHaven.
// DataHaven is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// DataHaven is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with DataHaven. If not, see <http://www.gnu.org/licenses/>.
// Substrate
use crate::client::{FullBackend, FullClient};
use datahaven_runtime_common::Block;
pub use fc_db::Backend as FrontierBackend;
use fc_rpc::EthConfig;
use fc_rpc::EthTask;
pub use fc_rpc_core::types::{FeeHistoryCache, FeeHistoryCacheLimit, FilterPool};
pub use fc_storage::{StorageOverride, StorageOverrideHandler};
use fp_rpc::EthereumRuntimeRPCApi;
use futures::{future, prelude::*};
use sc_client_api::{Backend, BlockchainEvents, StorageProvider};
use sc_executor::HostFunctions;
use sc_network_sync::SyncingService;
use sc_service::{error::Error as ServiceError, TaskManager};
use sp_api::ConstructRuntimeApi;
use sp_core::H256;
use sp_runtime::traits::Block as BlockT;
use std::{
collections::BTreeMap,
sync::{Arc, Mutex},
time::Duration,
};
/// Frontier DB backend type.
pub struct DefaultEthConfig<C, BE>(std::marker::PhantomData<(C, BE)>);
impl<C, BE> EthConfig<Block, C> for DefaultEthConfig<C, BE>
where
C: StorageProvider<Block, BE> + Sync + Send + 'static,
BE: Backend<Block> + 'static,
{
type EstimateGasAdapter = ();
type RuntimeStorageOverride =
fc_rpc::frontier_backend_client::SystemAccountId20StorageOverride<Block, C, BE>;
}
/// Available frontier backend types.
#[derive(Debug, Copy, Clone, Default, clap::ValueEnum)]
pub enum BackendType {
/// Either RocksDb or ParityDb as per inherited from the global backend settings.
#[default]
KeyValue,
/// Sql database with custom log indexing.
Sql,
}
/// The ethereum-compatibility configuration used to run a node.
#[derive(Clone, Debug, clap::Parser)]
pub struct EthConfiguration {
/// Maximum number of logs in a query.
#[arg(long, default_value = "10000")]
pub max_past_logs: u32,
/// Maximum fee history cache size.
#[arg(long, default_value = "2048")]
pub fee_history_limit: u64,
#[arg(long)]
pub enable_dev_signer: bool,
/// The dynamic-fee pallet target gas price set by block author
#[arg(long, default_value = "1")]
pub target_gas_price: u64,
/// Maximum allowed gas limit will be `block.gas_limit * execute_gas_limit_multiplier`
/// when using eth_call/eth_estimateGas.
#[arg(long, default_value = "10")]
pub execute_gas_limit_multiplier: u64,
/// Size in bytes of the LRU cache for block data.
#[arg(long, default_value = "50")]
pub eth_log_block_cache: usize,
/// Size in bytes of the LRU cache for transactions statuses data.
#[arg(long, default_value = "50")]
pub eth_statuses_cache: usize,
/// Sets the frontier backend type (KeyValue or Sql)
#[arg(long, value_enum, ignore_case = true, default_value_t = BackendType::default())]
pub frontier_backend_type: BackendType,
// Sets the SQL backend's pool size.
#[arg(long, default_value = "100")]
pub frontier_sql_backend_pool_size: u32,
/// Sets the SQL backend's query timeout in number of VM ops.
#[arg(long, default_value = "10000000")]
pub frontier_sql_backend_num_ops_timeout: u32,
/// Sets the SQL backend's auxiliary thread limit.
#[arg(long, default_value = "4")]
pub frontier_sql_backend_thread_count: u32,
/// Sets the SQL backend's query timeout in number of VM ops.
/// Default value is 200MB.
#[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,
})
}
/// A set of APIs that ethereum-compatible runtimes must implement.
pub trait EthCompatRuntimeApiCollection<Block: BlockT>:
sp_api::ApiExt<Block> + fp_rpc::ConvertTransactionRuntimeApi<Block> + EthereumRuntimeRPCApi<Block>
{
}
impl<Block, Api> EthCompatRuntimeApiCollection<Block> for Api
where
Block: BlockT,
Api: sp_api::ApiExt<Block>
+ fp_rpc::ConvertTransactionRuntimeApi<Block>
+ EthereumRuntimeRPCApi<Block>,
{
}
pub struct FrontierTasksParams<B, RA, HF>
where
B: BlockT<Hash = H256>,
RA: ConstructRuntimeApi<B, FullClient<B, RA, HF>>,
RA: Send + Sync + 'static,
RA::RuntimeApi: EthCompatRuntimeApiCollection<B>,
HF: HostFunctions + 'static,
{
pub client: Arc<FullClient<B, RA, HF>>,
pub backend: Arc<FullBackend<B>>,
pub frontier_backend: Arc<FrontierBackend<B, FullClient<B, RA, HF>>>,
pub frontier_partial_components: FrontierPartialComponents,
pub storage_override: Arc<dyn StorageOverride<B>>,
pub sync: Arc<SyncingService<B>>,
pub pubsub_notification_sinks: Arc<
fc_mapping_sync::EthereumBlockNotificationSinks<
fc_mapping_sync::EthereumBlockNotification<B>,
>,
>,
}
pub async fn spawn_frontier_tasks<B, RA, HF>(
task_manager: &TaskManager,
params: FrontierTasksParams<B, RA, HF>,
) where
B: BlockT<Hash = H256>,
RA: ConstructRuntimeApi<B, FullClient<B, RA, HF>>,
RA: Send + Sync + 'static,
RA::RuntimeApi: EthCompatRuntimeApiCollection<B>,
HF: HostFunctions + 'static,
{
let FrontierTasksParams {
client,
backend,
frontier_backend,
frontier_partial_components,
storage_override,
sync,
pubsub_notification_sinks,
} = params;
let FrontierPartialComponents {
filter_pool,
fee_history_cache,
fee_history_cache_limit,
} = frontier_partial_components;
// Spawn main mapping sync worker background task.
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,
storage_override.clone(),
b.clone(),
3,
0u32.into(),
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,
b.clone(),
client.import_notification_stream(),
fc_mapping_sync::sql::SyncWorkerConfig {
read_notification_timeout: Duration::from_secs(30),
check_indexed_blocks_interval: Duration::from_secs(60),
},
fc_mapping_sync::SyncStrategy::Parachain,
sync,
pubsub_notification_sinks,
),
);
}
}
// Spawn Frontier EthFilterApi maintenance task.
if let Some(filter_pool) = filter_pool {
// Each filter is allowed to stay in the pool for 100 blocks.
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),
);
}
// Spawn Frontier FeeHistory cache maintenance task.
task_manager.spawn_essential_handle().spawn(
"frontier-fee-history",
Some("frontier"),
EthTask::fee_history_task(
client,
storage_override,
fee_history_cache,
fee_history_cache_limit,
),
);
}