git.delta.rocks / unique-network / refs/commits / ec57cb9db90d

difftreelog

refactor ethereum RPC/tasks initialization

Yaroslav Bolyukin2023-06-16parent: #f28d992.patch.diff
in: master

7 files changed

modifiedCargo.lockdiffbeforeafterboth
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -6507,11 +6507,13 @@
  "frame-benchmarking",
  "frame-support",
  "frame-system",
+ "hex-literal",
  "parity-scale-codec",
  "scale-info",
  "smallvec",
  "sp-arithmetic",
  "sp-core",
+ "sp-io",
  "sp-std",
  "xcm",
 ]
@@ -13841,9 +13843,11 @@
  "fc-rpc",
  "fc-rpc-core",
  "fp-rpc",
+ "fp-storage",
  "frame-benchmarking",
  "frame-benchmarking-cli",
  "futures",
+ "jsonrpsee",
  "log",
  "opal-runtime",
  "pallet-transaction-payment-rpc-runtime-api",
@@ -13861,6 +13865,7 @@
  "sc-executor",
  "sc-network",
  "sc-network-sync",
+ "sc-rpc",
  "sc-service",
  "sc-sysinfo",
  "sc-telemetry",
@@ -13906,9 +13911,9 @@
  "fp-rpc",
  "fp-storage",
  "jsonrpsee",
+ "pallet-ethereum",
  "pallet-transaction-payment-rpc",
  "sc-client-api",
- "sc-consensus-grandpa",
  "sc-network",
  "sc-network-sync",
  "sc-rpc",
modifiedCargo.tomldiffbeforeafterboth
125sc-cli = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.43" }125sc-cli = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.43" }
126sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.43" }126sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.43" }
127sc-consensus = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.43" }127sc-consensus = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.43" }
128sc-consensus-grandpa = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.43" }
129sc-consensus-manual-seal = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.43" }128sc-consensus-manual-seal = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.43" }
130sc-executor = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.43" }129sc-executor = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.43" }
131sc-network = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.43" }130sc-network = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.43" }
modifiednode/cli/Cargo.tomldiffbeforeafterboth
--- a/node/cli/Cargo.toml
+++ b/node/cli/Cargo.toml
@@ -21,7 +21,7 @@
 
 [dependencies]
 clap = "4.1"
-futures = '0.3.17'
+futures = '0.3.28'
 tokio = { version = "1.24", features = ["time"] }
 serde_json = "1.0"
 
@@ -94,6 +94,9 @@
 unique-rpc = { workspace = true }
 up-pov-estimate-rpc = { workspace = true }
 up-rpc = { workspace = true }
+jsonrpsee.workspace = true
+fp-storage.workspace = true
+sc-rpc.workspace = true
 
 [build-dependencies]
 substrate-build-script-utils = { workspace = true }
modifiednode/cli/src/chain_spec.rsdiffbeforeafterboth
--- a/node/cli/src/chain_spec.rs
+++ b/node/cli/src/chain_spec.rs
@@ -168,6 +168,7 @@
 					.collect(),
 			},
 			common: Default::default(),
+			configuration: Default::default(),
 			nonfungible: Default::default(),
 			treasury: Default::default(),
 			tokens: TokensConfig { balances: vec![] },
@@ -228,6 +229,7 @@
 					.to_vec(),
 			},
 			common: Default::default(),
+			configuration: Default::default(),
 			nonfungible: Default::default(),
 			balances: BalancesConfig {
 				balances: $endowed_accounts
modifiednode/cli/src/service.rsdiffbeforeafterboth
--- a/node/cli/src/service.rs
+++ b/node/cli/src/service.rs
@@ -20,16 +20,19 @@
 use std::collections::BTreeMap;
 use std::time::Duration;
 use std::pin::Pin;
+use fc_mapping_sync::EthereumBlockNotificationSinks;
+use fc_rpc::EthBlockDataCacheTask;
+use fc_rpc::EthTask;
 use fc_rpc_core::types::FeeHistoryCache;
 use futures::{
 	Stream, StreamExt,
 	stream::select,
 	task::{Context, Poll},
 };
+use sc_rpc::SubscriptionTaskExecutor;
 use sp_keystore::KeystorePtr;
 use tokio::time::Interval;
-
-use unique_rpc::overrides_handle;
+use jsonrpsee::RpcModule;
 
 use serde::{Serialize, Deserialize};
 
@@ -49,7 +52,7 @@
 use cumulus_relay_chain_minimal_node::build_minimal_relay_chain_node;
 
 // Substrate Imports
-use sp_api::BlockT;
+use sp_api::{BlockT, HeaderT, ProvideRuntimeApi, StateBackend};
 use sc_executor::NativeElseWasmExecutor;
 use sc_executor::NativeExecutionDispatch;
 use sc_network::NetworkBlock;
@@ -58,14 +61,23 @@
 use sc_telemetry::{Telemetry, TelemetryHandle, TelemetryWorker, TelemetryWorkerHandle};
 use sp_runtime::traits::BlakeTwo256;
 use substrate_prometheus_endpoint::Registry;
-use sc_client_api::BlockchainEvents;
+use sc_client_api::{BlockchainEvents, BlockOf, Backend, AuxStore, StorageProvider};
+use sp_blockchain::{HeaderBackend, HeaderMetadata, Error as BlockChainError};
 use sc_consensus::ImportQueue;
+use sp_core::H256;
+use sp_block_builder::BlockBuilder;
 
 use polkadot_service::CollatorPair;
 
 // Frontier Imports
 use fc_rpc_core::types::FilterPool;
 use fc_mapping_sync::{kv::MappingSyncWorker, SyncStrategy};
+use fc_rpc::{
+	StorageOverride, OverrideHandle, SchemaV1Override, SchemaV2Override, SchemaV3Override,
+	RuntimeApiStorageOverride,
+};
+use fp_rpc::EthereumRuntimeRPCApi;
+use fp_storage::EthereumStorageSchema;
 
 use up_common::types::opaque::*;
 
@@ -173,7 +185,7 @@
 	}
 }
 
-pub fn open_frontier_backend<Block: BlockT, C: sp_blockchain::HeaderBackend<Block>>(
+pub fn open_frontier_backend<Block: BlockT, C: HeaderBackend<Block>>(
 	client: Arc<C>,
 	config: &Configuration,
 ) -> Result<Arc<fc_db::kv::Backend<Block>>, String> {
@@ -213,13 +225,7 @@
 		FullSelectChain,
 		sc_consensus::DefaultImportQueue<Block, FullClient<RuntimeApi, ExecutorDispatch>>,
 		sc_transaction_pool::FullPool<Block, FullClient<RuntimeApi, ExecutorDispatch>>,
-		(
-			Option<Telemetry>,
-			Option<FilterPool>,
-			Arc<fc_db::kv::Backend<Block>>,
-			Option<TelemetryWorkerHandle>,
-			FeeHistoryCache,
-		),
+		OtherPartial,
 	>,
 	sc_service::Error,
 >
@@ -242,17 +248,6 @@
 		sc_service::Error,
 	>,
 {
-	let _telemetry = config
-		.telemetry_endpoints
-		.clone()
-		.filter(|x| !x.is_empty())
-		.map(|endpoints| -> Result<_, sc_telemetry::Error> {
-			let worker = TelemetryWorker::new(16)?;
-			let telemetry = worker.handle().new_telemetry(endpoints);
-			Ok((worker, telemetry))
-		})
-		.transpose()?;
-
 	let telemetry = config
 		.telemetry_endpoints
 		.clone()
@@ -293,9 +288,9 @@
 		client.clone(),
 	);
 
-	let filter_pool: Option<FilterPool> = Some(Arc::new(Mutex::new(BTreeMap::new())));
+	let eth_filter_pool: Option<FilterPool> = Some(Arc::new(Mutex::new(BTreeMap::new())));
 
-	let frontier_backend = open_frontier_backend(client.clone(), config)?;
+	let eth_backend = open_frontier_backend(client.clone(), config)?;
 
 	let import_queue = build_import_queue(
 		client.clone(),
@@ -304,7 +299,6 @@
 		telemetry.as_ref().map(|telemetry| telemetry.handle()),
 		&task_manager,
 	)?;
-	let fee_history_cache: FeeHistoryCache = Arc::new(Mutex::new(BTreeMap::new()));
 
 	let params = PartialComponents {
 		backend,
@@ -314,13 +308,12 @@
 		task_manager,
 		transaction_pool,
 		select_chain,
-		other: (
+		other: OtherPartial {
 			telemetry,
-			filter_pool,
-			frontier_backend,
+			eth_filter_pool,
+			eth_backend,
 			telemetry_worker_handle,
-			fee_history_cache,
-		),
+		},
 	};
 
 	Ok(params)
@@ -427,8 +420,12 @@
 
 	let params =
 		new_partial::<RuntimeApi, ExecutorDispatch, BIQ>(&parachain_config, build_import_queue)?;
-	let (mut telemetry, filter_pool, frontier_backend, telemetry_worker_handle, fee_history_cache) =
-		params.other;
+	let OtherPartial {
+		mut telemetry,
+		telemetry_worker_handle,
+		eth_filter_pool,
+		eth_backend,
+	} = params.other;
 	let net_config = sc_network::config::FullNetworkConfiguration::new(&parachain_config.network);
 
 	let client = params.client.clone();
@@ -470,69 +467,72 @@
 
 	let select_chain = params.select_chain.clone();
 
-	let block_data_cache = Arc::new(fc_rpc::EthBlockDataCacheTask::new(
-		task_manager.spawn_handle(),
-		overrides_handle::<_, _, Runtime>(client.clone()),
-		50,
-		50,
-		prometheus_registry.clone(),
-	));
+	let runtime_id = parachain_config.chain_spec.runtime_id();
 
-	let pubsub_notification_sinks: fc_mapping_sync::EthereumBlockNotificationSinks<
-		fc_mapping_sync::EthereumBlockNotification<Block>,
+	// Frontier
+	let fee_history_cache: FeeHistoryCache = Arc::new(Mutex::new(BTreeMap::new()));
+	let fee_history_limit = 2048;
+
+	let eth_pubsub_notification_sinks: Arc<
+		EthereumBlockNotificationSinks<fc_mapping_sync::EthereumBlockNotification<Block>>,
 	> = Default::default();
-	let pubsub_notification_sinks = Arc::new(pubsub_notification_sinks);
 
-	task_manager.spawn_essential_handle().spawn(
-		"frontier-mapping-sync-worker",
-		Some("frontier"),
-		MappingSyncWorker::new(
-			client.import_notification_stream(),
-			Duration::new(6, 0),
-			client.clone(),
-			backend.clone(),
-			overrides_handle::<_, _, Runtime>(client.clone()),
-			frontier_backend.clone(),
-			3,
-			0,
-			SyncStrategy::Parachain,
-			sync_service.clone(),
-			pubsub_notification_sinks.clone(),
-		)
-		.for_each(|()| futures::future::ready(())),
+	let overrides = overrides_handle(client.clone());
+	let eth_block_data_cache = spawn_frontier_tasks(
+		FrontierTaskParams {
+			client: client.clone(),
+			substrate_backend: backend.clone(),
+			eth_filter_pool: eth_filter_pool.clone(),
+			eth_backend: eth_backend.clone(),
+			fee_history_limit,
+			fee_history_cache: fee_history_cache.clone(),
+			task_manager: &task_manager,
+			prometheus_registry: prometheus_registry.clone(),
+			overrides: overrides.clone(),
+			sync_strategy: SyncStrategy::Parachain,
+		},
+		sync_service.clone(),
+		eth_pubsub_notification_sinks.clone(),
 	);
 
-	let runtime_id = parachain_config.chain_spec.runtime_id();
-
+	// Rpc
 	let rpc_builder = Box::new({
 		clone!(
 			client,
 			backend,
-			pubsub_notification_sinks,
+			eth_backend,
+			eth_pubsub_notification_sinks,
+			fee_history_cache,
+			eth_block_data_cache,
+			overrides,
 			transaction_pool,
 			network,
 			sync_service,
-			frontier_backend,
 		);
-		move |deny_unsafe, subscription_task_executor| {
+		move |deny_unsafe, subscription_task_executor: SubscriptionTaskExecutor| {
 			clone!(
 				backend,
-				runtime_id,
+				eth_block_data_cache,
 				client,
-				transaction_pool,
-				filter_pool,
+				eth_backend,
+				eth_filter_pool,
+				eth_pubsub_notification_sinks,
+				fee_history_cache,
+				eth_block_data_cache,
 				network,
+				runtime_id,
+				transaction_pool,
 				select_chain,
-				block_data_cache,
-				fee_history_cache,
-				pubsub_notification_sinks,
-				frontier_backend,
+				overrides,
 			);
 
 			#[cfg(not(feature = "pov-estimate"))]
 			let _ = backend;
 
+			let mut rpc_handle = RpcModule::new(());
+
 			let full_deps = unique_rpc::FullDeps {
+				client: client.clone(),
 				runtime_id,
 
 				#[cfg(feature = "pov-estimate")]
@@ -546,32 +546,40 @@
 				#[cfg(feature = "pov-estimate")]
 				backend,
 
-				eth_backend: frontier_backend,
 				deny_unsafe,
+				pool: transaction_pool.clone(),
+				select_chain,
+			};
+
+			unique_rpc::create_full::<_, _, _, Runtime, RuntimeApi, _>(&mut rpc_handle, full_deps)?;
+
+			let eth_deps = unique_rpc::EthDeps {
 				client,
 				graph: transaction_pool.pool().clone(),
 				pool: transaction_pool,
-				// TODO: Unhardcode
-				enable_dev_signer: false,
-				filter_pool,
+				is_authority: validator,
 				network,
-				sync: sync_service.clone(),
-				select_chain,
-				is_authority: validator,
+				eth_backend,
 				// TODO: Unhardcode
 				max_past_logs: 10000,
-				block_data_cache,
+				fee_history_limit,
 				fee_history_cache,
+				eth_block_data_cache,
 				// TODO: Unhardcode
-				fee_history_limit: 2048,
-				pubsub_notification_sinks,
+				enable_dev_signer: false,
+				eth_filter_pool,
+				eth_pubsub_notification_sinks,
+				overrides,
+				sync: sync_service.clone(),
 			};
 
-			unique_rpc::create_full::<_, _, _, _, Runtime, RuntimeApi, _>(
-				full_deps,
-				subscription_task_executor,
-			)
-			.map_err(Into::into)
+			unique_rpc::create_eth(
+				&mut rpc_handle,
+				eth_deps,
+				subscription_task_executor.clone(),
+			)?;
+
+			Ok(rpc_handle)
 		}
 	});
 
@@ -866,6 +874,13 @@
 	))
 }
 
+pub struct OtherPartial {
+	pub telemetry: Option<Telemetry>,
+	pub telemetry_worker_handle: Option<TelemetryWorkerHandle>,
+	pub eth_filter_pool: Option<FilterPool>,
+	pub eth_backend: Arc<fc_db::kv::Backend<Block>>,
+}
+
 /// Builds a new development service. This service uses instant seal, and mocks
 /// the parachain inherent
 pub fn start_dev_node<Runtime, RuntimeApi, ExecutorDispatch>(
@@ -899,7 +914,6 @@
 {
 	use sc_consensus_manual_seal::{run_manual_seal, EngineCommand, ManualSealParams};
 	use fc_consensus::FrontierBlockImport;
-	use sc_client_api::HeaderBackend;
 
 	let sc_service::PartialComponents {
 		client,
@@ -910,7 +924,12 @@
 		select_chain: maybe_select_chain,
 		transaction_pool,
 		other:
-			(telemetry, filter_pool, frontier_backend, _telemetry_worker_handle, fee_history_cache),
+			OtherPartial {
+				telemetry,
+				eth_filter_pool,
+				eth_backend,
+				telemetry_worker_handle: _,
+			},
 	} = new_partial::<RuntimeApi, ExecutorDispatch, _>(
 		&config,
 		dev_build_import_queue::<RuntimeApi, ExecutorDispatch>,
@@ -918,19 +937,6 @@
 	let net_config = sc_network::config::FullNetworkConfiguration::new(&config.network);
 	let prometheus_registry = config.prometheus_registry().cloned();
 
-	let block_data_cache = Arc::new(fc_rpc::EthBlockDataCacheTask::new(
-		task_manager.spawn_handle(),
-		overrides_handle::<_, _, Runtime>(client.clone()),
-		50,
-		50,
-		prometheus_registry.clone(),
-	));
-
-	let pubsub_notification_sinks: fc_mapping_sync::EthereumBlockNotificationSinks<
-		fc_mapping_sync::EthereumBlockNotification<Block>,
-	> = Default::default();
-	let pubsub_notification_sinks = Arc::new(pubsub_notification_sinks);
-
 	let (network, system_rpc_tx, tx_handler_controller, network_starter, sync_service) =
 		sc_service::build_network(sc_service::BuildNetworkParams {
 			config: &config,
@@ -1046,57 +1052,76 @@
 			}),
 		);
 	}
-
-	task_manager.spawn_essential_handle().spawn(
-		"frontier-mapping-sync-worker",
-		Some("block-authoring"),
-		MappingSyncWorker::new(
-			client.import_notification_stream(),
-			Duration::new(6, 0),
-			client.clone(),
-			backend.clone(),
-			overrides_handle::<_, _, Runtime>(client.clone()),
-			frontier_backend.clone(),
-			3,
-			0,
-			SyncStrategy::Normal,
-			sync_service.clone(),
-			pubsub_notification_sinks.clone(),
-		)
-		.for_each(|()| futures::future::ready(())),
-	);
 
 	#[cfg(feature = "pov-estimate")]
 	let rpc_backend = backend.clone();
 
 	let runtime_id = config.chain_spec.runtime_id();
 
+	// Frontier
+	let fee_history_cache: FeeHistoryCache = Arc::new(Mutex::new(BTreeMap::new()));
+	let fee_history_limit = 2048;
+
+	let eth_pubsub_notification_sinks: Arc<
+		EthereumBlockNotificationSinks<fc_mapping_sync::EthereumBlockNotification<Block>>,
+	> = Default::default();
+
+	let overrides = overrides_handle(client.clone());
+	let eth_block_data_cache = spawn_frontier_tasks(
+		FrontierTaskParams {
+			client: client.clone(),
+			substrate_backend: backend.clone(),
+			eth_filter_pool: eth_filter_pool.clone(),
+			eth_backend: eth_backend.clone(),
+			fee_history_limit,
+			fee_history_cache: fee_history_cache.clone(),
+			task_manager: &task_manager,
+			prometheus_registry,
+			overrides: overrides.clone(),
+			sync_strategy: SyncStrategy::Normal,
+		},
+		sync_service.clone(),
+		eth_pubsub_notification_sinks.clone(),
+	);
+
+	// Rpc
 	let rpc_builder = Box::new({
 		clone!(
-			backend,
 			client,
-			sync_service,
-			frontier_backend,
+			backend,
+			eth_backend,
+			eth_pubsub_notification_sinks,
+			fee_history_cache,
+			eth_block_data_cache,
+			overrides,
+			transaction_pool,
 			network,
-			transaction_pool,
-			pubsub_notification_sinks
+			sync_service,
 		);
-		move |deny_unsafe, subscription_executor| {
+		move |deny_unsafe, subscription_task_executor: SubscriptionTaskExecutor| {
 			clone!(
 				backend,
-				block_data_cache,
+				eth_block_data_cache,
 				client,
+				eth_backend,
+				eth_filter_pool,
+				eth_pubsub_notification_sinks,
 				fee_history_cache,
-				filter_pool,
+				eth_block_data_cache,
 				network,
-				pubsub_notification_sinks,
+				runtime_id,
+				transaction_pool,
+				select_chain,
+				overrides,
 			);
 
 			#[cfg(not(feature = "pov-estimate"))]
 			let _ = backend;
 
+			let mut rpc_module = RpcModule::new(());
+
 			let full_deps = unique_rpc::FullDeps {
-				runtime_id: runtime_id.clone(),
+				runtime_id,
 
 				#[cfg(feature = "pov-estimate")]
 				exec_params: uc_rpc::pov_estimate::ExecutorParams {
@@ -1108,32 +1133,42 @@
 
 				#[cfg(feature = "pov-estimate")]
 				backend,
-				eth_backend: frontier_backend.clone(),
+				// eth_backend,
 				deny_unsafe,
-				client,
+				client: client.clone(),
 				pool: transaction_pool.clone(),
+				select_chain,
+			};
+
+			unique_rpc::create_full::<_, _, _, Runtime, RuntimeApi, _>(&mut rpc_module, full_deps)?;
+
+			let eth_deps = unique_rpc::EthDeps {
+				client,
 				graph: transaction_pool.pool().clone(),
-				// TODO: Unhardcode
-				enable_dev_signer: false,
-				filter_pool,
+				pool: transaction_pool,
+				is_authority: true,
 				network,
-				sync: sync_service.clone(),
-				select_chain: select_chain.clone(),
-				is_authority: collator,
+				eth_backend,
 				// TODO: Unhardcode
 				max_past_logs: 10000,
-				block_data_cache,
+				fee_history_limit,
 				fee_history_cache,
+				eth_block_data_cache,
 				// TODO: Unhardcode
-				fee_history_limit: 2048,
-				pubsub_notification_sinks,
+				enable_dev_signer: false,
+				eth_filter_pool,
+				eth_pubsub_notification_sinks,
+				overrides,
+				sync: sync_service.clone(),
 			};
 
-			unique_rpc::create_full::<_, _, _, _, Runtime, RuntimeApi, _>(
-				full_deps,
-				subscription_executor,
-			)
-			.map_err(Into::into)
+			unique_rpc::create_eth(
+				&mut rpc_module,
+				eth_deps,
+				subscription_task_executor.clone(),
+			)?;
+
+			Ok(rpc_module)
 		}
 	});
 
@@ -1155,3 +1190,130 @@
 	network_starter.start_network();
 	Ok(task_manager)
 }
+
+fn overrides_handle<C, BE>(client: Arc<C>) -> Arc<OverrideHandle<Block>>
+where
+	C: ProvideRuntimeApi<Block> + StorageProvider<Block, BE> + AuxStore,
+	C: HeaderBackend<Block> + HeaderMetadata<Block, Error = BlockChainError>,
+	C: Send + Sync + 'static,
+	C::Api: fp_rpc::EthereumRuntimeRPCApi<Block>,
+	BE: Backend<Block> + 'static,
+	BE::State: StateBackend<BlakeTwo256>,
+{
+	let mut overrides_map = BTreeMap::new();
+	overrides_map.insert(
+		EthereumStorageSchema::V1,
+		Box::new(SchemaV1Override::new(client.clone())) as Box<dyn StorageOverride<_> + 'static>,
+	);
+	overrides_map.insert(
+		EthereumStorageSchema::V2,
+		Box::new(SchemaV2Override::new(client.clone())) as Box<dyn StorageOverride<_> + 'static>,
+	);
+	overrides_map.insert(
+		EthereumStorageSchema::V3,
+		Box::new(SchemaV3Override::new(client.clone())) as Box<dyn StorageOverride<_> + 'static>,
+	);
+
+	Arc::new(OverrideHandle {
+		schemas: overrides_map,
+		fallback: Box::new(RuntimeApiStorageOverride::new(client)),
+	})
+}
+
+pub struct FrontierTaskParams<'a, B: BlockT, C, BE> {
+	pub task_manager: &'a TaskManager,
+	pub client: Arc<C>,
+	pub substrate_backend: Arc<BE>,
+	pub eth_backend: Arc<fc_db::kv::Backend<B>>,
+	pub eth_filter_pool: Option<FilterPool>,
+	pub overrides: Arc<OverrideHandle<B>>,
+	pub fee_history_limit: u64,
+	pub fee_history_cache: FeeHistoryCache,
+	pub sync_strategy: SyncStrategy,
+	pub prometheus_registry: Option<Registry>,
+}
+
+pub fn spawn_frontier_tasks<B, C, BE>(
+	params: FrontierTaskParams<B, C, BE>,
+	sync: Arc<SyncingService<B>>,
+	pubsub_notification_sinks: Arc<
+		EthereumBlockNotificationSinks<fc_mapping_sync::EthereumBlockNotification<B>>,
+	>,
+) -> Arc<EthBlockDataCacheTask<B>>
+where
+	C: ProvideRuntimeApi<B> + BlockOf,
+	C: HeaderBackend<B> + HeaderMetadata<B, Error = BlockChainError> + 'static,
+	C: BlockchainEvents<B> + StorageProvider<B, BE>,
+	C: Send + Sync + 'static,
+	C::Api: EthereumRuntimeRPCApi<B>,
+	C::Api: BlockBuilder<B>,
+	B: BlockT<Hash = H256> + Send + Sync + 'static,
+	B::Header: HeaderT<Number = u32>,
+	BE: Backend<B> + 'static,
+	BE::State: StateBackend<BlakeTwo256>,
+{
+	let FrontierTaskParams {
+		task_manager,
+		client,
+		substrate_backend,
+		eth_backend,
+		eth_filter_pool,
+		overrides,
+		fee_history_limit,
+		fee_history_cache,
+		sync_strategy,
+		prometheus_registry,
+	} = params;
+	// Frontier offchain DB task. Essential.
+	// Maps emulated ethereum data to substrate native data.
+	params.task_manager.spawn_essential_handle().spawn(
+		"frontier-mapping-sync-worker",
+		Some("frontier"),
+		MappingSyncWorker::new(
+			client.import_notification_stream(),
+			Duration::new(6, 0),
+			client.clone(),
+			substrate_backend,
+			overrides.clone(),
+			eth_backend,
+			3,
+			0,
+			sync_strategy,
+			sync,
+			pubsub_notification_sinks,
+		)
+		.for_each(|()| futures::future::ready(())),
+	);
+
+	// Frontier `EthFilterApi` maintenance.
+	// Manages the pool of user-created Filters.
+	if let Some(eth_filter_pool) = eth_filter_pool {
+		// Each filter is allowed to stay in the pool for 100 blocks.
+		const FILTER_RETAIN_THRESHOLD: u64 = 100;
+		params.task_manager.spawn_essential_handle().spawn(
+			"frontier-filter-pool",
+			Some("frontier"),
+			EthTask::filter_pool_task(client.clone(), eth_filter_pool, FILTER_RETAIN_THRESHOLD),
+		);
+	}
+
+	// Spawn Frontier FeeHistory cache maintenance task.
+	params.task_manager.spawn_essential_handle().spawn(
+		"frontier-fee-history",
+		Some("frontier"),
+		EthTask::fee_history_task(
+			client,
+			overrides.clone(),
+			fee_history_cache,
+			fee_history_limit,
+		),
+	);
+
+	Arc::new(EthBlockDataCacheTask::new(
+		task_manager.spawn_handle(),
+		overrides,
+		50,
+		50,
+		prometheus_registry,
+	))
+}
modifiednode/rpc/Cargo.tomldiffbeforeafterboth
--- a/node/rpc/Cargo.toml
+++ b/node/rpc/Cargo.toml
@@ -14,7 +14,6 @@
 # pallet-contracts-rpc = { git = 'https://github.com/paritytech/substrate', branch = 'master' }
 pallet-transaction-payment-rpc = { workspace = true }
 sc-client-api = { workspace = true }
-sc-consensus-grandpa = { workspace = true }
 sc-network = { workspace = true }
 sc-network-sync = { workspace = true }
 sc-rpc = { workspace = true }
@@ -41,6 +40,7 @@
 up-data-structs = { workspace = true }
 up-pov-estimate-rpc = { workspace = true, default-features = true }
 up-rpc = { workspace = true }
+pallet-ethereum.workspace = true
 
 [features]
 default = []
modifiednode/rpc/src/lib.rsdiffbeforeafterboth
--- a/node/rpc/src/lib.rs
+++ b/node/rpc/src/lib.rs
@@ -14,6 +14,7 @@
 // You should have received a copy of the GNU General Public License
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
+use fc_mapping_sync::{EthereumBlockNotificationSinks, EthereumBlockNotification};
 use sp_runtime::traits::BlakeTwo256;
 use fc_rpc::{
 	EthBlockDataCacheTask, OverrideHandle, RuntimeApiStorageOverride, SchemaV1Override,
@@ -26,9 +27,6 @@
 	backend::{AuxStore, StorageProvider},
 	client::BlockchainEvents,
 	StateBackend, Backend,
-};
-use sc_consensus_grandpa::{
-	FinalityProofProvider, GrandpaJustificationStream, SharedAuthoritySet, SharedVoterState,
 };
 use sc_network::NetworkService;
 use sc_network_sync::SyncingService;
@@ -46,42 +44,16 @@
 #[cfg(feature = "pov-estimate")]
 type FullBackend = sc_service::TFullBackend<Block>;
 
-/// Extra dependencies for GRANDPA
-pub struct GrandpaDeps<B> {
-	/// Voting round info.
-	pub shared_voter_state: SharedVoterState,
-	/// Authority set info.
-	pub shared_authority_set: SharedAuthoritySet<Hash, BlockNumber>,
-	/// Receives notifications about justification events from Grandpa.
-	pub justification_stream: GrandpaJustificationStream<Block>,
-	/// Executor to drive the subscription manager in the Grandpa RPC handler.
-	pub subscription_executor: SubscriptionTaskExecutor,
-	/// Finality proof provider.
-	pub finality_provider: Arc<FinalityProofProvider<B, Block>>,
-}
-
 /// Full client dependencies.
-pub struct FullDeps<C, P, SC, CA: ChainApi> {
+pub struct FullDeps<C, P, SC> {
 	/// The client instance to use.
 	pub client: Arc<C>,
 	/// Transaction pool instance.
 	pub pool: Arc<P>,
-	/// Graph pool instance.
-	pub graph: Arc<Pool<CA>>,
 	/// The SelectChain Strategy
 	pub select_chain: SC,
-	/// The Node authority flag
-	pub is_authority: bool,
-	/// Whether to enable dev signer
-	pub enable_dev_signer: bool,
-	/// Network service
-	pub network: Arc<NetworkService<Block, Hash>>,
-	/// Syncing service
-	pub sync: Arc<SyncingService<Block>>,
 	/// Whether to deny unsafe calls
 	pub deny_unsafe: DenyUnsafe,
-	/// EthFilterApi pool.
-	pub filter_pool: Option<FilterPool>,
 
 	/// Runtime identification (read from the chain spec)
 	pub runtime_id: RuntimeId,
@@ -91,23 +63,6 @@
 	/// Substrate Backend.
 	#[cfg(feature = "pov-estimate")]
 	pub backend: Arc<FullBackend>,
-
-	/// Ethereum Backend.
-	pub eth_backend: Arc<dyn fc_db::BackendReader<Block> + Send + Sync>,
-	/// Maximum number of logs in a query.
-	pub max_past_logs: u32,
-	/// Maximum fee history cache size.
-	pub fee_history_limit: u64,
-	/// Fee history cache.
-	pub fee_history_cache: FeeHistoryCache,
-	/// Cache for Ethereum block data.
-	pub block_data_cache: Arc<EthBlockDataCacheTask<Block>>,
-
-	pub pubsub_notification_sinks: Arc<
-		fc_mapping_sync::EthereumBlockNotificationSinks<
-			fc_mapping_sync::EthereumBlockNotification<Block>,
-		>,
-	>,
 }
 
 pub fn overrides_handle<C, BE, R>(client: Arc<C>) -> Arc<OverrideHandle<Block>>
@@ -142,10 +97,10 @@
 }
 
 /// Instantiate all Full RPC extensions.
-pub fn create_full<C, P, SC, CA, R, A, B>(
-	deps: FullDeps<C, P, SC, CA>,
-	subscription_task_executor: SubscriptionTaskExecutor,
-) -> Result<RpcModule<()>, Box<dyn std::error::Error + Send + Sync>>
+pub fn create_full<C, P, SC, R, A, B>(
+	io: &mut RpcModule<()>,
+	deps: FullDeps<C, P, SC>,
+) -> Result<(), Box<dyn std::error::Error + Send + Sync>>
 where
 	C: ProvideRuntimeApi<Block> + StorageProvider<Block, B> + AuxStore,
 	C: HeaderBackend<Block> + HeaderMetadata<Block, Error = BlockChainError> + 'static,
@@ -155,8 +110,6 @@
 	C::Api: BlockBuilder<Block>,
 	// C::Api: pallet_contracts_rpc::ContractsRuntimeApi<Block, AccountId, Balance, BlockNumber, Hash>,
 	C::Api: pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi<Block, Balance>,
-	C::Api: fp_rpc::EthereumRuntimeRPCApi<Block>,
-	C::Api: fp_rpc::ConvertTransactionRuntimeApi<Block>,
 	C::Api: up_rpc::UniqueApi<Block, <R as RuntimeInstance>::CrossAccountId, AccountId>,
 	C::Api: app_promotion_rpc::AppPromotionApi<
 		Block,
@@ -168,7 +121,6 @@
 	B: sc_client_api::Backend<Block> + Send + Sync + 'static,
 	B::State: sc_client_api::backend::StateBackend<sp_runtime::traits::HashFor<Block>>,
 	P: TransactionPool<Block = Block> + 'static,
-	CA: ChainApi<Block = Block> + 'static,
 	R: RuntimeInstance + Send + Sync + 'static,
 	<R as RuntimeInstance>::CrossAccountId: serde::Serialize,
 	C: sp_api::CallApiAt<
@@ -179,10 +131,6 @@
 	>,
 	for<'de> <R as RuntimeInstance>::CrossAccountId: serde::Deserialize<'de>,
 {
-	use fc_rpc::{
-		Eth, EthApiServer, EthDevSigner, EthFilter, EthFilterApiServer, EthPubSub,
-		EthPubSubApiServer, EthSigner, Net, NetApiServer, Web3, Web3ApiServer, TxPool, TxPoolApiServer
-	};
 	use uc_rpc::{UniqueApiServer, Unique};
 
 	use uc_rpc::{AppPromotionApiServer, AppPromotion};
@@ -194,21 +142,11 @@
 	use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApiServer};
 	use substrate_frame_rpc_system::{System, SystemApiServer};
 
-	let mut io = RpcModule::new(());
 	let FullDeps {
 		client,
 		pool,
-		graph,
 		select_chain: _,
-		fee_history_limit,
-		fee_history_cache,
-		block_data_cache,
-		enable_dev_signer,
-		is_authority,
-		network,
-		sync,
 		deny_unsafe,
-		filter_pool,
 
 		runtime_id: _,
 
@@ -217,37 +155,137 @@
 
 		#[cfg(feature = "pov-estimate")]
 		backend,
-
-		eth_backend,
-		max_past_logs,
-		pubsub_notification_sinks,
 	} = deps;
 
 	io.merge(System::new(Arc::clone(&client), Arc::clone(&pool), deny_unsafe).into_rpc())?;
 	io.merge(TransactionPayment::new(Arc::clone(&client)).into_rpc())?;
 
-	// io.extend_with(ContractsApi::to_delegate(Contracts::new(client.clone())));
+	io.merge(Unique::new(client.clone()).into_rpc())?;
+
+	io.merge(AppPromotion::new(client.clone()).into_rpc())?;
+
+	#[cfg(feature = "pov-estimate")]
+	io.merge(
+		PovEstimate::new(
+			client.clone(),
+			backend,
+			deny_unsafe,
+			exec_params,
+			runtime_id,
+		)
+		.into_rpc(),
+	)?;
+
+	Ok(())
+}
+
+pub struct EthDeps<C, P, CA: ChainApi> {
+	/// The client instance to use.
+	pub client: Arc<C>,
+	/// Transaction pool instance.
+	pub pool: Arc<P>,
+	/// Graph pool instance.
+	pub graph: Arc<Pool<CA>>,
+	/// Syncing service
+	pub sync: Arc<SyncingService<Block>>,
+	/// The Node authority flag
+	pub is_authority: bool,
+	/// Network service
+	pub network: Arc<NetworkService<Block, Hash>>,
+
+	/// Ethereum Backend.
+	pub eth_backend: Arc<dyn fc_db::BackendReader<Block> + Send + Sync>,
+	/// Maximum number of logs in a query.
+	pub max_past_logs: u32,
+	/// Maximum fee history cache size.
+	pub fee_history_limit: u64,
+	/// Fee history cache.
+	pub fee_history_cache: FeeHistoryCache,
+	pub eth_block_data_cache: Arc<EthBlockDataCacheTask<Block>>,
+	/// EthFilterApi pool.
+	pub eth_filter_pool: Option<FilterPool>,
+	pub eth_pubsub_notification_sinks: Arc<EthereumBlockNotificationSinks<EthereumBlockNotification<Block>>>,
+	/// Whether to enable eth dev signer
+	pub enable_dev_signer: bool,
+
+	pub overrides: Arc<OverrideHandle<Block>>,
+}
+
+/// This converter is never used, but we have a generic
+/// Option<T>, where T should implement ConvertTransaction
+///
+/// TODO: remove after never-type (`!`) stabilization
+enum NeverConvert {}
+impl<T> fp_rpc::ConvertTransaction<T> for NeverConvert {
+	fn convert_transaction(&self, _transaction: pallet_ethereum::Transaction) -> T {
+		unreachable!()
+	}
+}
 
+pub fn create_eth<C, P, CA, B>(
+	io: &mut RpcModule<()>,
+	deps: EthDeps<C, P, CA>,
+	subscription_task_executor: SubscriptionTaskExecutor,
+) -> Result<(), Box<dyn std::error::Error + Send + Sync>>
+where
+	C: ProvideRuntimeApi<Block> + StorageProvider<Block, B> + AuxStore,
+	C: HeaderBackend<Block> + HeaderMetadata<Block, Error = BlockChainError> + 'static,
+	C: Send + Sync + 'static,
+	C: BlockchainEvents<Block>,
+	C::Api: BlockBuilder<Block>,
+	C::Api: fp_rpc::EthereumRuntimeRPCApi<Block>,
+	C::Api: fp_rpc::ConvertTransactionRuntimeApi<Block>,
+	P: TransactionPool<Block = Block> + 'static,
+	CA: ChainApi<Block = Block> + 'static,
+	B: sc_client_api::Backend<Block> + Send + Sync + 'static,
+	C: sp_api::CallApiAt<
+		sp_runtime::generic::Block<
+			sp_runtime::generic::Header<u32, BlakeTwo256>,
+			sp_runtime::OpaqueExtrinsic,
+		>,
+	>,
+{
+	use fc_rpc::{
+		Eth, EthApiServer, EthDevSigner, EthFilter, EthFilterApiServer, EthPubSub,
+		EthPubSubApiServer, EthSigner, Net, NetApiServer, Web3, Web3ApiServer, TxPool, TxPoolApiServer,
+	};
+
+	let EthDeps {
+		client,
+		pool,
+		graph,
+		eth_backend,
+		max_past_logs,
+		fee_history_limit,
+		fee_history_cache,
+		eth_block_data_cache,
+		eth_filter_pool,
+		eth_pubsub_notification_sinks,
+		enable_dev_signer,
+		sync,
+		is_authority,
+		network,
+		overrides,
+	} = deps;
+
 	let mut signers = Vec::new();
 	if enable_dev_signer {
 		signers.push(Box::new(EthDevSigner::new()) as Box<dyn EthSigner>);
 	}
-
-	let overrides = overrides_handle::<_, _, R>(client.clone());
-
 	let execute_gas_limit_multiplier = 10;
 	io.merge(
 		Eth::new(
 			client.clone(),
 			pool.clone(),
 			graph.clone(),
-			Some(<R as RuntimeInstance>::get_transaction_converter()),
+			// We have no runtimes old enough to only accept converted transactions
+			None::<NeverConvert>,
 			sync.clone(),
 			signers,
 			overrides.clone(),
 			eth_backend.clone(),
 			is_authority,
-			block_data_cache.clone(),
+			eth_block_data_cache.clone(),
 			fee_history_cache,
 			fee_history_limit,
 			execute_gas_limit_multiplier,
@@ -256,24 +294,12 @@
 		.into_rpc(),
 	)?;
 
-	io.merge(Unique::new(client.clone()).into_rpc())?;
-
-	io.merge(AppPromotion::new(client.clone()).into_rpc())?;
+	let tx_pool = TxPool::new(
+		client.clone(),
+		graph,
+		);
 
-	#[cfg(feature = "pov-estimate")]
-	io.merge(
-		PovEstimate::new(
-			client.clone(),
-			backend,
-			deny_unsafe,
-			exec_params,
-			runtime_id,
-		)
-		.into_rpc(),
-	)?;
-
-	let tx_pool = TxPool::new(client.clone(), graph);
-	if let Some(filter_pool) = filter_pool {
+	if let Some(filter_pool) = eth_filter_pool {
 		io.merge(
 			EthFilter::new(
 				client.clone(),
@@ -282,12 +308,11 @@
 				filter_pool,
 				500_usize, // max stored filters
 				max_past_logs,
-				block_data_cache,
+				eth_block_data_cache,
 			)
 			.into_rpc(),
 		)?;
 	}
-
 	io.merge(
 		Net::new(
 			client.clone(),
@@ -297,9 +322,7 @@
 		)
 		.into_rpc(),
 	)?;
-
 	io.merge(Web3::new(client.clone()).into_rpc())?;
-
 	io.merge(
 		EthPubSub::new(
 			pool,
@@ -307,12 +330,11 @@
 			sync,
 			subscription_task_executor,
 			overrides,
-			pubsub_notification_sinks,
+			eth_pubsub_notification_sinks,
 		)
 		.into_rpc(),
 	)?;
-
 	io.merge(tx_pool.into_rpc())?;
 
-	Ok(io)
+	Ok(())
 }