diff --git a/polkadot/Cargo.lock b/polkadot/Cargo.lock
index c0991ae3b78471e933f4731c5f65f835105fab89..b8bca8772e47eb164d6092bbdedc9dc189cb3e9a 100644
--- a/polkadot/Cargo.lock
+++ b/polkadot/Cargo.lock
@@ -4575,11 +4575,10 @@ dependencies = [
 
 [[package]]
 name = "log"
-version = "0.4.17"
+version = "0.4.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
+checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4"
 dependencies = [
- "cfg-if",
  "serde",
  "value-bag",
 ]
@@ -6917,7 +6916,6 @@ dependencies = [
  "frame-benchmarking-cli",
  "futures",
  "log",
- "polkadot-client",
  "polkadot-node-core-pvf-execute-worker",
  "polkadot-node-core-pvf-prepare-worker",
  "polkadot-node-metrics",
@@ -6940,50 +6938,6 @@ dependencies = [
  "try-runtime-cli",
 ]
 
-[[package]]
-name = "polkadot-client"
-version = "0.9.43"
-dependencies = [
- "async-trait",
- "frame-benchmarking",
- "frame-benchmarking-cli",
- "frame-system",
- "frame-system-rpc-runtime-api",
- "futures",
- "kusama-runtime",
- "pallet-transaction-payment",
- "pallet-transaction-payment-rpc-runtime-api",
- "polkadot-core-primitives",
- "polkadot-node-core-parachains-inherent",
- "polkadot-primitives",
- "polkadot-runtime",
- "polkadot-runtime-common",
- "rococo-runtime",
- "sc-client-api",
- "sc-consensus",
- "sc-executor",
- "sc-service",
- "sp-api",
- "sp-authority-discovery",
- "sp-block-builder",
- "sp-blockchain",
- "sp-consensus",
- "sp-consensus-babe",
- "sp-consensus-beefy",
- "sp-consensus-grandpa",
- "sp-core",
- "sp-inherents",
- "sp-keyring",
- "sp-mmr-primitives",
- "sp-offchain",
- "sp-runtime",
- "sp-session",
- "sp-storage",
- "sp-timestamp",
- "sp-transaction-pool",
- "westend-runtime",
-]
-
 [[package]]
 name = "polkadot-collator-protocol"
 version = "0.9.43"
@@ -8071,8 +8025,10 @@ dependencies = [
  "assert_matches",
  "async-trait",
  "env_logger 0.9.0",
+ "frame-benchmarking",
  "frame-benchmarking-cli",
  "frame-support",
+ "frame-system",
  "frame-system-rpc-runtime-api",
  "futures",
  "hex-literal 0.4.1",
@@ -8086,14 +8042,16 @@ dependencies = [
  "pallet-babe",
  "pallet-im-online",
  "pallet-staking",
+ "pallet-transaction-payment",
  "pallet-transaction-payment-rpc-runtime-api",
  "parity-db",
+ "parity-scale-codec",
  "polkadot-approval-distribution",
  "polkadot-availability-bitfield-distribution",
  "polkadot-availability-distribution",
  "polkadot-availability-recovery",
- "polkadot-client",
  "polkadot-collator-protocol",
+ "polkadot-core-primitives",
  "polkadot-dispute-distribution",
  "polkadot-gossip-support",
  "polkadot-network-bridge",
@@ -8121,6 +8079,7 @@ dependencies = [
  "polkadot-primitives",
  "polkadot-rpc",
  "polkadot-runtime",
+ "polkadot-runtime-common",
  "polkadot-runtime-constants",
  "polkadot-runtime-parachains",
  "polkadot-statement-distribution",
@@ -8162,6 +8121,7 @@ dependencies = [
  "sp-core",
  "sp-inherents",
  "sp-io",
+ "sp-keyring",
  "sp-keystore",
  "sp-mmr-primitives",
  "sp-offchain",
@@ -8172,6 +8132,8 @@ dependencies = [
  "sp-timestamp",
  "sp-transaction-pool",
  "sp-trie",
+ "sp-version",
+ "sp-weights",
  "substrate-prometheus-endpoint",
  "tempfile",
  "thiserror",
@@ -8224,6 +8186,7 @@ dependencies = [
 name = "polkadot-test-client"
 version = "0.9.43"
 dependencies = [
+ "frame-benchmarking",
  "futures",
  "parity-scale-codec",
  "polkadot-node-subsystem",
@@ -8232,6 +8195,7 @@ dependencies = [
  "polkadot-test-service",
  "sc-block-builder",
  "sc-consensus",
+ "sc-offchain",
  "sc-service",
  "sp-api",
  "sp-blockchain",
@@ -8239,6 +8203,7 @@ dependencies = [
  "sp-consensus-babe",
  "sp-core",
  "sp-inherents",
+ "sp-io",
  "sp-keyring",
  "sp-runtime",
  "sp-state-machine",
@@ -8344,7 +8309,6 @@ dependencies = [
 name = "polkadot-test-service"
 version = "0.9.43"
 dependencies = [
- "frame-benchmarking",
  "frame-system",
  "futures",
  "hex",
@@ -8369,7 +8333,6 @@ dependencies = [
  "sc-consensus",
  "sc-consensus-babe",
  "sc-consensus-grandpa",
- "sc-executor",
  "sc-network",
  "sc-service",
  "sc-tracing",
@@ -12195,11 +12158,70 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
 
 [[package]]
 name = "sval"
-version = "1.0.0-alpha.5"
+version = "2.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b031320a434d3e9477ccf9b5756d57d4272937b8d22cb88af80b7633a1b78b1"
+
+[[package]]
+name = "sval_buffer"
+version = "2.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6bf7e9412af26b342f3f2cc5cc4122b0105e9d16eb76046cd14ed10106cf6028"
+dependencies = [
+ "sval",
+ "sval_ref",
+]
+
+[[package]]
+name = "sval_dynamic"
+version = "2.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a0ef628e8a77a46ed3338db8d1b08af77495123cc229453084e47cd716d403cf"
+dependencies = [
+ "sval",
+]
+
+[[package]]
+name = "sval_fmt"
+version = "2.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7dc09e9364c2045ab5fa38f7b04d077b3359d30c4c2b3ec4bae67a358bd64326"
+dependencies = [
+ "itoa",
+ "ryu",
+ "sval",
+]
+
+[[package]]
+name = "sval_json"
+version = "2.6.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "45f6ee7c7b87caf59549e9fe45d6a69c75c8019e79e212a835c5da0e92f0ba08"
+checksum = "ada6f627e38cbb8860283649509d87bc4a5771141daa41c78fd31f2b9485888d"
+dependencies = [
+ "itoa",
+ "ryu",
+ "sval",
+]
+
+[[package]]
+name = "sval_ref"
+version = "2.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "703ca1942a984bd0d9b5a4c0a65ab8b4b794038d080af4eb303c71bc6bf22d7c"
+dependencies = [
+ "sval",
+]
+
+[[package]]
+name = "sval_serde"
+version = "2.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "830926cd0581f7c3e5d51efae4d35c6b6fc4db583842652891ba2f1bed8db046"
 dependencies = [
  "serde",
+ "sval",
+ "sval_buffer",
+ "sval_fmt",
 ]
 
 [[package]]
@@ -13248,16 +13270,38 @@ checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
 
 [[package]]
 name = "value-bag"
-version = "1.0.0-alpha.9"
+version = "1.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2209b78d1249f7e6f3293657c9779fe31ced465df091bbd433a1cf88e916ec55"
+checksum = "d92ccd67fb88503048c01b59152a04effd0782d035a83a6d256ce6085f08f4a3"
+dependencies = [
+ "value-bag-serde1",
+ "value-bag-sval2",
+]
+
+[[package]]
+name = "value-bag-serde1"
+version = "1.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b0b9f3feef403a50d4d67e9741a6d8fc688bcbb4e4f31bd4aab72cc690284394"
 dependencies = [
- "ctor",
  "erased-serde",
  "serde",
  "serde_fmt",
+]
+
+[[package]]
+name = "value-bag-sval2"
+version = "1.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "30b24f4146b6f3361e91cbf527d1fb35e9376c3c0cef72ca5ec5af6d640fad7d"
+dependencies = [
  "sval",
- "version_check",
+ "sval_buffer",
+ "sval_dynamic",
+ "sval_fmt",
+ "sval_json",
+ "sval_ref",
+ "sval_serde",
 ]
 
 [[package]]
diff --git a/polkadot/Cargo.toml b/polkadot/Cargo.toml
index c4cd139b68fa7c993cccf276cdb6a1aaf4cac8b0..74f2b95705174abd1d40a6c479366c31c72d345e 100644
--- a/polkadot/Cargo.toml
+++ b/polkadot/Cargo.toml
@@ -23,7 +23,7 @@ color-eyre = { version = "0.6.1", default-features = false }
 tikv-jemallocator = "0.5.0"
 
 # Crates in our workspace, defined as dependencies so we can pass them feature flags.
-polkadot-cli = { path = "cli", features = [ "kusama-native", "westend-native", "rococo-native" ]  }
+polkadot-cli = { path = "cli", features = [ "polkadot-native", "kusama-native", "westend-native", "rococo-native" ]  }
 polkadot-node-core-pvf-prepare-worker = { path = "node/core/pvf/prepare-worker" }
 polkadot-overseer = { path = "node/overseer" }
 
@@ -68,7 +68,6 @@ members = [
 	"xcm/pallet-xcm",
 	"xcm/pallet-xcm-benchmarks",
 	"xcm/procedural",
-	"node/client",
 	"node/collation-generation",
 	"node/core/approval-voting",
 	"node/core/av-store",
diff --git a/polkadot/cli/Cargo.toml b/polkadot/cli/Cargo.toml
index 64ce6e7ca595cc171e3216d8c01778b946ccc662..e7aa562880ccb228e9c56f937243080f4301dbeb 100644
--- a/polkadot/cli/Cargo.toml
+++ b/polkadot/cli/Cargo.toml
@@ -22,7 +22,6 @@ pyro = { package = "pyroscope", version = "0.5.3", optional = true }
 pyroscope_pprofrs = { version = "0.2", optional = true }
 
 service = { package = "polkadot-service", path = "../node/service", default-features = false, optional = true }
-polkadot-client = { path = "../node/client", optional = true }
 polkadot-node-core-pvf-execute-worker = { path = "../node/core/pvf/execute-worker", optional = true }
 polkadot-node-core-pvf-prepare-worker = { path = "../node/core/pvf/prepare-worker", optional = true }
 polkadot-performance-test = { path = "../node/test/performance-test", optional = true }
@@ -45,7 +44,7 @@ sc-storage-monitor = { git = "https://github.com/paritytech/substrate", branch =
 substrate-build-script-utils = { git = "https://github.com/paritytech/substrate", branch = "master" }
 
 [features]
-default = ["db", "cli", "full-node", "polkadot-native"]
+default = ["db", "cli", "full-node"]
 db = ["service/db"]
 cli = [
 	"clap",
@@ -54,7 +53,6 @@ cli = [
 	"sc-tracing",
 	"frame-benchmarking-cli",
 	"try-runtime-cli",
-	"polkadot-client",
 	"polkadot-node-core-pvf-execute-worker",
 	"polkadot-node-core-pvf-prepare-worker",
 	"service",
diff --git a/polkadot/cli/src/command.rs b/polkadot/cli/src/command.rs
index db5ebe150ecfd459761ed0d30b5383c8cacd6240..4cf06f254b0dc2b564f45555813981b31887dec2 100644
--- a/polkadot/cli/src/command.rs
+++ b/polkadot/cli/src/command.rs
@@ -18,11 +18,12 @@ use crate::cli::{Cli, Subcommand};
 use frame_benchmarking_cli::{BenchmarkCmd, ExtrinsicFactory, SUBSTRATE_REFERENCE_HARDWARE};
 use futures::future::TryFutureExt;
 use log::info;
-use polkadot_client::benchmarking::{
-	benchmark_inherent_data, ExistentialDepositProvider, RemarkBuilder, TransferKeepAliveBuilder,
-};
 use sc_cli::{RuntimeVersion, SubstrateCli};
-use service::{self, HeaderBackend, IdentifyVariant};
+use service::{
+	self,
+	benchmarking::{benchmark_inherent_data, RemarkBuilder, TransferKeepAliveBuilder},
+	HeaderBackend, IdentifyVariant,
+};
 use sp_core::crypto::Ss58AddressFormatRegistry;
 use sp_keyring::Sr25519Keyring;
 use std::net::ToSocketAddrs;
@@ -225,31 +226,6 @@ fn ensure_dev(spec: &Box<dyn service::ChainSpec>) -> std::result::Result<(), Str
 	}
 }
 
-/// Unwraps a [`polkadot_client::Client`] into the concrete runtime client.
-macro_rules! unwrap_client {
-	(
-		$client:ident,
-		$code:expr
-	) => {
-		match $client.as_ref() {
-			#[cfg(feature = "polkadot-native")]
-			polkadot_client::Client::Polkadot($client) => $code,
-			#[cfg(feature = "westend-native")]
-			polkadot_client::Client::Westend($client) => $code,
-			#[cfg(feature = "kusama-native")]
-			polkadot_client::Client::Kusama($client) => $code,
-			#[cfg(feature = "rococo-native")]
-			polkadot_client::Client::Rococo($client) => $code,
-			#[allow(unreachable_patterns)]
-			_ => {
-				let _ = $client;
-
-				Err(Error::CommandNotImplemented)
-			},
-		}
-	};
-}
-
 /// Runs performance checks.
 /// Should only be used in release build since the check would take too much time otherwise.
 fn host_perf_check() -> Result<()> {
@@ -540,15 +516,12 @@ pub fn run() -> Result<()> {
 					let db = backend.expose_db();
 					let storage = backend.expose_storage();
 
-					unwrap_client!(
-						client,
-						cmd.run(config, client.clone(), db, storage).map_err(Error::SubstrateCli)
-					)
+					cmd.run(config, client.clone(), db, storage).map_err(Error::SubstrateCli)
 				}),
 				BenchmarkCmd::Block(cmd) => runner.sync_run(|mut config| {
 					let (client, _, _, _) = service::new_chain_ops(&mut config, None)?;
 
-					unwrap_client!(client, cmd.run(client.clone()).map_err(Error::SubstrateCli))
+					cmd.run(client.clone()).map_err(Error::SubstrateCli)
 				}),
 				// These commands are very similar and can be handled in nearly the same way.
 				BenchmarkCmd::Extrinsic(_) | BenchmarkCmd::Overhead(_) => {
@@ -558,14 +531,15 @@ pub fn run() -> Result<()> {
 						let header = client.header(client.info().genesis_hash).unwrap().unwrap();
 						let inherent_data = benchmark_inherent_data(header)
 							.map_err(|e| format!("generating inherent data: {:?}", e))?;
-						let remark_builder = RemarkBuilder::new(client.clone());
+						let remark_builder =
+							RemarkBuilder::new(client.clone(), config.chain_spec.identify_chain());
 
 						match cmd {
 							BenchmarkCmd::Extrinsic(cmd) => {
 								let tka_builder = TransferKeepAliveBuilder::new(
 									client.clone(),
 									Sr25519Keyring::Alice.to_account_id(),
-									client.existential_deposit(),
+									config.chain_spec.identify_chain(),
 								);
 
 								let ext_factory = ExtrinsicFactory(vec![
@@ -573,28 +547,18 @@ pub fn run() -> Result<()> {
 									Box::new(tka_builder),
 								]);
 
-								unwrap_client!(
-									client,
-									cmd.run(
-										client.clone(),
-										inherent_data,
-										Vec::new(),
-										&ext_factory
-									)
+								cmd.run(client.clone(), inherent_data, Vec::new(), &ext_factory)
 									.map_err(Error::SubstrateCli)
-								)
 							},
-							BenchmarkCmd::Overhead(cmd) => unwrap_client!(
-								client,
-								cmd.run(
+							BenchmarkCmd::Overhead(cmd) => cmd
+								.run(
 									config,
 									client.clone(),
 									inherent_data,
 									Vec::new(),
-									&remark_builder
+									&remark_builder,
 								)
-								.map_err(Error::SubstrateCli)
-							),
+								.map_err(Error::SubstrateCli),
 							_ => unreachable!("Ensured by the outside match; qed"),
 						}
 					})
@@ -637,17 +601,12 @@ pub fn run() -> Result<()> {
 		Some(Subcommand::Key(cmd)) => Ok(cmd.run(&cli)?),
 		#[cfg(feature = "try-runtime")]
 		Some(Subcommand::TryRuntime(cmd)) => {
-			use sc_executor::{sp_wasm_interface::ExtendedHostFunctions, NativeExecutionDispatch};
 			use sc_service::TaskManager;
 			use try_runtime_cli::block_building_info::timestamp_with_babe_info;
 
 			let runner = cli.create_runner(cmd)?;
 			let chain_spec = &runner.config().chain_spec;
 			set_default_ss58_version(chain_spec);
-			type HostFunctionsOf<E> = ExtendedHostFunctions<
-				sp_io::SubstrateHostFunctions,
-				<E as NativeExecutionDispatch>::ExtendHostFunctions,
-			>;
 
 			let registry = &runner.config().prometheus_config.as_ref().map(|cfg| &cfg.registry);
 			let task_manager = TaskManager::new(runner.config().tokio_handle.clone(), *registry)
@@ -659,7 +618,7 @@ pub fn run() -> Result<()> {
 			if chain_spec.is_kusama() {
 				return runner.async_run(|_| {
 					Ok((
-						cmd.run::<service::kusama_runtime::Block, HostFunctionsOf<service::KusamaExecutorDispatch>, _>(
+						cmd.run::<service::kusama_runtime::Block, sp_io::SubstrateHostFunctions, _>(
 							Some(timestamp_with_babe_info(service::kusama_runtime_constants::time::MILLISECS_PER_BLOCK))
 						)
 						.map_err(Error::SubstrateCli),
@@ -672,7 +631,7 @@ pub fn run() -> Result<()> {
 			if chain_spec.is_westend() {
 				return runner.async_run(|_| {
 					Ok((
-						cmd.run::<service::westend_runtime::Block, HostFunctionsOf<service::WestendExecutorDispatch>, _>(
+						cmd.run::<service::westend_runtime::Block, sp_io::SubstrateHostFunctions, _>(
 							Some(timestamp_with_babe_info(service::westend_runtime_constants::time::MILLISECS_PER_BLOCK))
 						)
 						.map_err(Error::SubstrateCli),
@@ -685,7 +644,7 @@ pub fn run() -> Result<()> {
 			{
 				return runner.async_run(|_| {
 					Ok((
-						cmd.run::<service::polkadot_runtime::Block, HostFunctionsOf<service::PolkadotExecutorDispatch>, _>(
+						cmd.run::<service::polkadot_runtime::Block, sp_io::SubstrateHostFunctions, _>(
 							Some(timestamp_with_babe_info(service::polkadot_runtime_constants::time::MILLISECS_PER_BLOCK))
 						)
 						.map_err(Error::SubstrateCli),
diff --git a/polkadot/cli/src/lib.rs b/polkadot/cli/src/lib.rs
index 8a859c1b2bd2a42e131dc50e62ba75fc5163638d..057592fa8a10ea79939b66bad8f6adc2e7476059 100644
--- a/polkadot/cli/src/lib.rs
+++ b/polkadot/cli/src/lib.rs
@@ -27,8 +27,6 @@ mod error;
 #[cfg(all(feature = "hostperfcheck", build_type = "release"))]
 mod host_perf_check;
 
-#[cfg(feature = "full-node")]
-pub use service::RuntimeApiCollection;
 #[cfg(feature = "service")]
 pub use service::{self, Block, CoreApi, IdentifyVariant, ProvideRuntimeApi, TFullClient};
 
diff --git a/polkadot/node/client/Cargo.toml b/polkadot/node/client/Cargo.toml
deleted file mode 100644
index 3b4e8e725ae50a8384ea3d38f8f90e4d1f4729eb..0000000000000000000000000000000000000000
--- a/polkadot/node/client/Cargo.toml
+++ /dev/null
@@ -1,63 +0,0 @@
-[package]
-name = "polkadot-client"
-version.workspace = true
-authors.workspace = true
-edition.workspace = true
-
-[dependencies]
-async-trait = "0.1.57"
-futures = "0.3.21"
-frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "master" }
-frame-benchmarking-cli = { git = "https://github.com/paritytech/substrate", branch = "master" }
-pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", branch = "master" }
-pallet-transaction-payment-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
-frame-system = { git = "https://github.com/paritytech/substrate", branch = "master" }
-frame-system-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
-
-sp-consensus = { git = "https://github.com/paritytech/substrate", branch = "master" }
-sp-storage = { git = "https://github.com/paritytech/substrate", branch = "master" }
-sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" }
-sp-blockchain = { git = "https://github.com/paritytech/substrate", branch = "master" }
-sp-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
-sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
-sp-keyring = { git = "https://github.com/paritytech/substrate", branch = "master" }
-sp-inherents = { git = "https://github.com/paritytech/substrate", branch = "master" }
-sp-timestamp = { git = "https://github.com/paritytech/substrate", branch = "master" }
-sp-session = { git = "https://github.com/paritytech/substrate", branch = "master" }
-sp-authority-discovery = { git = "https://github.com/paritytech/substrate", branch = "master" }
-sp-consensus-babe = { git = "https://github.com/paritytech/substrate", branch = "master" }
-sp-consensus-beefy = { git = "https://github.com/paritytech/substrate", branch = "master" }
-sp-consensus-grandpa = { git = "https://github.com/paritytech/substrate", branch = "master" }
-sp-transaction-pool = { git = "https://github.com/paritytech/substrate", branch = "master" }
-sp-offchain = { package = "sp-offchain", git = "https://github.com/paritytech/substrate", branch = "master" }
-sp-block-builder = { git = "https://github.com/paritytech/substrate", branch = "master" }
-sp-mmr-primitives = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
-
-sc-consensus = { git = "https://github.com/paritytech/substrate", branch = "master" }
-sc-executor = { git = "https://github.com/paritytech/substrate", branch = "master" }
-sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
-sc-service = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
-
-# Polkadot Runtimes
-polkadot-runtime = { path = "../../runtime/polkadot", optional = true }
-kusama-runtime = { path = "../../runtime/kusama", optional = true }
-westend-runtime = { path = "../../runtime/westend", optional = true }
-rococo-runtime = { path = "../../runtime/rococo", optional = true }
-
-polkadot-core-primitives = { path = "../../core-primitives" }
-polkadot-primitives = { path = "../../primitives" }
-polkadot-node-core-parachains-inherent = { path = "../core/parachains-inherent" }
-polkadot-runtime-common = { path = "../../runtime/common" }
-
-[features]
-default = ["polkadot"]
-polkadot = ["polkadot-runtime"]
-kusama = ["kusama-runtime"]
-rococo = ["rococo-runtime"]
-westend = ["westend-runtime"]
-runtime-metrics = [
-    "rococo-runtime/runtime-metrics",
-    "kusama-runtime/runtime-metrics",
-    "westend-runtime/runtime-metrics",
-    "polkadot-runtime/runtime-metrics",
-]
diff --git a/polkadot/node/client/src/benchmarking.rs b/polkadot/node/client/src/benchmarking.rs
deleted file mode 100644
index 69927c11a913d4914fd8798906eac7b85cc76f22..0000000000000000000000000000000000000000
--- a/polkadot/node/client/src/benchmarking.rs
+++ /dev/null
@@ -1,390 +0,0 @@
-// Copyright (C) Parity Technologies (UK) Ltd.
-// This file is part of Polkadot.
-
-// Polkadot 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.
-
-// Polkadot 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 Polkadot.  If not, see <http://www.gnu.org/licenses/>.
-
-//! Code related to benchmarking a [`crate::Client`].
-
-use polkadot_primitives::{AccountId, Balance};
-use sp_core::{Pair, H256};
-use sp_keyring::Sr25519Keyring;
-use sp_runtime::OpaqueExtrinsic;
-
-use crate::*;
-
-/// Generates `System::Remark` extrinsics for the benchmarks.
-///
-/// Note: Should only be used for benchmarking.
-pub struct RemarkBuilder {
-	client: Arc<Client>,
-}
-
-impl RemarkBuilder {
-	/// Creates a new [`Self`] from the given client.
-	pub fn new(client: Arc<Client>) -> Self {
-		Self { client }
-	}
-}
-
-impl frame_benchmarking_cli::ExtrinsicBuilder for RemarkBuilder {
-	fn pallet(&self) -> &str {
-		"system"
-	}
-
-	fn extrinsic(&self) -> &str {
-		"remark"
-	}
-
-	fn build(&self, nonce: u32) -> std::result::Result<OpaqueExtrinsic, &'static str> {
-		with_client! {
-			self.client.as_ref(), client, {
-				use runtime::{RuntimeCall, SystemCall};
-
-				let call = RuntimeCall::System(SystemCall::remark { remark: vec![] });
-				let signer = Sr25519Keyring::Bob.pair();
-
-				let period = polkadot_runtime_common::BlockHashCount::get().checked_next_power_of_two().map(|c| c / 2).unwrap_or(2) as u64;
-				let genesis = client.usage_info().chain.best_hash;
-
-				Ok(client.sign_call(call, nonce, 0, period, genesis, signer))
-			}
-		}
-	}
-}
-
-/// Generates `Balances::TransferKeepAlive` extrinsics for the benchmarks.
-///
-/// Note: Should only be used for benchmarking.
-pub struct TransferKeepAliveBuilder {
-	client: Arc<Client>,
-	dest: AccountId,
-	value: Balance,
-}
-
-impl TransferKeepAliveBuilder {
-	/// Creates a new [`Self`] from the given client and the arguments for the extrinsics.
-
-	pub fn new(client: Arc<Client>, dest: AccountId, value: Balance) -> Self {
-		Self { client, dest, value }
-	}
-}
-
-impl frame_benchmarking_cli::ExtrinsicBuilder for TransferKeepAliveBuilder {
-	fn pallet(&self) -> &str {
-		"balances"
-	}
-
-	fn extrinsic(&self) -> &str {
-		"transfer_keep_alive"
-	}
-
-	fn build(&self, nonce: u32) -> std::result::Result<OpaqueExtrinsic, &'static str> {
-		with_client! {
-			self.client.as_ref(), client, {
-				use runtime::{RuntimeCall, BalancesCall};
-
-				let call = RuntimeCall::Balances(BalancesCall::transfer_keep_alive {
-					dest: self.dest.clone().into(),
-					value: self.value.into(),
-				});
-				let signer = Sr25519Keyring::Bob.pair();
-
-				let period = polkadot_runtime_common::BlockHashCount::get().checked_next_power_of_two().map(|c| c / 2).unwrap_or(2) as u64;
-				let genesis = client.usage_info().chain.best_hash;
-
-				Ok(client.sign_call(call, nonce, 0, period, genesis, signer))
-			}
-		}
-	}
-}
-
-/// Helper trait to implement [`frame_benchmarking_cli::ExtrinsicBuilder`].
-///
-/// Should only be used for benchmarking since it makes strong assumptions
-/// about the chain state that these calls will be valid for.
-trait BenchmarkCallSigner<RuntimeCall: Encode + Clone, Signer: Pair> {
-	/// Signs a call together with the signed extensions of the specific runtime.
-	///
-	/// Only works if the current block is the genesis block since the
-	/// `CheckMortality` check is mocked by using the genesis block.
-	fn sign_call(
-		&self,
-		call: RuntimeCall,
-		nonce: u32,
-		current_block: u64,
-		period: u64,
-		genesis: H256,
-		acc: Signer,
-	) -> OpaqueExtrinsic;
-}
-
-#[cfg(feature = "polkadot")]
-impl BenchmarkCallSigner<polkadot_runtime::RuntimeCall, sp_core::sr25519::Pair>
-	for FullClient<polkadot_runtime::RuntimeApi, PolkadotExecutorDispatch>
-{
-	fn sign_call(
-		&self,
-		call: polkadot_runtime::RuntimeCall,
-		nonce: u32,
-		current_block: u64,
-		period: u64,
-		genesis: H256,
-		acc: sp_core::sr25519::Pair,
-	) -> OpaqueExtrinsic {
-		use polkadot_runtime as runtime;
-
-		let extra: runtime::SignedExtra = (
-			frame_system::CheckNonZeroSender::<runtime::Runtime>::new(),
-			frame_system::CheckSpecVersion::<runtime::Runtime>::new(),
-			frame_system::CheckTxVersion::<runtime::Runtime>::new(),
-			frame_system::CheckGenesis::<runtime::Runtime>::new(),
-			frame_system::CheckMortality::<runtime::Runtime>::from(
-				sp_runtime::generic::Era::mortal(period, current_block),
-			),
-			frame_system::CheckNonce::<runtime::Runtime>::from(nonce),
-			frame_system::CheckWeight::<runtime::Runtime>::new(),
-			pallet_transaction_payment::ChargeTransactionPayment::<runtime::Runtime>::from(0),
-			polkadot_runtime_common::claims::PrevalidateAttests::<runtime::Runtime>::new(),
-		);
-
-		let payload = runtime::SignedPayload::from_raw(
-			call.clone(),
-			extra.clone(),
-			(
-				(),
-				runtime::VERSION.spec_version,
-				runtime::VERSION.transaction_version,
-				genesis,
-				genesis,
-				(),
-				(),
-				(),
-				(),
-			),
-		);
-
-		let signature = payload.using_encoded(|p| acc.sign(p));
-		runtime::UncheckedExtrinsic::new_signed(
-			call,
-			sp_runtime::AccountId32::from(acc.public()).into(),
-			polkadot_core_primitives::Signature::Sr25519(signature.clone()),
-			extra,
-		)
-		.into()
-	}
-}
-
-#[cfg(feature = "westend")]
-impl BenchmarkCallSigner<westend_runtime::RuntimeCall, sp_core::sr25519::Pair>
-	for FullClient<westend_runtime::RuntimeApi, WestendExecutorDispatch>
-{
-	fn sign_call(
-		&self,
-		call: westend_runtime::RuntimeCall,
-		nonce: u32,
-		current_block: u64,
-		period: u64,
-		genesis: H256,
-		acc: sp_core::sr25519::Pair,
-	) -> OpaqueExtrinsic {
-		use westend_runtime as runtime;
-
-		let extra: runtime::SignedExtra = (
-			frame_system::CheckNonZeroSender::<runtime::Runtime>::new(),
-			frame_system::CheckSpecVersion::<runtime::Runtime>::new(),
-			frame_system::CheckTxVersion::<runtime::Runtime>::new(),
-			frame_system::CheckGenesis::<runtime::Runtime>::new(),
-			frame_system::CheckMortality::<runtime::Runtime>::from(
-				sp_runtime::generic::Era::mortal(period, current_block),
-			),
-			frame_system::CheckNonce::<runtime::Runtime>::from(nonce),
-			frame_system::CheckWeight::<runtime::Runtime>::new(),
-			pallet_transaction_payment::ChargeTransactionPayment::<runtime::Runtime>::from(0),
-		);
-
-		let payload = runtime::SignedPayload::from_raw(
-			call.clone(),
-			extra.clone(),
-			(
-				(),
-				runtime::VERSION.spec_version,
-				runtime::VERSION.transaction_version,
-				genesis,
-				genesis,
-				(),
-				(),
-				(),
-			),
-		);
-
-		let signature = payload.using_encoded(|p| acc.sign(p));
-		runtime::UncheckedExtrinsic::new_signed(
-			call,
-			sp_runtime::AccountId32::from(acc.public()).into(),
-			polkadot_core_primitives::Signature::Sr25519(signature.clone()),
-			extra,
-		)
-		.into()
-	}
-}
-
-#[cfg(feature = "kusama")]
-impl BenchmarkCallSigner<kusama_runtime::RuntimeCall, sp_core::sr25519::Pair>
-	for FullClient<kusama_runtime::RuntimeApi, KusamaExecutorDispatch>
-{
-	fn sign_call(
-		&self,
-		call: kusama_runtime::RuntimeCall,
-		nonce: u32,
-		current_block: u64,
-		period: u64,
-		genesis: H256,
-		acc: sp_core::sr25519::Pair,
-	) -> OpaqueExtrinsic {
-		use kusama_runtime as runtime;
-
-		let extra: runtime::SignedExtra = (
-			frame_system::CheckNonZeroSender::<runtime::Runtime>::new(),
-			frame_system::CheckSpecVersion::<runtime::Runtime>::new(),
-			frame_system::CheckTxVersion::<runtime::Runtime>::new(),
-			frame_system::CheckGenesis::<runtime::Runtime>::new(),
-			frame_system::CheckMortality::<runtime::Runtime>::from(
-				sp_runtime::generic::Era::mortal(period, current_block),
-			),
-			frame_system::CheckNonce::<runtime::Runtime>::from(nonce),
-			frame_system::CheckWeight::<runtime::Runtime>::new(),
-			pallet_transaction_payment::ChargeTransactionPayment::<runtime::Runtime>::from(0),
-		);
-
-		let payload = runtime::SignedPayload::from_raw(
-			call.clone(),
-			extra.clone(),
-			(
-				(),
-				runtime::VERSION.spec_version,
-				runtime::VERSION.transaction_version,
-				genesis,
-				genesis,
-				(),
-				(),
-				(),
-			),
-		);
-
-		let signature = payload.using_encoded(|p| acc.sign(p));
-		runtime::UncheckedExtrinsic::new_signed(
-			call,
-			sp_runtime::AccountId32::from(acc.public()).into(),
-			polkadot_core_primitives::Signature::Sr25519(signature.clone()),
-			extra,
-		)
-		.into()
-	}
-}
-
-#[cfg(feature = "rococo")]
-impl BenchmarkCallSigner<rococo_runtime::RuntimeCall, sp_core::sr25519::Pair>
-	for FullClient<rococo_runtime::RuntimeApi, RococoExecutorDispatch>
-{
-	fn sign_call(
-		&self,
-		call: rococo_runtime::RuntimeCall,
-		nonce: u32,
-		current_block: u64,
-		period: u64,
-		genesis: H256,
-		acc: sp_core::sr25519::Pair,
-	) -> OpaqueExtrinsic {
-		use rococo_runtime as runtime;
-
-		let extra: runtime::SignedExtra = (
-			frame_system::CheckNonZeroSender::<runtime::Runtime>::new(),
-			frame_system::CheckSpecVersion::<runtime::Runtime>::new(),
-			frame_system::CheckTxVersion::<runtime::Runtime>::new(),
-			frame_system::CheckGenesis::<runtime::Runtime>::new(),
-			frame_system::CheckMortality::<runtime::Runtime>::from(
-				sp_runtime::generic::Era::mortal(period, current_block),
-			),
-			frame_system::CheckNonce::<runtime::Runtime>::from(nonce),
-			frame_system::CheckWeight::<runtime::Runtime>::new(),
-			pallet_transaction_payment::ChargeTransactionPayment::<runtime::Runtime>::from(0),
-		);
-
-		let payload = runtime::SignedPayload::from_raw(
-			call.clone(),
-			extra.clone(),
-			(
-				(),
-				runtime::VERSION.spec_version,
-				runtime::VERSION.transaction_version,
-				genesis,
-				genesis,
-				(),
-				(),
-				(),
-			),
-		);
-
-		let signature = payload.using_encoded(|p| acc.sign(p));
-		runtime::UncheckedExtrinsic::new_signed(
-			call,
-			sp_runtime::AccountId32::from(acc.public()).into(),
-			polkadot_core_primitives::Signature::Sr25519(signature.clone()),
-			extra,
-		)
-		.into()
-	}
-}
-
-/// Generates inherent data for benchmarking Polkadot, Kusama, Westend and Rococo.
-///
-/// Not to be used outside of benchmarking since it returns mocked values.
-pub fn benchmark_inherent_data(
-	header: polkadot_core_primitives::Header,
-) -> std::result::Result<sp_inherents::InherentData, sp_inherents::Error> {
-	use sp_inherents::InherentDataProvider;
-	let mut inherent_data = sp_inherents::InherentData::new();
-
-	// Assume that all runtimes have the `timestamp` pallet.
-	let d = std::time::Duration::from_millis(0);
-	let timestamp = sp_timestamp::InherentDataProvider::new(d.into());
-	futures::executor::block_on(timestamp.provide_inherent_data(&mut inherent_data))?;
-
-	let para_data = polkadot_primitives::InherentData {
-		bitfields: Vec::new(),
-		backed_candidates: Vec::new(),
-		disputes: Vec::new(),
-		parent_header: header,
-	};
-
-	inherent_data.put_data(polkadot_primitives::PARACHAINS_INHERENT_IDENTIFIER, &para_data)?;
-
-	Ok(inherent_data)
-}
-
-/// Provides the existential deposit that is only needed for benchmarking.
-pub trait ExistentialDepositProvider {
-	/// Returns the existential deposit.
-	fn existential_deposit(&self) -> Balance;
-}
-
-impl ExistentialDepositProvider for Client {
-	fn existential_deposit(&self) -> Balance {
-		with_client! {
-			self,
-			_client,
-			runtime::ExistentialDeposit::get()
-		}
-	}
-}
diff --git a/polkadot/node/client/src/lib.rs b/polkadot/node/client/src/lib.rs
deleted file mode 100644
index 1ef0e7f6c022d87b2128d3220dfc9109e08b2fe1..0000000000000000000000000000000000000000
--- a/polkadot/node/client/src/lib.rs
+++ /dev/null
@@ -1,590 +0,0 @@
-// Copyright (C) Parity Technologies (UK) Ltd.
-// This file is part of Polkadot.
-
-// Polkadot 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.
-
-// Polkadot 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 Polkadot.  If not, see <http://www.gnu.org/licenses/>.
-
-//! Polkadot Client
-//!
-//! Provides the [`AbstractClient`] trait that is a super trait that combines all the traits the client implements.
-//! There is also the [`Client`] enum that combines all the different clients into one common structure.
-
-use polkadot_primitives::{
-	runtime_api::ParachainHost, AccountId, Balance, Block, BlockNumber, Hash, Header, Nonce,
-};
-use sc_client_api::{
-	AuxStore, Backend as BackendT, BlockchainEvents, KeysIter, PairsIter, UsageProvider,
-};
-use sc_executor::NativeElseWasmExecutor;
-use sp_api::{CallApiAt, Encode, NumberFor, ProvideRuntimeApi};
-use sp_blockchain::{HeaderBackend, HeaderMetadata};
-use sp_consensus::BlockStatus;
-use sp_runtime::{
-	generic::SignedBlock,
-	traits::{BlakeTwo256, Block as BlockT},
-	Justifications,
-};
-use sp_storage::{ChildInfo, StorageData, StorageKey};
-use std::sync::Arc;
-
-pub mod benchmarking;
-
-pub type FullBackend = sc_service::TFullBackend<Block>;
-
-pub type FullClient<RuntimeApi, ExecutorDispatch> =
-	sc_service::TFullClient<Block, RuntimeApi, NativeElseWasmExecutor<ExecutorDispatch>>;
-
-#[cfg(not(any(
-	feature = "rococo",
-	feature = "kusama",
-	feature = "westend",
-	feature = "polkadot"
-)))]
-compile_error!("at least one runtime feature must be enabled");
-
-/// The native executor instance for Polkadot.
-#[cfg(feature = "polkadot")]
-pub struct PolkadotExecutorDispatch;
-
-#[cfg(feature = "polkadot")]
-impl sc_executor::NativeExecutionDispatch for PolkadotExecutorDispatch {
-	type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions;
-
-	fn dispatch(method: &str, data: &[u8]) -> Option<Vec<u8>> {
-		polkadot_runtime::api::dispatch(method, data)
-	}
-
-	fn native_version() -> sc_executor::NativeVersion {
-		polkadot_runtime::native_version()
-	}
-}
-
-#[cfg(feature = "kusama")]
-/// The native executor instance for Kusama.
-pub struct KusamaExecutorDispatch;
-
-#[cfg(feature = "kusama")]
-impl sc_executor::NativeExecutionDispatch for KusamaExecutorDispatch {
-	type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions;
-
-	fn dispatch(method: &str, data: &[u8]) -> Option<Vec<u8>> {
-		kusama_runtime::api::dispatch(method, data)
-	}
-
-	fn native_version() -> sc_executor::NativeVersion {
-		kusama_runtime::native_version()
-	}
-}
-
-#[cfg(feature = "westend")]
-/// The native executor instance for Westend.
-pub struct WestendExecutorDispatch;
-
-#[cfg(feature = "westend")]
-impl sc_executor::NativeExecutionDispatch for WestendExecutorDispatch {
-	type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions;
-
-	fn dispatch(method: &str, data: &[u8]) -> Option<Vec<u8>> {
-		westend_runtime::api::dispatch(method, data)
-	}
-
-	fn native_version() -> sc_executor::NativeVersion {
-		westend_runtime::native_version()
-	}
-}
-
-#[cfg(feature = "rococo")]
-/// The native executor instance for Rococo.
-pub struct RococoExecutorDispatch;
-
-#[cfg(feature = "rococo")]
-impl sc_executor::NativeExecutionDispatch for RococoExecutorDispatch {
-	type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions;
-
-	fn dispatch(method: &str, data: &[u8]) -> Option<Vec<u8>> {
-		rococo_runtime::api::dispatch(method, data)
-	}
-
-	fn native_version() -> sc_executor::NativeVersion {
-		rococo_runtime::native_version()
-	}
-}
-
-/// A set of APIs that polkadot-like runtimes must implement.
-pub trait RuntimeApiCollection:
-	sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block>
-	+ sp_api::ApiExt<Block>
-	+ sp_consensus_babe::BabeApi<Block>
-	+ sp_consensus_grandpa::GrandpaApi<Block>
-	+ ParachainHost<Block>
-	+ sp_block_builder::BlockBuilder<Block>
-	+ frame_system_rpc_runtime_api::AccountNonceApi<Block, AccountId, Nonce>
-	+ sp_mmr_primitives::MmrApi<Block, <Block as BlockT>::Hash, BlockNumber>
-	+ pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<Block, Balance>
-	+ sp_api::Metadata<Block>
-	+ sp_offchain::OffchainWorkerApi<Block>
-	+ sp_session::SessionKeys<Block>
-	+ sp_authority_discovery::AuthorityDiscoveryApi<Block>
-	+ sp_consensus_beefy::BeefyApi<Block>
-where
-	<Self as sp_api::ApiExt<Block>>::StateBackend: sp_api::StateBackend<BlakeTwo256>,
-{
-}
-
-impl<Api> RuntimeApiCollection for Api
-where
-	Api: sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block>
-		+ sp_api::ApiExt<Block>
-		+ sp_consensus_babe::BabeApi<Block>
-		+ sp_consensus_grandpa::GrandpaApi<Block>
-		+ ParachainHost<Block>
-		+ sp_block_builder::BlockBuilder<Block>
-		+ frame_system_rpc_runtime_api::AccountNonceApi<Block, AccountId, Nonce>
-		+ sp_mmr_primitives::MmrApi<Block, <Block as BlockT>::Hash, BlockNumber>
-		+ pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<Block, Balance>
-		+ sp_api::Metadata<Block>
-		+ sp_offchain::OffchainWorkerApi<Block>
-		+ sp_session::SessionKeys<Block>
-		+ sp_authority_discovery::AuthorityDiscoveryApi<Block>
-		+ sp_consensus_beefy::BeefyApi<Block>,
-	<Self as sp_api::ApiExt<Block>>::StateBackend: sp_api::StateBackend<BlakeTwo256>,
-{
-}
-
-/// Trait that abstracts over all available client implementations.
-///
-/// For a concrete type there exists [`Client`].
-pub trait AbstractClient<Block, Backend>:
-	BlockchainEvents<Block>
-	+ Sized
-	+ Send
-	+ Sync
-	+ ProvideRuntimeApi<Block>
-	+ HeaderBackend<Block>
-	+ CallApiAt<Block, StateBackend = Backend::State>
-	+ AuxStore
-	+ UsageProvider<Block>
-	+ HeaderMetadata<Block, Error = sp_blockchain::Error>
-where
-	Block: BlockT,
-	Backend: BackendT<Block>,
-	Backend::State: sp_api::StateBackend<BlakeTwo256>,
-	Self::Api: RuntimeApiCollection<StateBackend = Backend::State>,
-{
-}
-
-impl<Block, Backend, Client> AbstractClient<Block, Backend> for Client
-where
-	Block: BlockT,
-	Backend: BackendT<Block>,
-	Backend::State: sp_api::StateBackend<BlakeTwo256>,
-	Client: BlockchainEvents<Block>
-		+ ProvideRuntimeApi<Block>
-		+ HeaderBackend<Block>
-		+ AuxStore
-		+ UsageProvider<Block>
-		+ Sized
-		+ Send
-		+ Sync
-		+ CallApiAt<Block, StateBackend = Backend::State>
-		+ HeaderMetadata<Block, Error = sp_blockchain::Error>,
-	Client::Api: RuntimeApiCollection<StateBackend = Backend::State>,
-{
-}
-
-/// Execute something with the client instance.
-///
-/// As there exist multiple chains inside Polkadot, like Polkadot itself, Kusama, Westend etc,
-/// there can exist different kinds of client types. As these client types differ in the generics
-/// that are being used, we can not easily return them from a function. For returning them from a
-/// function there exists [`Client`]. However, the problem on how to use this client instance still
-/// exists. This trait "solves" it in a dirty way. It requires a type to implement this trait and
-/// than the [`execute_with_client`](ExecuteWithClient::execute_with_client) function can be called
-/// with any possible client instance.
-///
-/// In a perfect world, we could make a closure work in this way.
-pub trait ExecuteWithClient {
-	/// The return type when calling this instance.
-	type Output;
-
-	/// Execute whatever should be executed with the given client instance.
-	fn execute_with_client<Client, Api, Backend>(self, client: Arc<Client>) -> Self::Output
-	where
-		<Api as sp_api::ApiExt<Block>>::StateBackend: sp_api::StateBackend<BlakeTwo256>,
-		Backend: sc_client_api::Backend<Block> + 'static,
-		Backend::State: sp_api::StateBackend<BlakeTwo256>,
-		Api: crate::RuntimeApiCollection<StateBackend = Backend::State>,
-		Client: AbstractClient<Block, Backend, Api = Api> + 'static;
-}
-
-/// A handle to a Polkadot client instance.
-///
-/// The Polkadot service supports multiple different runtimes (Westend, Polkadot itself, etc). As each runtime has a
-/// specialized client, we need to hide them behind a trait. This is this trait.
-///
-/// When wanting to work with the inner client, you need to use `execute_with`.
-///
-/// See [`ExecuteWithClient`](trait.ExecuteWithClient.html) for more information.
-pub trait ClientHandle {
-	/// Execute the given something with the client.
-	fn execute_with<T: ExecuteWithClient>(&self, t: T) -> T::Output;
-}
-
-/// Unwraps a [`Client`] into the concrete client type and
-/// provides the concrete runtime as `runtime`.
-macro_rules! with_client {
-	{
-		// The client instance that should be unwrapped.
-		$self:expr,
-		// The name that the unwrapped client will have.
-		$client:ident,
-		// NOTE: Using an expression here is fine since blocks are also expressions.
-		$code:expr
-	} => {
-		match $self {
-			#[cfg(feature = "polkadot")]
-			Client::Polkadot($client) => {
-				#[allow(unused_imports)]
-				use polkadot_runtime as runtime;
-
-				$code
-			},
-			#[cfg(feature = "westend")]
-			Client::Westend($client) => {
-				#[allow(unused_imports)]
-				use westend_runtime as runtime;
-
-				$code
-			},
-			#[cfg(feature = "kusama")]
-			Client::Kusama($client) => {
-				#[allow(unused_imports)]
-				use kusama_runtime as runtime;
-
-				$code
-			},
-			#[cfg(feature = "rococo")]
-			Client::Rococo($client) => {
-				#[allow(unused_imports)]
-				use rococo_runtime as runtime;
-
-				$code
-			},
-		}
-	}
-}
-// Make the macro available only within this crate.
-pub(crate) use with_client;
-
-/// A client instance of Polkadot.
-///
-/// See [`ExecuteWithClient`] for more information.
-#[derive(Clone)]
-pub enum Client {
-	#[cfg(feature = "polkadot")]
-	Polkadot(Arc<FullClient<polkadot_runtime::RuntimeApi, PolkadotExecutorDispatch>>),
-	#[cfg(feature = "westend")]
-	Westend(Arc<FullClient<westend_runtime::RuntimeApi, WestendExecutorDispatch>>),
-	#[cfg(feature = "kusama")]
-	Kusama(Arc<FullClient<kusama_runtime::RuntimeApi, KusamaExecutorDispatch>>),
-	#[cfg(feature = "rococo")]
-	Rococo(Arc<FullClient<rococo_runtime::RuntimeApi, RococoExecutorDispatch>>),
-}
-
-impl ClientHandle for Client {
-	fn execute_with<T: ExecuteWithClient>(&self, t: T) -> T::Output {
-		with_client! {
-			self,
-			client,
-			{
-				T::execute_with_client::<_, _, FullBackend>(t, client.clone())
-			}
-		}
-	}
-}
-
-impl UsageProvider<Block> for Client {
-	fn usage_info(&self) -> sc_client_api::ClientInfo<Block> {
-		with_client! {
-			self,
-			client,
-			{
-				client.usage_info()
-			}
-		}
-	}
-}
-
-impl sc_client_api::BlockBackend<Block> for Client {
-	fn block_body(
-		&self,
-		hash: <Block as BlockT>::Hash,
-	) -> sp_blockchain::Result<Option<Vec<<Block as BlockT>::Extrinsic>>> {
-		with_client! {
-			self,
-			client,
-			{
-				client.block_body(hash)
-			}
-		}
-	}
-
-	fn block(
-		&self,
-		hash: <Block as BlockT>::Hash,
-	) -> sp_blockchain::Result<Option<SignedBlock<Block>>> {
-		with_client! {
-			self,
-			client,
-			{
-				client.block(hash)
-			}
-		}
-	}
-
-	fn block_status(&self, hash: <Block as BlockT>::Hash) -> sp_blockchain::Result<BlockStatus> {
-		with_client! {
-			self,
-			client,
-			{
-				client.block_status(hash)
-			}
-		}
-	}
-
-	fn justifications(
-		&self,
-		hash: <Block as BlockT>::Hash,
-	) -> sp_blockchain::Result<Option<Justifications>> {
-		with_client! {
-			self,
-			client,
-			{
-				client.justifications(hash)
-			}
-		}
-	}
-
-	fn block_hash(
-		&self,
-		number: NumberFor<Block>,
-	) -> sp_blockchain::Result<Option<<Block as BlockT>::Hash>> {
-		with_client! {
-			self,
-			client,
-			{
-				client.block_hash(number)
-			}
-		}
-	}
-
-	fn indexed_transaction(
-		&self,
-		id: <Block as BlockT>::Hash,
-	) -> sp_blockchain::Result<Option<Vec<u8>>> {
-		with_client! {
-			self,
-			client,
-			{
-				client.indexed_transaction(id)
-			}
-		}
-	}
-
-	fn block_indexed_body(
-		&self,
-		id: <Block as BlockT>::Hash,
-	) -> sp_blockchain::Result<Option<Vec<Vec<u8>>>> {
-		with_client! {
-			self,
-			client,
-			{
-				client.block_indexed_body(id)
-			}
-		}
-	}
-
-	fn requires_full_sync(&self) -> bool {
-		with_client! {
-			self,
-			client,
-			{
-				client.requires_full_sync()
-			}
-		}
-	}
-}
-
-impl sc_client_api::StorageProvider<Block, crate::FullBackend> for Client {
-	fn storage(
-		&self,
-		hash: <Block as BlockT>::Hash,
-		key: &StorageKey,
-	) -> sp_blockchain::Result<Option<StorageData>> {
-		with_client! {
-			self,
-			client,
-			{
-				client.storage(hash, key)
-			}
-		}
-	}
-
-	fn storage_hash(
-		&self,
-		hash: <Block as BlockT>::Hash,
-		key: &StorageKey,
-	) -> sp_blockchain::Result<Option<<Block as BlockT>::Hash>> {
-		with_client! {
-			self,
-			client,
-			{
-				client.storage_hash(hash, key)
-			}
-		}
-	}
-
-	fn storage_pairs(
-		&self,
-		hash: <Block as BlockT>::Hash,
-		key_prefix: Option<&StorageKey>,
-		start_key: Option<&StorageKey>,
-	) -> sp_blockchain::Result<
-		PairsIter<<crate::FullBackend as sc_client_api::Backend<Block>>::State, Block>,
-	> {
-		with_client! {
-			self,
-			client,
-			{
-				client.storage_pairs(hash, key_prefix, start_key)
-			}
-		}
-	}
-
-	fn storage_keys(
-		&self,
-		hash: <Block as BlockT>::Hash,
-		prefix: Option<&StorageKey>,
-		start_key: Option<&StorageKey>,
-	) -> sp_blockchain::Result<
-		KeysIter<<crate::FullBackend as sc_client_api::Backend<Block>>::State, Block>,
-	> {
-		with_client! {
-			self,
-			client,
-			{
-				client.storage_keys(hash, prefix, start_key)
-			}
-		}
-	}
-
-	fn child_storage(
-		&self,
-		hash: <Block as BlockT>::Hash,
-		child_info: &ChildInfo,
-		key: &StorageKey,
-	) -> sp_blockchain::Result<Option<StorageData>> {
-		with_client! {
-			self,
-			client,
-			{
-				client.child_storage(hash, child_info, key)
-			}
-		}
-	}
-
-	fn child_storage_keys(
-		&self,
-		hash: <Block as BlockT>::Hash,
-		child_info: ChildInfo,
-		prefix: Option<&StorageKey>,
-		start_key: Option<&StorageKey>,
-	) -> sp_blockchain::Result<
-		KeysIter<<crate::FullBackend as sc_client_api::Backend<Block>>::State, Block>,
-	> {
-		with_client! {
-			self,
-			client,
-			{
-				client.child_storage_keys(hash, child_info, prefix, start_key)
-			}
-		}
-	}
-
-	fn child_storage_hash(
-		&self,
-		hash: <Block as BlockT>::Hash,
-		child_info: &ChildInfo,
-		key: &StorageKey,
-	) -> sp_blockchain::Result<Option<<Block as BlockT>::Hash>> {
-		with_client! {
-			self,
-			client,
-			{
-				client.child_storage_hash(hash, child_info, key)
-			}
-		}
-	}
-}
-
-impl sp_blockchain::HeaderBackend<Block> for Client {
-	fn header(&self, hash: Hash) -> sp_blockchain::Result<Option<Header>> {
-		with_client! {
-			self,
-			client,
-			{
-				client.header(hash)
-			}
-		}
-	}
-
-	fn info(&self) -> sp_blockchain::Info<Block> {
-		with_client! {
-			self,
-			client,
-			{
-				client.info()
-			}
-		}
-	}
-
-	fn status(&self, hash: Hash) -> sp_blockchain::Result<sp_blockchain::BlockStatus> {
-		with_client! {
-			self,
-			client,
-			{
-				client.status(hash)
-			}
-		}
-	}
-
-	fn number(&self, hash: Hash) -> sp_blockchain::Result<Option<BlockNumber>> {
-		with_client! {
-			self,
-			client,
-			{
-				client.number(hash)
-			}
-		}
-	}
-
-	fn hash(&self, number: BlockNumber) -> sp_blockchain::Result<Option<Hash>> {
-		with_client! {
-			self,
-			client,
-			{
-				client.hash(number)
-			}
-		}
-	}
-}
diff --git a/polkadot/node/service/Cargo.toml b/polkadot/node/service/Cargo.toml
index 34b69d045753999ef5566e77dd12fba2ab7b4a67..91eb139d67f35e86d163b8394c80f72191846fe4 100644
--- a/polkadot/node/service/Cargo.toml
+++ b/polkadot/node/service/Cargo.toml
@@ -37,7 +37,8 @@ sp-authority-discovery = { git = "https://github.com/paritytech/substrate", bran
 consensus_common = { package = "sp-consensus", git = "https://github.com/paritytech/substrate", branch = "master" }
 beefy-primitives = { package = "sp-consensus-beefy", git = "https://github.com/paritytech/substrate", branch = "master" }
 grandpa_primitives = { package = "sp-consensus-grandpa", git = "https://github.com/paritytech/substrate", branch = "master" }
-inherents = { package = "sp-inherents", git = "https://github.com/paritytech/substrate", branch = "master" }
+sp-inherents = { git = "https://github.com/paritytech/substrate", branch = "master" }
+sp-keyring = { git = "https://github.com/paritytech/substrate", branch = "master" }
 sp-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
 sp-block-builder = { git = "https://github.com/paritytech/substrate", branch = "master" }
 sp-blockchain = { git = "https://github.com/paritytech/substrate", branch = "master" }
@@ -49,22 +50,27 @@ sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master
 sp-session = { git = "https://github.com/paritytech/substrate", branch = "master" }
 sp-storage = { git = "https://github.com/paritytech/substrate", branch = "master" }
 sp-transaction-pool = { git = "https://github.com/paritytech/substrate", branch = "master" }
+pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", branch = "master" }
 sp-trie = { git = "https://github.com/paritytech/substrate", branch = "master" }
 sp-timestamp = { git = "https://github.com/paritytech/substrate", branch = "master" }
 sp-consensus-babe = { git = "https://github.com/paritytech/substrate", branch = "master" }
 sp-state-machine = { git = "https://github.com/paritytech/substrate", branch = "master" }
+sp-weights = { git = "https://github.com/paritytech/substrate", branch = "master" }
+sp-version = { git = "https://github.com/paritytech/substrate", branch = "master" }
 
 # Substrate Pallets
 pallet-babe = { git = "https://github.com/paritytech/substrate", branch = "master" }
 pallet-im-online = { git = "https://github.com/paritytech/substrate", branch = "master" }
 pallet-staking = { git = "https://github.com/paritytech/substrate", branch = "master" }
 pallet-transaction-payment-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
+frame-system = { git = "https://github.com/paritytech/substrate", branch = "master" }
 
 # Substrate Other
 frame-system-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
 prometheus-endpoint = { package = "substrate-prometheus-endpoint", git = "https://github.com/paritytech/substrate", branch = "master" }
 frame-support = { git = "https://github.com/paritytech/substrate", branch = "master" }
 frame-benchmarking-cli = { git = "https://github.com/paritytech/substrate", branch = "master" }
+frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "master" }
 
 # External Crates
 futures = "0.3.21"
@@ -76,15 +82,16 @@ thiserror = "1.0.31"
 kvdb = "0.13.0"
 kvdb-rocksdb = { version = "0.19.0", optional = true }
 parity-db = { version = "0.4.8", optional = true }
+codec = { package = "parity-scale-codec", version = "3.6.1" }
 
 async-trait = "0.1.57"
 lru = "0.9"
 log = "0.4.17"
 
 # Polkadot
+polkadot-core-primitives = { path = "../../core-primitives" }
 polkadot-node-core-parachains-inherent = { path = "../core/parachains-inherent" }
 polkadot-overseer = { path = "../overseer" }
-polkadot-client = { path = "../client", default-features = false, optional = true }
 polkadot-parachain = { path = "../../parachain" }
 polkadot-primitives = { path = "../../primitives" }
 polkadot-node-primitives = { path = "../primitives" }
@@ -94,6 +101,7 @@ polkadot-node-subsystem-util = { path = "../subsystem-util" }
 polkadot-node-subsystem-types = { path = "../subsystem-types" }
 polkadot-runtime-parachains = { path = "../../runtime/parachains" }
 polkadot-node-network-protocol = { path = "../network/protocol" }
+polkadot-runtime-common = { path = "../../runtime/common" }
 
 # Polkadot Runtime Constants
 polkadot-runtime-constants = { path = "../../runtime/polkadot/constants", optional = true }
@@ -138,7 +146,7 @@ assert_matches = "1.5.0"
 tempfile = "3.2"
 
 [features]
-default = ["db", "full-node", "polkadot-native"]
+default = ["db", "full-node"]
 
 db = [
 	"service/rocksdb"
@@ -150,7 +158,6 @@ full-node = [
 	"polkadot-availability-bitfield-distribution",
 	"polkadot-availability-distribution",
 	"polkadot-availability-recovery",
-	"polkadot-client",
 	"polkadot-collator-protocol",
 	"polkadot-dispute-distribution",
 	"polkadot-gossip-support",
@@ -174,10 +181,10 @@ full-node = [
 # Configure the native runtimes to use. Polkadot is enabled by default.
 #
 # Validators require the native runtime currently
-polkadot-native = [ "polkadot-runtime", "polkadot-runtime-constants", "polkadot-client/polkadot" ]
-kusama-native = [ "kusama-runtime", "kusama-runtime-constants", "polkadot-client/kusama" ]
-westend-native = [ "westend-runtime", "westend-runtime-constants", "polkadot-client/westend" ]
-rococo-native = [ "rococo-runtime", "rococo-runtime-constants", "polkadot-client/rococo" ]
+polkadot-native = [ "polkadot-runtime", "polkadot-runtime-constants" ]
+kusama-native = [ "kusama-runtime", "kusama-runtime-constants" ]
+westend-native = [ "westend-runtime", "westend-runtime-constants" ]
+rococo-native = [ "rococo-runtime", "rococo-runtime-constants" ]
 
 runtime-benchmarks = [
 	"polkadot-runtime?/runtime-benchmarks",
@@ -202,7 +209,6 @@ fast-runtime = [
 
 malus = ["full-node"]
 runtime-metrics = [
-	"polkadot-client/runtime-metrics",
 	"rococo-runtime?/runtime-metrics",
 	"westend-runtime?/runtime-metrics",
 	"kusama-runtime?/runtime-metrics",
diff --git a/polkadot/node/service/src/benchmarking.rs b/polkadot/node/service/src/benchmarking.rs
new file mode 100644
index 0000000000000000000000000000000000000000..7d2bae88e5f313c7dce6134235fc8f4ccbb6f741
--- /dev/null
+++ b/polkadot/node/service/src/benchmarking.rs
@@ -0,0 +1,430 @@
+// Copyright (C) Parity Technologies (UK) Ltd.
+// This file is part of Polkadot.
+
+// Polkadot 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.
+
+// Polkadot 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 Polkadot.  If not, see <http://www.gnu.org/licenses/>.
+
+//! Code related to benchmarking a [`crate::Client`].
+
+use codec::Encode;
+use polkadot_primitives::AccountId;
+use sc_client_api::UsageProvider;
+use sp_core::{Pair, H256};
+use sp_keyring::Sr25519Keyring;
+use sp_runtime::OpaqueExtrinsic;
+
+use crate::*;
+
+macro_rules! identify_chain {
+	(
+		$chain:expr,
+		$nonce:ident,
+		$current_block:ident,
+		$period:ident,
+		$genesis:ident,
+		$signer:ident,
+		$generic_code:expr $(,)*
+	) => {
+		match $chain {
+			Chain::Polkadot => {
+				#[cfg(feature = "polkadot-native")]
+				{
+					use polkadot_runtime as runtime;
+
+					let call = $generic_code;
+
+					Ok(polkadot_sign_call(call, $nonce, $current_block, $period, $genesis, $signer))
+				}
+
+				#[cfg(not(feature = "polkadot-native"))]
+				{
+					Err("`polkadot-native` feature not enabled")
+				}
+			},
+			Chain::Kusama => {
+				#[cfg(feature = "kusama-native")]
+				{
+					use kusama_runtime as runtime;
+
+					let call = $generic_code;
+
+					Ok(kusama_sign_call(call, $nonce, $current_block, $period, $genesis, $signer))
+				}
+
+				#[cfg(not(feature = "kusama-native"))]
+				{
+					Err("`kusama-native` feature not enabled")
+				}
+			},
+			Chain::Rococo => {
+				#[cfg(feature = "rococo-native")]
+				{
+					use rococo_runtime as runtime;
+
+					let call = $generic_code;
+
+					Ok(rococo_sign_call(call, $nonce, $current_block, $period, $genesis, $signer))
+				}
+
+				#[cfg(not(feature = "rococo-native"))]
+				{
+					Err("`rococo-native` feature not enabled")
+				}
+			},
+			Chain::Westend => {
+				#[cfg(feature = "westend-native")]
+				{
+					use westend_runtime as runtime;
+
+					let call = $generic_code;
+
+					Ok(westend_sign_call(call, $nonce, $current_block, $period, $genesis, $signer))
+				}
+
+				#[cfg(not(feature = "westend-native"))]
+				{
+					Err("`westend-native` feature not enabled")
+				}
+			},
+			Chain::Unknown => Err("Unknown chain"),
+		}
+	};
+}
+
+/// Generates `System::Remark` extrinsics for the benchmarks.
+///
+/// Note: Should only be used for benchmarking.
+pub struct RemarkBuilder {
+	client: Arc<FullClient>,
+	chain: Chain,
+}
+
+impl RemarkBuilder {
+	/// Creates a new [`Self`] from the given client.
+	pub fn new(client: Arc<FullClient>, chain: Chain) -> Self {
+		Self { client, chain }
+	}
+}
+
+impl frame_benchmarking_cli::ExtrinsicBuilder for RemarkBuilder {
+	fn pallet(&self) -> &str {
+		"system"
+	}
+
+	fn extrinsic(&self) -> &str {
+		"remark"
+	}
+
+	fn build(&self, nonce: u32) -> std::result::Result<OpaqueExtrinsic, &'static str> {
+		let period = polkadot_runtime_common::BlockHashCount::get()
+			.checked_next_power_of_two()
+			.map(|c| c / 2)
+			.unwrap_or(2) as u64;
+		let genesis = self.client.usage_info().chain.best_hash;
+		let signer = Sr25519Keyring::Bob.pair();
+		let current_block = 0;
+
+		identify_chain! {
+			self.chain,
+			nonce,
+			current_block,
+			period,
+			genesis,
+			signer,
+			{
+				runtime::RuntimeCall::System(
+					runtime::SystemCall::remark { remark: vec![] }
+				)
+			},
+		}
+	}
+}
+
+/// Generates `Balances::TransferKeepAlive` extrinsics for the benchmarks.
+///
+/// Note: Should only be used for benchmarking.
+pub struct TransferKeepAliveBuilder {
+	client: Arc<FullClient>,
+	dest: AccountId,
+	chain: Chain,
+}
+
+impl TransferKeepAliveBuilder {
+	/// Creates a new [`Self`] from the given client and the arguments for the extrinsics.
+	pub fn new(client: Arc<FullClient>, dest: AccountId, chain: Chain) -> Self {
+		Self { client, dest, chain }
+	}
+}
+
+impl frame_benchmarking_cli::ExtrinsicBuilder for TransferKeepAliveBuilder {
+	fn pallet(&self) -> &str {
+		"balances"
+	}
+
+	fn extrinsic(&self) -> &str {
+		"transfer_keep_alive"
+	}
+
+	fn build(&self, nonce: u32) -> std::result::Result<OpaqueExtrinsic, &'static str> {
+		let signer = Sr25519Keyring::Bob.pair();
+		let period = polkadot_runtime_common::BlockHashCount::get()
+			.checked_next_power_of_two()
+			.map(|c| c / 2)
+			.unwrap_or(2) as u64;
+		let genesis = self.client.usage_info().chain.best_hash;
+		let current_block = 0;
+
+		identify_chain! {
+			self.chain,
+			nonce,
+			current_block,
+			period,
+			genesis,
+			signer,
+			{
+				runtime::RuntimeCall::Balances(runtime::BalancesCall::transfer_keep_alive {
+					dest: self.dest.clone().into(),
+					value: runtime::ExistentialDeposit::get(),
+				})
+			},
+		}
+	}
+}
+
+#[cfg(feature = "polkadot-native")]
+fn polkadot_sign_call(
+	call: polkadot_runtime::RuntimeCall,
+	nonce: u32,
+	current_block: u64,
+	period: u64,
+	genesis: H256,
+	acc: sp_core::sr25519::Pair,
+) -> OpaqueExtrinsic {
+	use polkadot_runtime as runtime;
+
+	let extra: runtime::SignedExtra = (
+		frame_system::CheckNonZeroSender::<runtime::Runtime>::new(),
+		frame_system::CheckSpecVersion::<runtime::Runtime>::new(),
+		frame_system::CheckTxVersion::<runtime::Runtime>::new(),
+		frame_system::CheckGenesis::<runtime::Runtime>::new(),
+		frame_system::CheckMortality::<runtime::Runtime>::from(sp_runtime::generic::Era::mortal(
+			period,
+			current_block,
+		)),
+		frame_system::CheckNonce::<runtime::Runtime>::from(nonce),
+		frame_system::CheckWeight::<runtime::Runtime>::new(),
+		pallet_transaction_payment::ChargeTransactionPayment::<runtime::Runtime>::from(0),
+		polkadot_runtime_common::claims::PrevalidateAttests::<runtime::Runtime>::new(),
+	);
+
+	let payload = runtime::SignedPayload::from_raw(
+		call.clone(),
+		extra.clone(),
+		(
+			(),
+			runtime::VERSION.spec_version,
+			runtime::VERSION.transaction_version,
+			genesis,
+			genesis,
+			(),
+			(),
+			(),
+			(),
+		),
+	);
+
+	let signature = payload.using_encoded(|p| acc.sign(p));
+	runtime::UncheckedExtrinsic::new_signed(
+		call,
+		sp_runtime::AccountId32::from(acc.public()).into(),
+		polkadot_core_primitives::Signature::Sr25519(signature.clone()),
+		extra,
+	)
+	.into()
+}
+
+#[cfg(feature = "westend-native")]
+fn westend_sign_call(
+	call: westend_runtime::RuntimeCall,
+	nonce: u32,
+	current_block: u64,
+	period: u64,
+	genesis: H256,
+	acc: sp_core::sr25519::Pair,
+) -> OpaqueExtrinsic {
+	use westend_runtime as runtime;
+
+	let extra: runtime::SignedExtra = (
+		frame_system::CheckNonZeroSender::<runtime::Runtime>::new(),
+		frame_system::CheckSpecVersion::<runtime::Runtime>::new(),
+		frame_system::CheckTxVersion::<runtime::Runtime>::new(),
+		frame_system::CheckGenesis::<runtime::Runtime>::new(),
+		frame_system::CheckMortality::<runtime::Runtime>::from(sp_runtime::generic::Era::mortal(
+			period,
+			current_block,
+		)),
+		frame_system::CheckNonce::<runtime::Runtime>::from(nonce),
+		frame_system::CheckWeight::<runtime::Runtime>::new(),
+		pallet_transaction_payment::ChargeTransactionPayment::<runtime::Runtime>::from(0),
+	);
+
+	let payload = runtime::SignedPayload::from_raw(
+		call.clone(),
+		extra.clone(),
+		(
+			(),
+			runtime::VERSION.spec_version,
+			runtime::VERSION.transaction_version,
+			genesis,
+			genesis,
+			(),
+			(),
+			(),
+		),
+	);
+
+	let signature = payload.using_encoded(|p| acc.sign(p));
+	runtime::UncheckedExtrinsic::new_signed(
+		call,
+		sp_runtime::AccountId32::from(acc.public()).into(),
+		polkadot_core_primitives::Signature::Sr25519(signature.clone()),
+		extra,
+	)
+	.into()
+}
+
+#[cfg(feature = "kusama-native")]
+fn kusama_sign_call(
+	call: kusama_runtime::RuntimeCall,
+	nonce: u32,
+	current_block: u64,
+	period: u64,
+	genesis: H256,
+	acc: sp_core::sr25519::Pair,
+) -> OpaqueExtrinsic {
+	use kusama_runtime as runtime;
+
+	let extra: runtime::SignedExtra = (
+		frame_system::CheckNonZeroSender::<runtime::Runtime>::new(),
+		frame_system::CheckSpecVersion::<runtime::Runtime>::new(),
+		frame_system::CheckTxVersion::<runtime::Runtime>::new(),
+		frame_system::CheckGenesis::<runtime::Runtime>::new(),
+		frame_system::CheckMortality::<runtime::Runtime>::from(sp_runtime::generic::Era::mortal(
+			period,
+			current_block,
+		)),
+		frame_system::CheckNonce::<runtime::Runtime>::from(nonce),
+		frame_system::CheckWeight::<runtime::Runtime>::new(),
+		pallet_transaction_payment::ChargeTransactionPayment::<runtime::Runtime>::from(0),
+	);
+
+	let payload = runtime::SignedPayload::from_raw(
+		call.clone(),
+		extra.clone(),
+		(
+			(),
+			runtime::VERSION.spec_version,
+			runtime::VERSION.transaction_version,
+			genesis,
+			genesis,
+			(),
+			(),
+			(),
+		),
+	);
+
+	let signature = payload.using_encoded(|p| acc.sign(p));
+	runtime::UncheckedExtrinsic::new_signed(
+		call,
+		sp_runtime::AccountId32::from(acc.public()).into(),
+		polkadot_core_primitives::Signature::Sr25519(signature.clone()),
+		extra,
+	)
+	.into()
+}
+
+#[cfg(feature = "rococo-native")]
+fn rococo_sign_call(
+	call: rococo_runtime::RuntimeCall,
+	nonce: u32,
+	current_block: u64,
+	period: u64,
+	genesis: H256,
+	acc: sp_core::sr25519::Pair,
+) -> OpaqueExtrinsic {
+	use rococo_runtime as runtime;
+
+	let extra: runtime::SignedExtra = (
+		frame_system::CheckNonZeroSender::<runtime::Runtime>::new(),
+		frame_system::CheckSpecVersion::<runtime::Runtime>::new(),
+		frame_system::CheckTxVersion::<runtime::Runtime>::new(),
+		frame_system::CheckGenesis::<runtime::Runtime>::new(),
+		frame_system::CheckMortality::<runtime::Runtime>::from(sp_runtime::generic::Era::mortal(
+			period,
+			current_block,
+		)),
+		frame_system::CheckNonce::<runtime::Runtime>::from(nonce),
+		frame_system::CheckWeight::<runtime::Runtime>::new(),
+		pallet_transaction_payment::ChargeTransactionPayment::<runtime::Runtime>::from(0),
+	);
+
+	let payload = runtime::SignedPayload::from_raw(
+		call.clone(),
+		extra.clone(),
+		(
+			(),
+			runtime::VERSION.spec_version,
+			runtime::VERSION.transaction_version,
+			genesis,
+			genesis,
+			(),
+			(),
+			(),
+		),
+	);
+
+	let signature = payload.using_encoded(|p| acc.sign(p));
+	runtime::UncheckedExtrinsic::new_signed(
+		call,
+		sp_runtime::AccountId32::from(acc.public()).into(),
+		polkadot_core_primitives::Signature::Sr25519(signature.clone()),
+		extra,
+	)
+	.into()
+}
+
+/// Generates inherent data for benchmarking Polkadot, Kusama, Westend and Rococo.
+///
+/// Not to be used outside of benchmarking since it returns mocked values.
+pub fn benchmark_inherent_data(
+	header: polkadot_core_primitives::Header,
+) -> std::result::Result<sp_inherents::InherentData, sp_inherents::Error> {
+	use sp_inherents::InherentDataProvider;
+	let mut inherent_data = sp_inherents::InherentData::new();
+
+	// Assume that all runtimes have the `timestamp` pallet.
+	let d = std::time::Duration::from_millis(0);
+	let timestamp = sp_timestamp::InherentDataProvider::new(d.into());
+	futures::executor::block_on(timestamp.provide_inherent_data(&mut inherent_data))?;
+
+	let para_data = polkadot_primitives::InherentData {
+		bitfields: Vec::new(),
+		backed_candidates: Vec::new(),
+		disputes: Vec::new(),
+		parent_header: header,
+	};
+
+	inherent_data.put_data(polkadot_primitives::PARACHAINS_INHERENT_IDENTIFIER, &para_data)?;
+
+	Ok(inherent_data)
+}
diff --git a/polkadot/node/service/src/chain_spec.rs b/polkadot/node/service/src/chain_spec.rs
index 9e788bc8326fa351c3cb354989fe9cf19282b926..9d76f9c8ce616cc54f4849e6b22495184d838a12 100644
--- a/polkadot/node/service/src/chain_spec.rs
+++ b/polkadot/node/service/src/chain_spec.rs
@@ -23,6 +23,12 @@ use kusama_runtime as kusama;
 #[cfg(feature = "kusama-native")]
 use kusama_runtime_constants::currency::UNITS as KSM;
 use pallet_im_online::sr25519::AuthorityId as ImOnlineId;
+#[cfg(any(
+	feature = "polkadot-native",
+	feature = "kusama-native",
+	feature = "westend-native",
+	feature = "rococo-native"
+))]
 use pallet_staking::Forcing;
 use polkadot_primitives::{AccountId, AccountPublic, AssignmentId, ValidatorId};
 #[cfg(feature = "polkadot-native")]
@@ -36,10 +42,30 @@ use sp_consensus_babe::AuthorityId as BabeId;
 use rococo_runtime as rococo;
 #[cfg(feature = "rococo-native")]
 use rococo_runtime_constants::currency::UNITS as ROC;
-use sc_chain_spec::{ChainSpecExtension, ChainType};
+use sc_chain_spec::ChainSpecExtension;
+#[cfg(any(
+	feature = "polkadot-native",
+	feature = "kusama-native",
+	feature = "westend-native",
+	feature = "rococo-native"
+))]
+use sc_chain_spec::ChainType;
 use serde::{Deserialize, Serialize};
 use sp_core::{sr25519, Pair, Public};
-use sp_runtime::{traits::IdentifyAccount, Perbill};
+use sp_runtime::traits::IdentifyAccount;
+#[cfg(any(
+	feature = "polkadot-native",
+	feature = "kusama-native",
+	feature = "westend-native",
+	feature = "rococo-native"
+))]
+use sp_runtime::Perbill;
+#[cfg(any(
+	feature = "polkadot-native",
+	feature = "kusama-native",
+	feature = "westend-native",
+	feature = "rococo-native"
+))]
 use telemetry::TelemetryEndpoints;
 #[cfg(feature = "westend-native")]
 use westend_runtime as westend;
@@ -56,6 +82,12 @@ const WESTEND_STAGING_TELEMETRY_URL: &str = "wss://telemetry.polkadot.io/submit/
 const ROCOCO_STAGING_TELEMETRY_URL: &str = "wss://telemetry.polkadot.io/submit/";
 #[cfg(feature = "rococo-native")]
 const VERSI_STAGING_TELEMETRY_URL: &str = "wss://telemetry.polkadot.io/submit/";
+#[cfg(any(
+	feature = "polkadot-native",
+	feature = "kusama-native",
+	feature = "westend-native",
+	feature = "rococo-native"
+))]
 const DEFAULT_PROTOCOL_ID: &str = "dot";
 
 /// Node `ChainSpec` extensions.
@@ -1271,6 +1303,12 @@ pub fn get_authority_keys_from_seed_no_beefy(
 	)
 }
 
+#[cfg(any(
+	feature = "polkadot-native",
+	feature = "kusama-native",
+	feature = "westend-native",
+	feature = "rococo-native"
+))]
 fn testnet_accounts() -> Vec<AccountId> {
 	vec![
 		get_account_id_from_seed::<sr25519::Public>("Alice"),
@@ -1667,7 +1705,7 @@ pub fn polkadot_development_config() -> Result<PolkadotChainSpec, String> {
 
 	Ok(PolkadotChainSpec::from_genesis(
 		"Development",
-		"dev",
+		"polkadot_dev",
 		ChainType::Development,
 		move || polkadot_development_config_genesis(wasm_binary),
 		vec![],
diff --git a/polkadot/node/service/src/fake_runtime_api.rs b/polkadot/node/service/src/fake_runtime_api.rs
new file mode 100644
index 0000000000000000000000000000000000000000..f4864d5c2010af15f1fcf5152721cccffcb3b9ad
--- /dev/null
+++ b/polkadot/node/service/src/fake_runtime_api.rs
@@ -0,0 +1,398 @@
+// Copyright (C) Parity Technologies (UK) Ltd.
+// This file is part of Polkadot.
+
+// Polkadot 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.
+
+// Polkadot 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 Polkadot.  If not, see <http://www.gnu.org/licenses/>.
+
+//! Provides "fake" runtime api implementations
+//!
+//! These are used to provide a type that implements these runtime apis without requiring to import the native runtimes.
+
+use beefy_primitives::crypto::{AuthorityId as BeefyId, Signature as BeefySignature};
+use grandpa_primitives::AuthorityId as GrandpaId;
+use pallet_transaction_payment::{FeeDetails, RuntimeDispatchInfo};
+use polkadot_primitives::{
+	runtime_api, slashing, AccountId, AuthorityDiscoveryId, Balance, Block, BlockNumber,
+	CandidateCommitments, CandidateEvent, CandidateHash, CommittedCandidateReceipt, CoreState,
+	DisputeState, ExecutorParams, GroupRotationInfo, Hash, Id as ParaId, InboundDownwardMessage,
+	InboundHrmpMessage, Nonce, OccupiedCoreAssumption, PersistedValidationData, PvfCheckStatement,
+	ScrapedOnChainVotes, SessionIndex, SessionInfo, ValidationCode, ValidationCodeHash,
+	ValidatorId, ValidatorIndex, ValidatorSignature,
+};
+use sp_core::OpaqueMetadata;
+use sp_runtime::{
+	traits::Block as BlockT,
+	transaction_validity::{TransactionSource, TransactionValidity},
+	ApplyExtrinsicResult,
+};
+use sp_version::RuntimeVersion;
+use sp_weights::Weight;
+use std::collections::BTreeMap;
+
+sp_api::decl_runtime_apis! {
+	/// This runtime api is only implemented for the test runtime!
+	pub trait GetLastTimestamp {
+		/// Returns the last timestamp of a runtime.
+		fn get_last_timestamp() -> u64;
+	}
+}
+
+struct Runtime;
+
+sp_api::impl_runtime_apis! {
+	impl sp_api::Core<Block> for Runtime {
+		fn version() -> RuntimeVersion {
+			unimplemented!()
+		}
+
+		fn execute_block(_: Block) {
+			unimplemented!()
+		}
+
+		fn initialize_block(_: &<Block as BlockT>::Header) {
+			unimplemented!()
+		}
+	}
+
+	impl sp_api::Metadata<Block> for Runtime {
+		fn metadata() -> OpaqueMetadata {
+			unimplemented!()
+		}
+
+		fn metadata_at_version(_: u32) -> Option<OpaqueMetadata> {
+			unimplemented!()
+		}
+
+		fn metadata_versions() -> Vec<u32> {
+			unimplemented!()
+		}
+	}
+
+	impl sp_block_builder::BlockBuilder<Block> for Runtime {
+		fn apply_extrinsic(_: <Block as BlockT>::Extrinsic) -> ApplyExtrinsicResult {
+			unimplemented!()
+		}
+
+		fn finalize_block() -> <Block as BlockT>::Header {
+			unimplemented!()
+		}
+
+		fn inherent_extrinsics(_: sp_inherents::InherentData) -> Vec<<Block as BlockT>::Extrinsic> {
+			unimplemented!()
+		}
+
+		fn check_inherents(
+			_: Block,
+			_: sp_inherents::InherentData,
+		) -> sp_inherents::CheckInherentsResult {
+			unimplemented!()
+		}
+	}
+
+	impl sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block> for Runtime {
+		fn validate_transaction(
+			_: TransactionSource,
+			_: <Block as BlockT>::Extrinsic,
+			_: <Block as BlockT>::Hash,
+		) -> TransactionValidity {
+			unimplemented!()
+		}
+	}
+
+	impl sp_offchain::OffchainWorkerApi<Block> for Runtime {
+		fn offchain_worker(_: &<Block as BlockT>::Header) {
+			unimplemented!()
+		}
+	}
+
+	impl runtime_api::ParachainHost<Block, Hash, BlockNumber> for Runtime {
+		fn validators() -> Vec<ValidatorId> {
+			unimplemented!()
+		}
+
+		fn validator_groups() -> (Vec<Vec<ValidatorIndex>>, GroupRotationInfo<BlockNumber>) {
+			unimplemented!()
+		}
+
+		fn availability_cores() -> Vec<CoreState<Hash, BlockNumber>> {
+			unimplemented!()
+		}
+
+		fn persisted_validation_data(_: ParaId, _: OccupiedCoreAssumption)
+			-> Option<PersistedValidationData<Hash, BlockNumber>> {
+			unimplemented!()
+		}
+
+		fn assumed_validation_data(
+			_: ParaId,
+			_: Hash,
+		) -> Option<(PersistedValidationData<Hash, BlockNumber>, ValidationCodeHash)> {
+			unimplemented!()
+		}
+
+		fn check_validation_outputs(
+			_: ParaId,
+			_: CandidateCommitments,
+		) -> bool {
+			unimplemented!()
+		}
+
+		fn session_index_for_child() -> SessionIndex {
+			unimplemented!()
+		}
+
+		fn validation_code(_: ParaId, _: OccupiedCoreAssumption)
+			-> Option<ValidationCode> {
+			unimplemented!()
+		}
+
+		fn candidate_pending_availability(_: ParaId) -> Option<CommittedCandidateReceipt<Hash>> {
+			unimplemented!()
+		}
+
+		fn candidate_events() -> Vec<CandidateEvent<Hash>> {
+			unimplemented!()
+		}
+
+		fn session_info(_: SessionIndex) -> Option<SessionInfo> {
+			unimplemented!()
+		}
+
+		fn session_executor_params(_: SessionIndex) -> Option<ExecutorParams> {
+			unimplemented!()
+		}
+
+		fn dmq_contents(_: ParaId) -> Vec<InboundDownwardMessage<BlockNumber>> {
+			unimplemented!()
+		}
+
+		fn inbound_hrmp_channels_contents(
+			_: ParaId
+		) -> BTreeMap<ParaId, Vec<InboundHrmpMessage<BlockNumber>>> {
+			unimplemented!()
+		}
+
+		fn validation_code_by_hash(_: ValidationCodeHash) -> Option<ValidationCode> {
+			unimplemented!()
+		}
+
+		fn on_chain_votes() -> Option<ScrapedOnChainVotes<Hash>> {
+			unimplemented!()
+		}
+
+		fn submit_pvf_check_statement(
+			_: PvfCheckStatement,
+			_: ValidatorSignature,
+		) {
+			unimplemented!()
+		}
+
+		fn pvfs_require_precheck() -> Vec<ValidationCodeHash> {
+			unimplemented!()
+		}
+
+		fn validation_code_hash(_: ParaId, _: OccupiedCoreAssumption)
+			-> Option<ValidationCodeHash>
+		{
+			unimplemented!()
+		}
+
+		fn disputes() -> Vec<(SessionIndex, CandidateHash, DisputeState<BlockNumber>)> {
+			unimplemented!()
+		}
+
+		fn unapplied_slashes(
+		) -> Vec<(SessionIndex, CandidateHash, slashing::PendingSlashes)> {
+			unimplemented!()
+		}
+
+		fn key_ownership_proof(
+			_: ValidatorId,
+		) -> Option<slashing::OpaqueKeyOwnershipProof> {
+			unimplemented!()
+		}
+
+		fn submit_report_dispute_lost(
+			_: slashing::DisputeProof,
+			_: slashing::OpaqueKeyOwnershipProof,
+		) -> Option<()> {
+			unimplemented!()
+		}
+	}
+
+	impl beefy_primitives::BeefyApi<Block> for Runtime {
+		fn beefy_genesis() -> Option<BlockNumber> {
+			unimplemented!()
+		}
+
+		fn validator_set() -> Option<beefy_primitives::ValidatorSet<BeefyId>> {
+			unimplemented!()
+		}
+
+		fn submit_report_equivocation_unsigned_extrinsic(
+			_: beefy_primitives::EquivocationProof<
+				BlockNumber,
+				BeefyId,
+				BeefySignature,
+			>,
+			_: beefy_primitives::OpaqueKeyOwnershipProof,
+		) -> Option<()> {
+			unimplemented!()
+		}
+
+		fn generate_key_ownership_proof(
+			_: beefy_primitives::ValidatorSetId,
+			_: BeefyId,
+		) -> Option<beefy_primitives::OpaqueKeyOwnershipProof> {
+			unimplemented!()
+		}
+	}
+
+	impl sp_mmr_primitives::MmrApi<Block, Hash, BlockNumber> for Runtime {
+		fn mmr_root() -> Result<Hash, sp_mmr_primitives::Error> {
+			unimplemented!()
+		}
+
+		fn mmr_leaf_count() -> Result<sp_mmr_primitives::LeafIndex, sp_mmr_primitives::Error> {
+			unimplemented!()
+		}
+
+		fn generate_proof(
+			_: Vec<BlockNumber>,
+			_: Option<BlockNumber>,
+		) -> Result<(Vec<sp_mmr_primitives::EncodableOpaqueLeaf>, sp_mmr_primitives::Proof<Hash>), sp_mmr_primitives::Error> {
+			unimplemented!()
+		}
+
+		fn verify_proof(_: Vec<sp_mmr_primitives::EncodableOpaqueLeaf>, _: sp_mmr_primitives::Proof<Hash>)
+			-> Result<(), sp_mmr_primitives::Error>
+		{
+			unimplemented!()
+		}
+
+		fn verify_proof_stateless(
+			_: Hash,
+			_: Vec<sp_mmr_primitives::EncodableOpaqueLeaf>,
+			_: sp_mmr_primitives::Proof<Hash>
+		) -> Result<(), sp_mmr_primitives::Error> {
+			unimplemented!()
+		}
+	}
+
+	impl grandpa_primitives::GrandpaApi<Block> for Runtime {
+		fn grandpa_authorities() -> Vec<(GrandpaId, u64)> {
+			unimplemented!()
+		}
+
+		fn current_set_id() -> grandpa_primitives::SetId {
+			unimplemented!()
+		}
+
+		fn submit_report_equivocation_unsigned_extrinsic(
+			_: grandpa_primitives::EquivocationProof<
+				<Block as BlockT>::Hash,
+				sp_runtime::traits::NumberFor<Block>,
+			>,
+			_: grandpa_primitives::OpaqueKeyOwnershipProof,
+		) -> Option<()> {
+			unimplemented!()
+		}
+
+		fn generate_key_ownership_proof(
+			_: grandpa_primitives::SetId,
+			_: grandpa_primitives::AuthorityId,
+		) -> Option<grandpa_primitives::OpaqueKeyOwnershipProof> {
+			unimplemented!()
+		}
+	}
+
+	impl sp_consensus_babe::BabeApi<Block> for Runtime {
+		fn configuration() -> sp_consensus_babe::BabeConfiguration {
+			unimplemented!()
+		}
+
+		fn current_epoch_start() -> sp_consensus_babe::Slot {
+			unimplemented!()
+		}
+
+		fn current_epoch() -> sp_consensus_babe::Epoch {
+			unimplemented!()
+		}
+
+		fn next_epoch() -> sp_consensus_babe::Epoch {
+			unimplemented!()
+		}
+
+		fn generate_key_ownership_proof(
+			_: sp_consensus_babe::Slot,
+			_: sp_consensus_babe::AuthorityId,
+		) -> Option<sp_consensus_babe::OpaqueKeyOwnershipProof> {
+			unimplemented!()
+		}
+
+		fn submit_report_equivocation_unsigned_extrinsic(
+			_: sp_consensus_babe::EquivocationProof<<Block as BlockT>::Header>,
+			_: sp_consensus_babe::OpaqueKeyOwnershipProof,
+		) -> Option<()> {
+			unimplemented!()
+		}
+	}
+
+	impl sp_authority_discovery::AuthorityDiscoveryApi<Block> for Runtime {
+		fn authorities() -> Vec<AuthorityDiscoveryId> {
+			unimplemented!()
+		}
+	}
+
+	impl sp_session::SessionKeys<Block> for Runtime {
+		fn generate_session_keys(_: Option<Vec<u8>>) -> Vec<u8> {
+			unimplemented!()
+		}
+
+		fn decode_session_keys(
+			_: Vec<u8>,
+		) -> Option<Vec<(Vec<u8>, sp_core::crypto::KeyTypeId)>> {
+			unimplemented!()
+		}
+	}
+
+	impl frame_system_rpc_runtime_api::AccountNonceApi<Block, AccountId, Nonce> for Runtime {
+		fn account_nonce(_: AccountId) -> Nonce {
+			unimplemented!()
+		}
+	}
+
+	impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<
+		Block,
+		Balance,
+	> for Runtime {
+		fn query_info(_: <Block as BlockT>::Extrinsic, _: u32) -> RuntimeDispatchInfo<Balance> {
+			unimplemented!()
+		}
+		fn query_fee_details(_: <Block as BlockT>::Extrinsic, _: u32) -> FeeDetails<Balance> {
+			unimplemented!()
+		}
+		fn query_weight_to_fee(_: Weight) -> Balance {
+			unimplemented!()
+		}
+		fn query_length_to_fee(_: u32) -> Balance {
+			unimplemented!()
+		}
+	}
+
+	impl crate::fake_runtime_api::GetLastTimestamp<Block> for Runtime {
+		fn get_last_timestamp() -> u64 {
+			unimplemented!()
+		}
+	}
+}
diff --git a/polkadot/node/service/src/lib.rs b/polkadot/node/service/src/lib.rs
index c48ae9ea2ff5e60a55a75c4763118e2fc6c5cc9b..4e22736aeba0b027ed2fba7b02642264d56d8278 100644
--- a/polkadot/node/service/src/lib.rs
+++ b/polkadot/node/service/src/lib.rs
@@ -18,7 +18,15 @@
 
 #![deny(unused_results)]
 
+#[cfg(any(
+	feature = "polkadot-native",
+	feature = "kusama-native",
+	feature = "westend-native",
+	feature = "rococo-native"
+))]
+pub mod benchmarking;
 pub mod chain_spec;
+mod fake_runtime_api;
 mod grandpa_support;
 mod parachains_db;
 mod relay_chain_selection;
@@ -80,34 +88,15 @@ use telemetry::TelemetryWorker;
 #[cfg(feature = "full-node")]
 use telemetry::{Telemetry, TelemetryWorkerHandle};
 
-#[cfg(feature = "rococo-native")]
-pub use polkadot_client::RococoExecutorDispatch;
-
-#[cfg(feature = "westend-native")]
-pub use polkadot_client::WestendExecutorDispatch;
-
-#[cfg(feature = "kusama-native")]
-pub use polkadot_client::KusamaExecutorDispatch;
-
-#[cfg(feature = "polkadot-native")]
-pub use polkadot_client::PolkadotExecutorDispatch;
-
 pub use chain_spec::{KusamaChainSpec, PolkadotChainSpec, RococoChainSpec, WestendChainSpec};
-pub use consensus_common::{block_validation::Chain, Proposal, SelectChain};
+pub use consensus_common::{Proposal, SelectChain};
 use frame_benchmarking_cli::SUBSTRATE_REFERENCE_HARDWARE;
 use mmr_gadget::MmrGadget;
-#[cfg(feature = "full-node")]
-pub use polkadot_client::{
-	AbstractClient, Client, ClientHandle, ExecuteWithClient, FullBackend, FullClient,
-	RuntimeApiCollection,
-};
 pub use polkadot_primitives::{Block, BlockId, BlockNumber, CollatorPair, Hash, Id as ParaId};
 pub use sc_client_api::{Backend, CallExecutor, ExecutionStrategy};
 pub use sc_consensus::{BlockImport, LongestChain};
 pub use sc_executor::NativeExecutionDispatch;
-use sc_executor::{
-	HeapAllocStrategy, NativeElseWasmExecutor, WasmExecutor, DEFAULT_HEAP_ALLOC_STRATEGY,
-};
+use sc_executor::{HeapAllocStrategy, WasmExecutor, DEFAULT_HEAP_ALLOC_STRATEGY};
 pub use service::{
 	config::{DatabaseSource, PrometheusConfig},
 	ChainSpec, Configuration, Error as SubstrateServiceError, PruningMode, Role, RuntimeGenesis,
@@ -130,6 +119,18 @@ pub use {rococo_runtime, rococo_runtime_constants};
 #[cfg(feature = "westend-native")]
 pub use {westend_runtime, westend_runtime_constants};
 
+pub use fake_runtime_api::{GetLastTimestamp, RuntimeApi};
+
+#[cfg(feature = "full-node")]
+pub type FullBackend = service::TFullBackend<Block>;
+
+#[cfg(feature = "full-node")]
+pub type FullClient = service::TFullClient<
+	Block,
+	RuntimeApi,
+	WasmExecutor<(sp_io::SubstrateHostFunctions, frame_benchmarking::benchmarking::HostFunctions)>,
+>;
+
 /// Provides the header and block number for a hash.
 ///
 /// Decouples `sc_client_api::Backend` and `sp_blockchain::HeaderBackend`.
@@ -239,6 +240,21 @@ pub enum Error {
 	NoRuntime,
 }
 
+/// Identifies the variant of the chain.
+#[derive(Debug, Clone, Copy, PartialEq)]
+pub enum Chain {
+	/// Polkadot.
+	Polkadot,
+	/// Kusama.
+	Kusama,
+	/// Rococo or one of its derivations.
+	Rococo,
+	/// Westend.
+	Westend,
+	/// Unknown chain?
+	Unknown,
+}
+
 /// Can be called for a `Configuration` to identify which network the configuration targets.
 pub trait IdentifyVariant {
 	/// Returns if this is a configuration for the `Polkadot` network.
@@ -261,6 +277,9 @@ pub trait IdentifyVariant {
 
 	/// Returns true if this configuration is for a development network.
 	fn is_dev(&self) -> bool;
+
+	/// Identifies the variant of the chain.
+	fn identify_chain(&self) -> Chain;
 }
 
 impl IdentifyVariant for Box<dyn ChainSpec> {
@@ -285,6 +304,19 @@ impl IdentifyVariant for Box<dyn ChainSpec> {
 	fn is_dev(&self) -> bool {
 		self.id().ends_with("dev")
 	}
+	fn identify_chain(&self) -> Chain {
+		if self.is_polkadot() {
+			Chain::Polkadot
+		} else if self.is_kusama() {
+			Chain::Kusama
+		} else if self.is_westend() {
+			Chain::Westend
+		} else if self.is_rococo() || self.is_versi() || self.is_wococo() {
+			Chain::Rococo
+		} else {
+			Chain::Unknown
+		}
+	}
 }
 
 #[cfg(feature = "full-node")]
@@ -340,55 +372,27 @@ fn jaeger_launch_collector_with_agent(
 #[cfg(feature = "full-node")]
 type FullSelectChain = relay_chain_selection::SelectRelayChain<FullBackend>;
 #[cfg(feature = "full-node")]
-type FullGrandpaBlockImport<RuntimeApi, ExecutorDispatch, ChainSelection = FullSelectChain> =
-	grandpa::GrandpaBlockImport<
-		FullBackend,
-		Block,
-		FullClient<RuntimeApi, ExecutorDispatch>,
-		ChainSelection,
-	>;
+type FullGrandpaBlockImport<ChainSelection = FullSelectChain> =
+	grandpa::GrandpaBlockImport<FullBackend, Block, FullClient, ChainSelection>;
 #[cfg(feature = "full-node")]
-type FullBeefyBlockImport<RuntimeApi, ExecutorDispatch, InnerBlockImport> =
-	beefy::import::BeefyBlockImport<
-		Block,
-		FullBackend,
-		FullClient<RuntimeApi, ExecutorDispatch>,
-		InnerBlockImport,
-	>;
+type FullBeefyBlockImport<InnerBlockImport> =
+	beefy::import::BeefyBlockImport<Block, FullBackend, FullClient, InnerBlockImport>;
 
 #[cfg(feature = "full-node")]
-struct Basics<RuntimeApi, ExecutorDispatch>
-where
-	RuntimeApi: ConstructRuntimeApi<Block, FullClient<RuntimeApi, ExecutorDispatch>>
-		+ Send
-		+ Sync
-		+ 'static,
-	RuntimeApi::RuntimeApi:
-		RuntimeApiCollection<StateBackend = sc_client_api::StateBackendFor<FullBackend, Block>>,
-	ExecutorDispatch: NativeExecutionDispatch + 'static,
-{
+struct Basics {
 	task_manager: TaskManager,
-	client: Arc<FullClient<RuntimeApi, ExecutorDispatch>>,
+	client: Arc<FullClient>,
 	backend: Arc<FullBackend>,
 	keystore_container: KeystoreContainer,
 	telemetry: Option<Telemetry>,
 }
 
 #[cfg(feature = "full-node")]
-fn new_partial_basics<RuntimeApi, ExecutorDispatch>(
+fn new_partial_basics(
 	config: &mut Configuration,
 	jaeger_agent: Option<std::net::SocketAddr>,
 	telemetry_worker_handle: Option<TelemetryWorkerHandle>,
-) -> Result<Basics<RuntimeApi, ExecutorDispatch>, Error>
-where
-	RuntimeApi: ConstructRuntimeApi<Block, FullClient<RuntimeApi, ExecutorDispatch>>
-		+ Send
-		+ Sync
-		+ 'static,
-	RuntimeApi::RuntimeApi:
-		RuntimeApiCollection<StateBackend = sc_client_api::StateBackendFor<FullBackend, Block>>,
-	ExecutorDispatch: NativeExecutionDispatch + 'static,
-{
+) -> Result<Basics, Error> {
 	let telemetry = config
 		.telemetry_endpoints
 		.clone()
@@ -410,7 +414,7 @@ where
 		.default_heap_pages
 		.map_or(DEFAULT_HEAP_ALLOC_STRATEGY, |h| HeapAllocStrategy::Static { extra_pages: h as _ });
 
-	let wasm = WasmExecutor::builder()
+	let executor = WasmExecutor::builder()
 		.with_execution_method(config.wasm_method)
 		.with_onchain_heap_alloc_strategy(heap_pages)
 		.with_offchain_heap_alloc_strategy(heap_pages)
@@ -418,8 +422,6 @@ where
 		.with_runtime_cache_size(config.runtime_cache_size)
 		.build();
 
-	let executor = NativeElseWasmExecutor::<ExecutorDispatch>::new_with_wasm_executor(wasm);
-
 	let (client, backend, keystore_container, task_manager) =
 		service::new_full_parts::<Block, RuntimeApi, _>(
 			&config,
@@ -445,20 +447,17 @@ where
 }
 
 #[cfg(feature = "full-node")]
-fn new_partial<RuntimeApi, ExecutorDispatch, ChainSelection>(
+fn new_partial<ChainSelection>(
 	config: &mut Configuration,
-	Basics { task_manager, backend, client, keystore_container, telemetry }: Basics<
-		RuntimeApi,
-		ExecutorDispatch,
-	>,
+	Basics { task_manager, backend, client, keystore_container, telemetry }: Basics,
 	select_chain: ChainSelection,
 ) -> Result<
 	service::PartialComponents<
-		FullClient<RuntimeApi, ExecutorDispatch>,
+		FullClient,
 		FullBackend,
 		ChainSelection,
-		sc_consensus::DefaultImportQueue<Block, FullClient<RuntimeApi, ExecutorDispatch>>,
-		sc_transaction_pool::FullPool<Block, FullClient<RuntimeApi, ExecutorDispatch>>,
+		sc_consensus::DefaultImportQueue<Block, FullClient>,
+		sc_transaction_pool::FullPool<Block, FullClient>,
 		(
 			impl Fn(
 				polkadot_rpc::DenyUnsafe,
@@ -467,14 +466,10 @@ fn new_partial<RuntimeApi, ExecutorDispatch, ChainSelection>(
 			(
 				babe::BabeBlockImport<
 					Block,
-					FullClient<RuntimeApi, ExecutorDispatch>,
-					FullBeefyBlockImport<
-						RuntimeApi,
-						ExecutorDispatch,
-						FullGrandpaBlockImport<RuntimeApi, ExecutorDispatch, ChainSelection>,
-					>,
+					FullClient,
+					FullBeefyBlockImport<FullGrandpaBlockImport<ChainSelection>>,
 				>,
-				grandpa::LinkHalf<Block, FullClient<RuntimeApi, ExecutorDispatch>, ChainSelection>,
+				grandpa::LinkHalf<Block, FullClient, ChainSelection>,
 				babe::BabeLink<Block>,
 				beefy::BeefyVoterLinks<Block>,
 			),
@@ -486,13 +481,6 @@ fn new_partial<RuntimeApi, ExecutorDispatch, ChainSelection>(
 	Error,
 >
 where
-	RuntimeApi: ConstructRuntimeApi<Block, FullClient<RuntimeApi, ExecutorDispatch>>
-		+ Send
-		+ Sync
-		+ 'static,
-	RuntimeApi::RuntimeApi:
-		RuntimeApiCollection<StateBackend = sc_client_api::StateBackendFor<FullBackend, Block>>,
-	ExecutorDispatch: NativeExecutionDispatch + 'static,
 	ChainSelection: 'static + SelectChain<Block>,
 {
 	let transaction_pool = sc_transaction_pool::BasicPool::new_full(
@@ -616,9 +604,9 @@ where
 }
 
 #[cfg(feature = "full-node")]
-pub struct NewFull<C> {
+pub struct NewFull {
 	pub task_manager: TaskManager,
-	pub client: C,
+	pub client: Arc<FullClient>,
 	pub overseer_handle: Option<Handle>,
 	pub network: Arc<sc_network::NetworkService<Block, <Block as BlockT>::Hash>>,
 	pub sync_service: Arc<sc_network_sync::SyncingService<Block>>,
@@ -626,22 +614,6 @@ pub struct NewFull<C> {
 	pub backend: Arc<FullBackend>,
 }
 
-#[cfg(feature = "full-node")]
-impl<C> NewFull<C> {
-	/// Convert the client type using the given `func`.
-	pub fn with_client<NC>(self, func: impl FnOnce(C) -> NC) -> NewFull<NC> {
-		NewFull {
-			client: func(self.client),
-			task_manager: self.task_manager,
-			overseer_handle: self.overseer_handle,
-			network: self.network,
-			sync_service: self.sync_service,
-			rpc_handlers: self.rpc_handlers,
-			backend: self.backend,
-		}
-	}
-}
-
 /// Is this node a collator?
 #[cfg(feature = "full-node")]
 #[derive(Clone)]
@@ -685,7 +657,7 @@ pub const AVAILABILITY_CONFIG: AvailabilityConfig = AvailabilityConfig {
 /// regardless of the role the node has. The relay chain selection (longest or disputes-aware) is
 /// still determined based on the role of the node. Likewise for authority discovery.
 #[cfg(feature = "full-node")]
-pub fn new_full<RuntimeApi, ExecutorDispatch, OverseerGenerator>(
+pub fn new_full<OverseerGenerator>(
 	mut config: Configuration,
 	is_collator: IsCollator,
 	grandpa_pause: Option<(u32, u32)>,
@@ -698,15 +670,8 @@ pub fn new_full<RuntimeApi, ExecutorDispatch, OverseerGenerator>(
 	overseer_message_channel_capacity_override: Option<usize>,
 	_malus_finality_delay: Option<u32>,
 	hwbench: Option<sc_sysinfo::HwBench>,
-) -> Result<NewFull<Arc<FullClient<RuntimeApi, ExecutorDispatch>>>, Error>
+) -> Result<NewFull, Error>
 where
-	RuntimeApi: ConstructRuntimeApi<Block, FullClient<RuntimeApi, ExecutorDispatch>>
-		+ Send
-		+ Sync
-		+ 'static,
-	RuntimeApi::RuntimeApi:
-		RuntimeApiCollection<StateBackend = sc_client_api::StateBackendFor<FullBackend, Block>>,
-	ExecutorDispatch: NativeExecutionDispatch + 'static,
 	OverseerGenerator: OverseerGen,
 {
 	use polkadot_node_network_protocol::request_response::IncomingRequest;
@@ -743,11 +708,7 @@ where
 	let disable_grandpa = config.disable_grandpa;
 	let name = config.network.node_name.clone();
 
-	let basics = new_partial_basics::<RuntimeApi, ExecutorDispatch>(
-		&mut config,
-		jaeger_agent,
-		telemetry_worker_handle,
-	)?;
+	let basics = new_partial_basics(&mut config, jaeger_agent, telemetry_worker_handle)?;
 
 	let prometheus_registry = config.prometheus_registry().cloned();
 
@@ -783,11 +744,7 @@ where
 		import_queue,
 		transaction_pool,
 		other: (rpc_extensions_builder, import_setup, rpc_setup, slot_duration, mut telemetry),
-	} = new_partial::<RuntimeApi, ExecutorDispatch, SelectRelayChain<_>>(
-		&mut config,
-		basics,
-		select_chain,
-	)?;
+	} = new_partial::<SelectRelayChain<_>>(&mut config, basics, select_chain)?;
 
 	let shared_voter_state = rpc_setup;
 	let auth_disc_publish_non_global_ips = config.network.allow_non_globals_in_dht;
@@ -1003,7 +960,7 @@ where
 
 	let overseer_handle = if let Some(authority_discovery_service) = authority_discovery_service {
 		let (overseer, overseer_handle) = overseer_gen
-			.generate::<service::SpawnTaskHandle, FullClient<RuntimeApi, ExecutorDispatch>>(
+			.generate::<service::SpawnTaskHandle, FullClient>(
 				overseer_connector,
 				OverseerGenArgs {
 					keystore,
@@ -1259,27 +1216,19 @@ where
 
 #[cfg(feature = "full-node")]
 macro_rules! chain_ops {
-	($config:expr, $jaeger_agent:expr, $telemetry_worker_handle:expr; $scope:ident, $executor:ident, $variant:ident) => {{
+	($config:expr, $jaeger_agent:expr, $telemetry_worker_handle:expr) => {{
 		let telemetry_worker_handle = $telemetry_worker_handle;
 		let jaeger_agent = $jaeger_agent;
 		let mut config = $config;
-		let basics = new_partial_basics::<$scope::RuntimeApi, $executor>(
-			config,
-			jaeger_agent,
-			telemetry_worker_handle,
-		)?;
+		let basics = new_partial_basics(config, jaeger_agent, telemetry_worker_handle)?;
 
 		use ::sc_consensus::LongestChain;
 		// use the longest chain selection, since there is no overseer available
 		let chain_selection = LongestChain::new(basics.backend.clone());
 
 		let service::PartialComponents { client, backend, import_queue, task_manager, .. } =
-			new_partial::<$scope::RuntimeApi, $executor, LongestChain<_, Block>>(
-				&mut config,
-				basics,
-				chain_selection,
-			)?;
-		Ok((Arc::new(Client::$variant(client)), backend, import_queue, task_manager))
+			new_partial::<LongestChain<_, Block>>(&mut config, basics, chain_selection)?;
+		Ok((client, backend, import_queue, task_manager))
 	}};
 }
 
@@ -1290,7 +1239,7 @@ pub fn new_chain_ops(
 	jaeger_agent: Option<std::net::SocketAddr>,
 ) -> Result<
 	(
-		Arc<Client>,
+		Arc<FullClient>,
 		Arc<FullBackend>,
 		sc_consensus::BasicQueue<Block, PrefixedMemoryDB<BlakeTwo256>>,
 		TaskManager,
@@ -1299,35 +1248,17 @@ pub fn new_chain_ops(
 > {
 	config.keystore = service::config::KeystoreConfig::InMemory;
 
-	#[cfg(feature = "rococo-native")]
 	if config.chain_spec.is_rococo() ||
 		config.chain_spec.is_wococo() ||
 		config.chain_spec.is_versi()
 	{
-		return chain_ops!(config, jaeger_agent, None; rococo_runtime, RococoExecutorDispatch, Rococo)
-	}
-
-	#[cfg(feature = "kusama-native")]
-	if config.chain_spec.is_kusama() {
-		return chain_ops!(config, jaeger_agent, None; kusama_runtime, KusamaExecutorDispatch, Kusama)
-	}
-
-	#[cfg(feature = "westend-native")]
-	if config.chain_spec.is_westend() {
-		return chain_ops!(config, jaeger_agent, None; westend_runtime, WestendExecutorDispatch, Westend)
-	}
-
-	#[cfg(feature = "polkadot-native")]
-	{
-		return chain_ops!(config, jaeger_agent, None; polkadot_runtime, PolkadotExecutorDispatch, Polkadot)
-	}
-
-	#[cfg(not(feature = "polkadot-native"))]
-	{
-		let _ = config;
-		let _ = jaeger_agent;
-
-		Err(Error::NoRuntime)
+		chain_ops!(config, jaeger_agent, None)
+	} else if config.chain_spec.is_kusama() {
+		chain_ops!(config, jaeger_agent, None)
+	} else if config.chain_spec.is_westend() {
+		return chain_ops!(config, jaeger_agent, None)
+	} else {
+		chain_ops!(config, jaeger_agent, None)
 	}
 }
 
@@ -1352,105 +1283,28 @@ pub fn build_full(
 	overseer_message_channel_override: Option<usize>,
 	malus_finality_delay: Option<u32>,
 	hwbench: Option<sc_sysinfo::HwBench>,
-) -> Result<NewFull<Client>, Error> {
-	#[cfg(feature = "rococo-native")]
-	if config.chain_spec.is_rococo() ||
-		config.chain_spec.is_wococo() ||
-		config.chain_spec.is_versi()
-	{
-		return new_full::<rococo_runtime::RuntimeApi, RococoExecutorDispatch, _>(
-			config,
-			is_collator,
-			grandpa_pause,
-			enable_beefy,
-			jaeger_agent,
-			telemetry_worker_handle,
-			None,
-			overseer_enable_anyways,
-			overseer_gen,
-			overseer_message_channel_override,
-			malus_finality_delay,
-			hwbench,
-		)
-		.map(|full| full.with_client(Client::Rococo))
-	}
-
-	#[cfg(feature = "kusama-native")]
-	if config.chain_spec.is_kusama() {
-		return new_full::<kusama_runtime::RuntimeApi, KusamaExecutorDispatch, _>(
-			config,
-			is_collator,
-			grandpa_pause,
-			enable_beefy,
-			jaeger_agent,
-			telemetry_worker_handle,
-			None,
-			overseer_enable_anyways,
-			overseer_gen,
-			overseer_message_channel_override,
-			malus_finality_delay,
-			hwbench,
-		)
-		.map(|full| full.with_client(Client::Kusama))
-	}
+) -> Result<NewFull, Error> {
+	let is_polkadot = config.chain_spec.is_polkadot();
 
-	#[cfg(feature = "westend-native")]
-	if config.chain_spec.is_westend() {
-		return new_full::<westend_runtime::RuntimeApi, WestendExecutorDispatch, _>(
-			config,
-			is_collator,
-			grandpa_pause,
-			enable_beefy,
-			jaeger_agent,
-			telemetry_worker_handle,
-			None,
-			overseer_enable_anyways,
-			overseer_gen,
-			overseer_message_channel_override,
-			malus_finality_delay,
-			hwbench,
-		)
-		.map(|full| full.with_client(Client::Westend))
-	}
-
-	#[cfg(feature = "polkadot-native")]
-	{
-		return new_full::<polkadot_runtime::RuntimeApi, PolkadotExecutorDispatch, _>(
-			config,
-			is_collator,
-			grandpa_pause,
-			enable_beefy,
-			jaeger_agent,
-			telemetry_worker_handle,
-			None,
-			overseer_enable_anyways,
-			overseer_gen,
-			overseer_message_channel_override.map(|capacity| {
+	new_full(
+		config,
+		is_collator,
+		grandpa_pause,
+		enable_beefy,
+		jaeger_agent,
+		telemetry_worker_handle,
+		None,
+		overseer_enable_anyways,
+		overseer_gen,
+		overseer_message_channel_override.map(move |capacity| {
+			if is_polkadot {
 				gum::warn!("Channel capacity should _never_ be tampered with on polkadot!");
-				capacity
-			}),
-			malus_finality_delay,
-			hwbench,
-		)
-		.map(|full| full.with_client(Client::Polkadot))
-	}
-
-	#[cfg(not(feature = "polkadot-native"))]
-	{
-		let _ = config;
-		let _ = is_collator;
-		let _ = grandpa_pause;
-		let _ = enable_beefy;
-		let _ = jaeger_agent;
-		let _ = telemetry_worker_handle;
-		let _ = overseer_enable_anyways;
-		let _ = overseer_gen;
-		let _ = overseer_message_channel_override;
-		let _ = malus_finality_delay;
-		let _ = hwbench;
-
-		Err(Error::NoRuntime)
-	}
+			}
+			capacity
+		}),
+		malus_finality_delay,
+		hwbench,
+	)
 }
 
 /// Reverts the node state down to at most the last finalized block.
@@ -1461,7 +1315,7 @@ pub fn build_full(
 /// - Low level Babe and Grandpa consensus data.
 #[cfg(feature = "full-node")]
 pub fn revert_backend(
-	client: Arc<Client>,
+	client: Arc<FullClient>,
 	backend: Arc<FullBackend>,
 	blocks: BlockNumber,
 	config: Configuration,
@@ -1488,7 +1342,8 @@ pub fn revert_backend(
 	revert_approval_voting(parachains_db.clone(), hash)?;
 	revert_chain_selection(parachains_db, hash)?;
 	// Revert Substrate consensus related components
-	client.execute_with(RevertConsensus { blocks, backend })?;
+	babe::revert(client.clone(), backend, blocks)?;
+	grandpa::revert(client, blocks)?;
 
 	Ok(())
 }
@@ -1525,27 +1380,3 @@ fn revert_approval_voting(db: Arc<dyn Database>, hash: Hash) -> sp_blockchain::R
 		.revert_to(hash)
 		.map_err(|err| sp_blockchain::Error::Backend(err.to_string()))
 }
-
-struct RevertConsensus {
-	blocks: BlockNumber,
-	backend: Arc<FullBackend>,
-}
-
-impl ExecuteWithClient for RevertConsensus {
-	type Output = sp_blockchain::Result<()>;
-
-	fn execute_with_client<Client, Api, Backend>(self, client: Arc<Client>) -> Self::Output
-	where
-		<Api as sp_api::ApiExt<Block>>::StateBackend: sp_api::StateBackend<BlakeTwo256>,
-		Backend: sc_client_api::Backend<Block> + 'static,
-		Backend::State: sp_api::StateBackend<BlakeTwo256>,
-		Api: polkadot_client::RuntimeApiCollection<StateBackend = Backend::State>,
-		Client: AbstractClient<Block, Backend, Api = Api> + 'static,
-	{
-		// Revert consensus-related components.
-		// The operations are not correlated, thus call order is not relevant.
-		babe::revert(client.clone(), self.backend, self.blocks)?;
-		grandpa::revert(client, self.blocks)?;
-		Ok(())
-	}
-}
diff --git a/polkadot/node/test/client/Cargo.toml b/polkadot/node/test/client/Cargo.toml
index 7f61ed2408ab43bc54d2b30e37b379a3ab933851..366d244952c15d52012e89ebb14aa5a9246f094e 100644
--- a/polkadot/node/test/client/Cargo.toml
+++ b/polkadot/node/test/client/Cargo.toml
@@ -18,6 +18,7 @@ substrate-test-client = { git = "https://github.com/paritytech/substrate", branc
 sc-service = { git = "https://github.com/paritytech/substrate", branch = "master" }
 sc-block-builder = { git = "https://github.com/paritytech/substrate", branch = "master" }
 sc-consensus = { git = "https://github.com/paritytech/substrate", branch = "master" }
+sc-offchain = { git = "https://github.com/paritytech/substrate", branch = "master" }
 sp-blockchain = { git = "https://github.com/paritytech/substrate", branch = "master" }
 sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" }
 sp-inherents = { git = "https://github.com/paritytech/substrate", branch = "master" }
@@ -27,6 +28,8 @@ sp-timestamp = { git = "https://github.com/paritytech/substrate", branch = "mast
 sp-consensus = { git = "https://github.com/paritytech/substrate", branch = "master" }
 sp-consensus-babe = { git = "https://github.com/paritytech/substrate", branch = "master" }
 sp-state-machine = { git = "https://github.com/paritytech/substrate", branch = "master" }
+sp-io = { git = "https://github.com/paritytech/substrate", branch = "master" }
+frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "master" }
 
 [dev-dependencies]
 sp-keyring = { git = "https://github.com/paritytech/substrate", branch = "master" }
diff --git a/polkadot/node/test/client/src/block_builder.rs b/polkadot/node/test/client/src/block_builder.rs
index 33b01d018d041f5a6538254beb9e7d9c27115e12..88160e782a703fbabaac33f7e4156bac1fd30e63 100644
--- a/polkadot/node/test/client/src/block_builder.rs
+++ b/polkadot/node/test/client/src/block_builder.rs
@@ -17,7 +17,8 @@
 use crate::{Client, FullBackend};
 use parity_scale_codec::{Decode, Encode};
 use polkadot_primitives::{Block, InherentData as ParachainsInherentData};
-use polkadot_test_runtime::{GetLastTimestamp, UncheckedExtrinsic};
+use polkadot_test_runtime::UncheckedExtrinsic;
+use polkadot_test_service::GetLastTimestamp;
 use sc_block_builder::{BlockBuilder, BlockBuilderProvider};
 use sp_api::ProvideRuntimeApi;
 use sp_consensus_babe::{
diff --git a/polkadot/node/test/client/src/lib.rs b/polkadot/node/test/client/src/lib.rs
index 457634a9e1660aad6601b5f7b6e164d39737bdac..2996bc84c763a9f92d3a28e7587ab600df1a69b8 100644
--- a/polkadot/node/test/client/src/lib.rs
+++ b/polkadot/node/test/client/src/lib.rs
@@ -22,12 +22,12 @@ mod block_builder;
 
 use polkadot_primitives::Block;
 use sp_runtime::BuildStorage;
+use std::sync::Arc;
 
 pub use block_builder::*;
 pub use polkadot_test_runtime as runtime;
 pub use polkadot_test_service::{
 	construct_extrinsic, construct_transfer_extrinsic, Client, FullBackend,
-	PolkadotTestExecutorDispatch,
 };
 pub use substrate_test_client::*;
 
@@ -35,7 +35,7 @@ pub use substrate_test_client::*;
 pub type Executor = client::LocalCallExecutor<
 	Block,
 	FullBackend,
-	sc_executor::NativeElseWasmExecutor<PolkadotTestExecutorDispatch>,
+	WasmExecutor<(sp_io::SubstrateHostFunctions, frame_benchmarking::benchmarking::HostFunctions)>,
 >;
 
 /// Test client builder for Polkadot.
@@ -70,7 +70,21 @@ pub trait TestClientBuilderExt: Sized {
 
 impl TestClientBuilderExt for TestClientBuilder {
 	fn build_with_longest_chain(self) -> (Client, LongestChain) {
-		self.build_with_native_executor(None)
+		let executor = WasmExecutor::builder().build();
+		let executor = client::LocalCallExecutor::new(
+			self.backend().clone(),
+			executor.clone(),
+			Default::default(),
+			ExecutionExtensions::new(
+				Default::default(),
+				None,
+				sc_offchain::OffchainDb::factory_from_backend(&*self.backend()),
+				Arc::new(executor),
+			),
+		)
+		.unwrap();
+
+		self.build_with_executor(executor)
 	}
 }
 
diff --git a/polkadot/node/test/service/Cargo.toml b/polkadot/node/test/service/Cargo.toml
index 8bf8ba6976bfd7ab5add21dd3bd33d7c72d71568..504ee5beca744ebe2cfc2c62263702a2dc9c9776 100644
--- a/polkadot/node/test/service/Cargo.toml
+++ b/polkadot/node/test/service/Cargo.toml
@@ -31,7 +31,6 @@ sc-authority-discovery = { git = "https://github.com/paritytech/substrate", bran
 babe = { package = "sc-consensus-babe", git = "https://github.com/paritytech/substrate", branch = "master" }
 babe-primitives = { package = "sp-consensus-babe", git = "https://github.com/paritytech/substrate", branch = "master" }
 consensus_common = { package = "sp-consensus", git = "https://github.com/paritytech/substrate", branch = "master" }
-frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "master" }
 frame-system = { git = "https://github.com/paritytech/substrate", branch = "master" }
 grandpa = { package = "sc-consensus-grandpa", git = "https://github.com/paritytech/substrate", branch = "master" }
 grandpa_primitives = { package = "sp-consensus-grandpa", git = "https://github.com/paritytech/substrate", branch = "master" }
@@ -43,7 +42,6 @@ sc-chain-spec = { git = "https://github.com/paritytech/substrate", branch = "mas
 sc-cli = { git = "https://github.com/paritytech/substrate", branch = "master" }
 sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
 sc-consensus = { git = "https://github.com/paritytech/substrate", branch = "master" }
-sc-executor = { git = "https://github.com/paritytech/substrate", branch = "master" }
 sc-network = { git = "https://github.com/paritytech/substrate", branch = "master" }
 sc-tracing = { git = "https://github.com/paritytech/substrate", branch = "master" }
 sc-transaction-pool = { git = "https://github.com/paritytech/substrate", branch = "master" }
diff --git a/polkadot/node/test/service/src/lib.rs b/polkadot/node/test/service/src/lib.rs
index 3e7f66128886de07660a83006b3238bd4b4d81a7..08d09f8fe69a948b2372bbdda8de4960aa2fe0b5 100644
--- a/polkadot/node/test/service/src/lib.rs
+++ b/polkadot/node/test/service/src/lib.rs
@@ -28,9 +28,7 @@ use polkadot_overseer::Handle;
 use polkadot_primitives::{Balance, CollatorPair, HeadData, Id as ParaId, ValidationCode};
 use polkadot_runtime_common::BlockHashCount;
 use polkadot_runtime_parachains::paras::{ParaGenesisArgs, ParaKind};
-use polkadot_service::{
-	ClientHandle, Error, ExecuteWithClient, FullClient, IsCollator, NewFull, PrometheusConfig,
-};
+use polkadot_service::{Error, FullClient, IsCollator, NewFull, PrometheusConfig};
 use polkadot_test_runtime::{
 	ParasCall, ParasSudoWrapperCall, Runtime, SignedExtra, SignedPayload, SudoCall,
 	UncheckedExtrinsic, VERSION,
@@ -63,26 +61,11 @@ use std::{
 use substrate_test_client::{
 	BlockchainEventsExt, RpcHandlersExt, RpcTransactionError, RpcTransactionOutput,
 };
-/// Declare an instance of the native executor named `PolkadotTestExecutorDispatch`. Include the wasm binary as the
-/// equivalent wasm code.
-pub struct PolkadotTestExecutorDispatch;
-
-impl sc_executor::NativeExecutionDispatch for PolkadotTestExecutorDispatch {
-	type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions;
-
-	fn dispatch(method: &str, data: &[u8]) -> Option<Vec<u8>> {
-		polkadot_test_runtime::api::dispatch(method, data)
-	}
-
-	fn native_version() -> sc_executor::NativeVersion {
-		polkadot_test_runtime::native_version()
-	}
-}
 
 /// The client type being used by the test service.
-pub type Client = FullClient<polkadot_test_runtime::RuntimeApi, PolkadotTestExecutorDispatch>;
+pub type Client = FullClient;
 
-pub use polkadot_service::FullBackend;
+pub use polkadot_service::{FullBackend, GetLastTimestamp};
 
 /// Create a new full node.
 #[sc_tracing::logging::prefix_logs_with(config.network.node_name.as_str())]
@@ -90,8 +73,8 @@ pub fn new_full(
 	config: Configuration,
 	is_collator: IsCollator,
 	worker_program_path: Option<PathBuf>,
-) -> Result<NewFull<Arc<Client>>, Error> {
-	polkadot_service::new_full::<polkadot_test_runtime::RuntimeApi, PolkadotTestExecutorDispatch, _>(
+) -> Result<NewFull, Error> {
+	polkadot_service::new_full(
 		config,
 		is_collator,
 		None,
@@ -107,15 +90,6 @@ pub fn new_full(
 	)
 }
 
-/// A wrapper for the test client that implements `ClientHandle`.
-pub struct TestClient(pub Arc<Client>);
-
-impl ClientHandle for TestClient {
-	fn execute_with<T: ExecuteWithClient>(&self, t: T) -> T::Output {
-		T::execute_with_client::<_, _, polkadot_service::FullBackend>(t, self.0.clone())
-	}
-}
-
 /// Returns a prometheus config usable for testing.
 pub fn test_prometheus_config(port: u16) -> PrometheusConfig {
 	PrometheusConfig::new_with_default_registry(
diff --git a/polkadot/tests/purge_chain_works.rs b/polkadot/tests/purge_chain_works.rs
index c93a0dde9a8dc2fdfe33e53eb13f3a45472fb760..3e9a378147810e5d2edf377fa7c5ed93ecf16952 100644
--- a/polkadot/tests/purge_chain_works.rs
+++ b/polkadot/tests/purge_chain_works.rs
@@ -55,9 +55,9 @@ async fn purge_chain_rocksdb_works() {
 	kill(Pid::from_raw(cmd.id().try_into().unwrap()), SIGINT).unwrap();
 	// Wait for the node to handle it and exit.
 	assert!(common::wait_for(&mut cmd, 30).map(|x| x.success()).unwrap_or_default());
-	assert!(tmpdir.path().join("chains/dev").exists());
-	assert!(tmpdir.path().join("chains/dev/db/full").exists());
-	assert!(tmpdir.path().join("chains/dev/db/full/parachains").exists());
+	assert!(tmpdir.path().join("chains/polkadot_dev").exists());
+	assert!(tmpdir.path().join("chains/polkadot_dev/db/full").exists());
+	assert!(tmpdir.path().join("chains/polkadot_dev/db/full/parachains").exists());
 
 	// Purge chain
 	let status = Command::new(cargo_bin("polkadot"))
@@ -69,8 +69,8 @@ async fn purge_chain_rocksdb_works() {
 	assert!(status.success());
 
 	// Make sure that the chain folder exists, but `db/full` is deleted.
-	assert!(tmpdir.path().join("chains/dev").exists());
-	assert!(!tmpdir.path().join("chains/dev/db/full").exists());
+	assert!(tmpdir.path().join("chains/polkadot_dev").exists());
+	assert!(!tmpdir.path().join("chains/polkadot_dev/db/full").exists());
 }
 
 #[tokio::test]
@@ -105,9 +105,9 @@ async fn purge_chain_paritydb_works() {
 	kill(Pid::from_raw(cmd.id().try_into().unwrap()), SIGINT).unwrap();
 	// Wait for the node to handle it and exit.
 	assert!(common::wait_for(&mut cmd, 30).map(|x| x.success()).unwrap_or_default());
-	assert!(tmpdir.path().join("chains/dev").exists());
-	assert!(tmpdir.path().join("chains/dev/paritydb/full").exists());
-	assert!(tmpdir.path().join("chains/dev/paritydb/parachains").exists());
+	assert!(tmpdir.path().join("chains/polkadot_dev").exists());
+	assert!(tmpdir.path().join("chains/polkadot_dev/paritydb/full").exists());
+	assert!(tmpdir.path().join("chains/polkadot_dev/paritydb/parachains").exists());
 
 	// Purge chain
 	let status = Command::new(cargo_bin("polkadot"))
@@ -121,8 +121,8 @@ async fn purge_chain_paritydb_works() {
 	assert!(status.success());
 
 	// Make sure that the chain folder exists, but `db/full` is deleted.
-	assert!(tmpdir.path().join("chains/dev").exists());
-	assert!(!tmpdir.path().join("chains/dev/paritydb/full").exists());
+	assert!(tmpdir.path().join("chains/polkadot_dev").exists());
+	assert!(!tmpdir.path().join("chains/polkadot_dev/paritydb/full").exists());
 	// Parachains removal requires calling "purge-chain --parachains".
-	assert!(tmpdir.path().join("chains/dev/paritydb/parachains").exists());
+	assert!(tmpdir.path().join("chains/polkadot_dev/paritydb/parachains").exists());
 }