diff --git a/polkadot/Cargo.lock b/polkadot/Cargo.lock
index bf31c0490dafa093e450d3df98d6369524e2fa11..e3d65f29222128c985e5dcdc8e4781c72e44611d 100644
--- a/polkadot/Cargo.lock
+++ b/polkadot/Cargo.lock
@@ -5997,7 +5997,7 @@ dependencies = [
 
 [[package]]
 name = "rococo-runtime"
-version = "0.8.14"
+version = "0.8.22"
 dependencies = [
  "bitvec",
  "frame-benchmarking",
@@ -6073,7 +6073,7 @@ dependencies = [
 
 [[package]]
 name = "rococo-v1-runtime"
-version = "0.8.19"
+version = "0.8.22"
 dependencies = [
  "frame-executive",
  "frame-support",
diff --git a/polkadot/cli/src/browser.rs b/polkadot/cli/src/browser.rs
index 17ef9ae802299dd01d68d217fe67a95c3d3c4b91..d3523e92a60005ff305963cf7bff516e1a67341a 100644
--- a/polkadot/cli/src/browser.rs
+++ b/polkadot/cli/src/browser.rs
@@ -46,8 +46,7 @@ async fn start_inner(chain_spec: String, log_level: String) -> Result<Client, Bo
 	info!("👤 Role: {}", config.display_role());
 
 	// Create the service. This is the most heavy initialization step.
-	let builder = service::NodeBuilder::new(config);
-	let (task_manager, rpc_handlers) = builder.build_light().map_err(|e| format!("{:?}", e))?;
+	let (task_manager, rpc_handlers) = service::build_light(config).map_err(|e| format!("{:?}", e))?;
 
 	Ok(browser_utils::start_client(task_manager, rpc_handlers))
 }
diff --git a/polkadot/cli/src/command.rs b/polkadot/cli/src/command.rs
index 5537af7907c8c0f69d45665749328ba112991563..2d256374cdc73a5803857ac16a834b0b1fdb14a2 100644
--- a/polkadot/cli/src/command.rs
+++ b/polkadot/cli/src/command.rs
@@ -131,17 +131,17 @@ pub fn run() -> Result<()> {
 
 			runner.run_node_until_exit(|config| {
 				let role = config.role.clone();
-				let builder = service::NodeBuilder::new(config);
 
 				match role {
-					Role::Light => builder.build_light().map(|(task_manager, _)| task_manager),
-					_ => builder.build_full(
+					Role::Light => service::build_light(config).map(|(task_manager, _)| task_manager),
+					_ => service::build_full(
+						config,
 						None,
 						None,
 						authority_discovery_disabled,
 						6000,
 						grandpa_pause,
-					),
+					).map(|r| r.0),
 				}
 			})
 		},
diff --git a/polkadot/collator/src/lib.rs b/polkadot/collator/src/lib.rs
index 3eee4aba1e85c25fff469a8213ca9381e390e5a2..cfe400051327ac06897572a10e8cca2a74ad4dfd 100644
--- a/polkadot/collator/src/lib.rs
+++ b/polkadot/collator/src/lib.rs
@@ -51,8 +51,6 @@ use std::time::Duration;
 use std::pin::Pin;
 
 use futures::{future, Future, Stream, FutureExt, StreamExt};
-use sc_client_api::{StateBackend, BlockchainEvents};
-use sp_blockchain::HeaderBackend;
 use sp_core::Pair;
 use polkadot_primitives::v0::{
 	BlockId, Hash, Block, DownwardMessage,
@@ -60,27 +58,24 @@ use polkadot_primitives::v0::{
 	PoVBlock, ValidatorId, CollatorPair, LocalValidationData, GlobalValidationData,
 	Collation, CollationInfo, collator_signature_payload,
 };
-use polkadot_cli::{
-	ProvideRuntimeApi, ParachainHost, IdentifyVariant,
-	service::{self, Role}
-};
+use polkadot_cli::service::{self, Role};
 pub use polkadot_cli::service::Configuration;
 pub use polkadot_cli::Cli;
 pub use polkadot_validation::SignedStatement;
 pub use polkadot_primitives::v0::CollatorId;
 pub use sc_network::PeerId;
-pub use service::RuntimeApiCollection;
+pub use service::{RuntimeApiCollection, Client};
 pub use sc_cli::SubstrateCli;
-use sp_api::{ConstructRuntimeApi, ApiExt, HashFor};
 #[cfg(not(feature = "service-rewr"))]
-use polkadot_service::{FullNodeHandles, PolkadotClient};
+use polkadot_service::{FullNodeHandles, AbstractClient};
 #[cfg(feature = "service-rewr")]
 use polkadot_service_new::{
 	self as polkadot_service,
-	Error as ServiceError, FullNodeHandles, PolkadotClient,
+	Error as ServiceError, FullNodeHandles, AbstractClient,
 };
 use sc_service::SpawnTaskHandle;
 use sp_core::traits::SpawnNamed;
+use sp_runtime::traits::BlakeTwo256;
 
 const COLLATION_TIMEOUT: Duration = Duration::from_secs(30);
 
@@ -121,16 +116,13 @@ pub trait BuildParachainContext {
 	type ParachainContext: self::ParachainContext;
 
 	/// Build the `ParachainContext`.
-	fn build<Client, SP>(
+	fn build<SP>(
 		self,
-		client: Arc<Client>,
+		client: polkadot_service::Client,
 		spawner: SP,
 		network: impl Network + Clone + 'static,
 	) -> Result<Self::ParachainContext, ()>
 		where
-			Client: ProvideRuntimeApi<Block> + HeaderBackend<Block> + BlockchainEvents<Block> + Send + Sync + 'static,
-			Client::Api: RuntimeApiCollection,
-			<Client::Api as ApiExt<Block>>::StateBackend: StateBackend<HashFor<Block>>,
 			SP: SpawnNamed + Clone + Send + Sync + 'static;
 }
 
@@ -202,171 +194,179 @@ pub async fn collate<P>(
 }
 
 #[cfg(feature = "service-rewr")]
-fn build_collator_service<SP, P, C, R>(
-	_spawner: SP,
-	_handles: FullNodeHandles,
-	_client: Arc<C>,
-	_para_id: ParaId,
-	_key: Arc<CollatorPair>,
-	_build_parachain_context: P,
-) -> Result<future::Ready<()>, polkadot_service::Error>
+fn build_collator_service<P>(
+	spawner: SpawnTaskHandle,
+	handles: FullNodeHandles,
+	client: polkadot_service::Client,
+	para_id: ParaId,
+	key: Arc<CollatorPair>,
+	build_parachain_context: P,
+) -> Result<Pin<Box<dyn Future<Output = ()> + Send + 'static>>, polkadot_service::Error>
 	where
-		C: PolkadotClient<
-			service::Block,
-			service::TFullBackend<service::Block>,
-			R
-		> + 'static,
-		R: ConstructRuntimeApi<service::Block, C> + Sync + Send,
-		<R as ConstructRuntimeApi<service::Block, C>>::RuntimeApi:
-			sp_api::ApiExt<
-				service::Block,
-				StateBackend = <service::TFullBackend<service::Block> as service::Backend<service::Block>>::State,
-			>
-			+ RuntimeApiCollection<
-				StateBackend = <service::TFullBackend<service::Block> as service::Backend<service::Block>>::State,
-			>
-			+ Sync + Send,
 		P: BuildParachainContext,
 		P::ParachainContext: Send + 'static,
 		<P::ParachainContext as ParachainContext>::ProduceCandidate: Send,
-		SP: SpawnNamed + Clone + Send + Sync + 'static,
 {
 	Err("Collator is not functional with the new service yet".into())
 }
 
-
-#[cfg(not(feature = "service-rewr"))]
-fn build_collator_service<P, C, R>(
-	spawner: SpawnTaskHandle,
-	handles: FullNodeHandles,
-	client: Arc<C>,
+struct BuildCollationWork<P> {
+	handles: polkadot_service::FullNodeHandles,
 	para_id: ParaId,
 	key: Arc<CollatorPair>,
 	build_parachain_context: P,
-) -> Result<impl Future<Output = ()> + Send + 'static, polkadot_service::Error>
+	spawner: SpawnTaskHandle,
+	client: polkadot_service::Client,
+}
+
+impl<P> polkadot_service::ExecuteWithClient for BuildCollationWork<P>
 	where
-		C: PolkadotClient<
-			service::Block,
-			service::TFullBackend<service::Block>,
-			R
-		> + 'static,
-		R: ConstructRuntimeApi<service::Block, C> + Sync + Send,
-		<R as ConstructRuntimeApi<service::Block, C>>::RuntimeApi:
-			sp_api::ApiExt<
-				service::Block,
-				StateBackend = <service::TFullBackend<service::Block> as service::Backend<service::Block>>::State,
-			>
-			+ RuntimeApiCollection<
-				StateBackend = <service::TFullBackend<service::Block> as service::Backend<service::Block>>::State,
-			>
-			+ Sync + Send,
 		P: BuildParachainContext,
 		P::ParachainContext: Send + 'static,
 		<P::ParachainContext as ParachainContext>::ProduceCandidate: Send,
 {
-	let polkadot_network = handles.polkadot_network
-		.ok_or_else(|| "Collator cannot run when Polkadot-specific networking has not been started")?;
-
-	// We don't require this here, but we need to make sure that the validation service is started.
-	// This service makes sure the collator is joining the correct gossip topics and receives the appropiate
-	// messages.
-	handles.validation_service_handle
-		.ok_or_else(|| "Collator cannot run when validation networking has not been started")?;
-
-	let parachain_context = match build_parachain_context.build(
-		client.clone(),
-		spawner.clone(),
-		polkadot_network.clone(),
-	) {
-		Ok(ctx) => ctx,
-		Err(()) => {
-			return Err("Could not build the parachain context!".into())
-		}
-	};
-
-	let work = async move {
-		let mut notification_stream = client.import_notification_stream();
-
-		while let Some(notification) = notification_stream.next().await {
-			macro_rules! try_fr {
-				($e:expr) => {
-					match $e {
-						Ok(x) => x,
-						Err(e) => return future::Either::Left(future::err(Error::Polkadot(
-							format!("{:?}", e)
-						))),
+	type Output = Result<Pin<Box<dyn Future<Output = ()> + Send + 'static>>, polkadot_service::Error>;
+
+	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>,
+		Backend::State: sp_api::StateBackend<BlakeTwo256>,
+		Api: RuntimeApiCollection<StateBackend = Backend::State>,
+		Client: AbstractClient<Block, Backend, Api = Api> + 'static
+	{
+		let polkadot_network = self.handles
+			.polkadot_network
+			.ok_or_else(|| "Collator cannot run when Polkadot-specific networking has not been started")?;
+
+		// We don't require this here, but we need to make sure that the validation service is started.
+		// This service makes sure the collator is joining the correct gossip topics and receives the appropiate
+		// messages.
+		self.handles.validation_service_handle
+			.ok_or_else(|| "Collator cannot run when validation networking has not been started")?;
+
+		let parachain_context = match self.build_parachain_context.build(
+			self.client,
+			self.spawner.clone(),
+			polkadot_network.clone(),
+		) {
+			Ok(ctx) => ctx,
+			Err(()) => {
+				return Err("Could not build the parachain context!".into())
+			}
+		};
+
+		let key = self.key;
+		let para_id = self.para_id;
+		let spawner = self.spawner;
+
+		let res = async move {
+			let mut notification_stream = client.import_notification_stream();
+
+			while let Some(notification) = notification_stream.next().await {
+				macro_rules! try_fr {
+					($e:expr) => {
+						match $e {
+							Ok(x) => x,
+							Err(e) => return future::Either::Left(future::err(Error::Polkadot(
+								format!("{:?}", e)
+							))),
+						}
 					}
 				}
-			}
 
-			let relay_parent = notification.hash;
-			let id = BlockId::hash(relay_parent);
-
-			let network = polkadot_network.clone();
-			let client = client.clone();
-			let key = key.clone();
-			let parachain_context = parachain_context.clone();
-
-			let work = future::lazy(move |_| {
-				let api = client.runtime_api();
-				let global_validation = try_fr!(api.global_validation_data(&id));
-				let local_validation = match try_fr!(api.local_validation_data(&id, para_id)) {
-					Some(local_validation) => local_validation,
-					None => return future::Either::Left(future::ok(())),
-				};
-				let downward_messages = try_fr!(api.downward_messages(&id, para_id));
-
-				let validators = try_fr!(api.validators(&id));
-
-				let targets = compute_targets(
-					para_id,
-					validators.as_slice(),
-					try_fr!(api.duty_roster(&id)),
-				);
+				let relay_parent = notification.hash;
+				let id = BlockId::hash(relay_parent);
+
+				let network = polkadot_network.clone();
+				let client = client.clone();
+				let key = key.clone();
+				let parachain_context = parachain_context.clone();
+
+				let work = future::lazy(move |_| {
+					let api = client.runtime_api();
+					let global_validation = try_fr!(api.global_validation_data(&id));
+					let local_validation = match try_fr!(api.local_validation_data(&id, para_id)) {
+						Some(local_validation) => local_validation,
+						None => return future::Either::Left(future::ok(())),
+					};
+					let downward_messages = try_fr!(api.downward_messages(&id, para_id));
+
+					let validators = try_fr!(api.validators(&id));
+
+					let targets = compute_targets(
+						para_id,
+						validators.as_slice(),
+						try_fr!(api.duty_roster(&id)),
+					);
+
+					let collation_work = collate(
+						relay_parent,
+						para_id,
+						global_validation,
+						local_validation,
+						downward_messages,
+						parachain_context,
+						key,
+					).map(move |collation| {
+						match collation {
+							Some(collation) => network.distribute_collation(targets, collation),
+							None => log::trace!("Skipping collation as `collate` returned `None`"),
+						}
 
-				let collation_work = collate(
-					relay_parent,
-					para_id,
-					global_validation,
-					local_validation,
-					downward_messages,
-					parachain_context,
-					key,
-				).map(move |collation| {
-					match collation {
-						Some(collation) => network.distribute_collation(targets, collation),
-						None => log::trace!("Skipping collation as `collate` returned `None`"),
-					}
+						Ok(())
+					});
 
-					Ok(())
+					future::Either::Right(collation_work)
 				});
 
-				future::Either::Right(collation_work)
-			});
-
-			let deadlined = future::select(
-				work.then(|f| f).boxed(),
-				futures_timer::Delay::new(COLLATION_TIMEOUT)
-			);
+				let deadlined = future::select(
+					work.then(|f| f).boxed(),
+					futures_timer::Delay::new(COLLATION_TIMEOUT)
+				);
 
-			let silenced = deadlined
-				.map(|either| {
-					match either {
-						future::Either::Right(_) => log::warn!("Collation failure: timeout"),
-						future::Either::Left((Err(e), _)) => {
-							log::error!("Collation failed: {:?}", e)
+				let silenced = deadlined
+					.map(|either| {
+						match either {
+							future::Either::Right(_) => log::warn!("Collation failure: timeout"),
+							future::Either::Left((Err(e), _)) => {
+								log::error!("Collation failed: {:?}", e)
+							}
+							future::Either::Left((Ok(()), _)) => {},
 						}
-						future::Either::Left((Ok(()), _)) => {},
-					}
-				});
+					});
 
-			let future = silenced.map(drop);
+				let future = silenced.map(drop);
 
-			spawner.spawn("collation-work", future);
-		}
-	}.boxed();
+				spawner.spawn("collation-work", future);
+			}
+		};
 
-	Ok(work)
+		Ok(res.boxed())
+	}
+}
+
+#[cfg(not(feature = "service-rewr"))]
+fn build_collator_service<P>(
+	spawner: SpawnTaskHandle,
+	handles: FullNodeHandles,
+	client: polkadot_service::Client,
+	para_id: ParaId,
+	key: Arc<CollatorPair>,
+	build_parachain_context: P,
+) -> Result<Pin<Box<dyn Future<Output = ()> + Send + 'static>>, polkadot_service::Error>
+	where
+		P: BuildParachainContext,
+		P::ParachainContext: Send + 'static,
+		<P::ParachainContext as ParachainContext>::ProduceCandidate: Send,
+{
+	client.execute_with(BuildCollationWork {
+		handles,
+		para_id,
+		key,
+		build_parachain_context,
+		spawner,
+		client: client.clone(),
+	})
 }
 
 /// Async function that will run the collator node with the given `RelayChainContext` and `ParachainContext`
@@ -391,64 +391,25 @@ where
 		.into());
 	}
 
-	if config.chain_spec.is_kusama() {
-		let (task_manager, client, handlers) = service::kusama_new_full(
-			config,
-			Some((key.public(), para_id)),
-			None,
-			false,
-			6000,
-			None,
-		)?;
-		let spawn_handle = task_manager.spawn_handle();
-		let future = build_collator_service(
-			spawn_handle,
-			handlers,
-			client,
-			para_id,
-			key,
-			build_parachain_context
-		)?;
-		Ok((future.boxed(), task_manager))
-	} else if config.chain_spec.is_westend() {
-		let (task_manager, client, handlers) = service::westend_new_full(
-			config,
-			Some((key.public(), para_id)),
-			None,
-			false,
-			6000,
-			None,
-		)?;
-		let spawn_handle = task_manager.spawn_handle();
-		let future = build_collator_service(
-			spawn_handle,
-			handlers,
-			client,
-			para_id,
-			key,
-			build_parachain_context
-		)?;
-		Ok((future.boxed(), task_manager))
-	} else {
-		let (task_manager, client, handles) = service::polkadot_new_full(
-			config,
-			Some((key.public(), para_id)),
-			None,
-			false,
-			6000,
-			None,
-		)?;
-		let spawn_handle = task_manager.spawn_handle();
-		let future = build_collator_service(
-			spawn_handle,
-			handles,
-			client,
-			para_id,
-			key,
-			build_parachain_context
-		)?;
-		Ok((future.boxed(), task_manager))
-	}
+	let (task_manager, client, handlers) = polkadot_service::build_full(
+		config,
+		Some((key.public(), para_id)),
+		None,
+		false,
+		6000,
+		None,
+	)?;
+
+	let future = build_collator_service(
+		task_manager.spawn_handle(),
+		handlers,
+		client,
+		para_id,
+		key,
+		build_parachain_context
+	)?;
+
+	Ok((future, task_manager))
 }
 
 #[cfg(not(feature = "service-rewr"))]
@@ -492,9 +453,9 @@ mod tests {
 	impl BuildParachainContext for BuildDummyParachainContext {
 		type ParachainContext = DummyParachainContext;
 
-		fn build<C, SP>(
+		fn build<SP>(
 			self,
-			_: Arc<C>,
+			_: polkadot_service::Client,
 			_: SP,
 			_: impl Network + Clone + 'static,
 		) -> Result<Self::ParachainContext, ()> {
diff --git a/polkadot/node/test-service/src/lib.rs b/polkadot/node/test-service/src/lib.rs
index e45b931464442ad76aa20063df944c77532cd1ad..bc210c2384f44c6c84ea29e29478f77afa5f7418 100644
--- a/polkadot/node/test-service/src/lib.rs
+++ b/polkadot/node/test-service/src/lib.rs
@@ -26,9 +26,7 @@ use polkadot_primitives::v0::{
 	Block, Hash, CollatorId, Id as ParaId,
 };
 use polkadot_runtime_common::{parachains, registrar, BlockHashCount};
-use polkadot_service::{
-	new_full, FullNodeHandles, PolkadotClient,
-};
+use polkadot_service::{new_full, FullNodeHandles, AbstractClient};
 use polkadot_test_runtime::{RestrictFunctionality, Runtime, SignedExtra, SignedPayload, VERSION};
 use sc_chain_spec::ChainSpec;
 use sc_client_api::{execution_extensions::ExecutionStrategies, BlockchainEvents};
@@ -69,7 +67,7 @@ pub fn polkadot_test_new_full(
 ) -> Result<
 	(
 		TaskManager,
-		Arc<impl PolkadotClient<Block, TFullBackend<Block>, polkadot_test_runtime::RuntimeApi>>,
+		Arc<impl AbstractClient<Block, TFullBackend<Block>>>,
 		FullNodeHandles,
 		Arc<NetworkService<Block, Hash>>,
 		Arc<RpcHandlers>,
@@ -196,7 +194,7 @@ pub fn run_test_node(
 	boot_nodes: Vec<MultiaddrWithPeerId>,
 ) -> PolkadotTestNode<
 	TaskManager,
-	impl PolkadotClient<Block, TFullBackend<Block>, polkadot_test_runtime::RuntimeApi>,
+	impl AbstractClient<Block, TFullBackend<Block>>,
 > {
 	let config = node_config(storage_update_func, task_executor, key, boot_nodes);
 	let multiaddr = config.network.listen_addresses[0].clone();
diff --git a/polkadot/parachain/test-parachains/adder/collator/src/main.rs b/polkadot/parachain/test-parachains/adder/collator/src/main.rs
index 9136cc0ca9f8f773b7999076b09f6db746e43dc4..2bddff6f8694ff96ba373344e2177176311c9a2f 100644
--- a/polkadot/parachain/test-parachains/adder/collator/src/main.rs
+++ b/polkadot/parachain/test-parachains/adder/collator/src/main.rs
@@ -89,8 +89,11 @@ impl ParachainContext for AdderContext {
 		let encoded_head = HeadData(next_head.encode());
 		let encoded_body = BlockData(next_body.encode());
 
-		println!("Created collation for #{}, post-state={}",
-			next_head.number, next_body.state.overflowing_add(next_body.add).0);
+		println!(
+			"Created collation for #{}, post-state={}",
+			next_head.number,
+			next_body.state.overflowing_add(next_body.add).0,
+		);
 
 		db.insert(next_head.clone(), next_body);
 		ready(Some((encoded_body, encoded_head)))
@@ -100,9 +103,9 @@ impl ParachainContext for AdderContext {
 impl BuildParachainContext for AdderContext {
 	type ParachainContext = Self;
 
-	fn build<Client, SP>(
+	fn build<SP>(
 		self,
-		_: Arc<Client>,
+		_: collator::Client,
 		_: SP,
 		network: impl Network + Clone + 'static,
 	) -> Result<Self::ParachainContext, ()> {
diff --git a/polkadot/runtime/rococo-v1/Cargo.toml b/polkadot/runtime/rococo-v1/Cargo.toml
index fbd7d617fa67a4b85e18cb4f323f611b92bddeab..8a9228a6acd52064ab76bad46554acbeac624a5b 100644
--- a/polkadot/runtime/rococo-v1/Cargo.toml
+++ b/polkadot/runtime/rococo-v1/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "rococo-v1-runtime"
-version = "0.8.19"
+version = "0.8.22"
 authors = ["Parity Technologies <admin@parity.io>"]
 edition = "2018"
 build = "build.rs"
diff --git a/polkadot/runtime/rococo/Cargo.toml b/polkadot/runtime/rococo/Cargo.toml
index 2c5ab8add33ae1b9adce573d106b2f2e1cb7ad2d..5eb029fbf3a20f4bb4ab5d99697f4c4a8eb8a824 100644
--- a/polkadot/runtime/rococo/Cargo.toml
+++ b/polkadot/runtime/rococo/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "rococo-runtime"
-version = "0.8.14"
+version = "0.8.22"
 authors = ["Parity Technologies <admin@parity.io>"]
 edition = "2018"
 build = "build.rs"
diff --git a/polkadot/service/src/client.rs b/polkadot/service/src/client.rs
index 28d2bccabbe5e270dce5bdd66253e343233c8b60..786d3b8fbabd37cc5f1702931f85608f7a971089 100644
--- a/polkadot/service/src/client.rs
+++ b/polkadot/service/src/client.rs
@@ -14,40 +14,137 @@
 // 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 meta trait
+//! Polkadot Client abstractions.
 
-use sp_api::{ProvideRuntimeApi, ConstructRuntimeApi, CallApiAt};
+use std::sync::Arc;
+use sp_api::{ProvideRuntimeApi, CallApiAt};
 use sp_blockchain::HeaderBackend;
-use sp_runtime::traits::Block as BlockT;
+use sp_runtime::traits::{Block as BlockT, BlakeTwo256};
 use sc_client_api::{Backend as BackendT, BlockchainEvents};
+use polkadot_primitives::v0::{Block, ParachainHost, AccountId, Nonce, Balance};
 
-/// Polkadot client abstraction, this super trait only pulls in functionality required for
-/// polkadot internal crates like polkadot-collator.
-pub trait PolkadotClient<Block, Backend, Runtime>:
+/// A set of APIs that polkadot-like runtimes must implement.
+pub trait RuntimeApiCollection:
+	sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block>
+	+ sp_api::ApiExt<Block, Error = sp_blockchain::Error>
+	+ babe_primitives::BabeApi<Block>
+	+ grandpa_primitives::GrandpaApi<Block>
+	+ ParachainHost<Block>
+	+ sp_block_builder::BlockBuilder<Block>
+	+ system_rpc_runtime_api::AccountNonceApi<Block, AccountId, Nonce>
+	+ pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<Block, Balance>
+	+ sp_api::Metadata<Block>
+	+ sp_offchain::OffchainWorkerApi<Block>
+	+ sp_session::SessionKeys<Block>
+	+ authority_discovery_primitives::AuthorityDiscoveryApi<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, Error = sp_blockchain::Error>
+	+ babe_primitives::BabeApi<Block>
+	+ grandpa_primitives::GrandpaApi<Block>
+	+ ParachainHost<Block>
+	+ sp_block_builder::BlockBuilder<Block>
+	+ system_rpc_runtime_api::AccountNonceApi<Block, AccountId, Nonce>
+	+ pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<Block, Balance>
+	+ sp_api::Metadata<Block>
+	+ sp_offchain::OffchainWorkerApi<Block>
+	+ sp_session::SessionKeys<Block>
+	+ authority_discovery_primitives::AuthorityDiscoveryApi<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, Api = Runtime::RuntimeApi>
+	+ ProvideRuntimeApi<Block>
 	+ HeaderBackend<Block>
 	+ CallApiAt<
 		Block,
 		Error = sp_blockchain::Error,
-		StateBackend = Backend ::State
+		StateBackend = Backend::State
 	>
 	where
 		Block: BlockT,
 		Backend: BackendT<Block>,
-		Runtime: ConstructRuntimeApi<Block, Self>
+		Backend::State: sp_api::StateBackend<BlakeTwo256>,
+		Self::Api: RuntimeApiCollection<StateBackend = Backend::State>,
 {}
 
-impl<Block, Backend, Runtime, Client> PolkadotClient<Block, Backend, Runtime> for Client
+impl<Block, Backend, Client> AbstractClient<Block, Backend> for Client
 	where
 		Block: BlockT,
-		Runtime: ConstructRuntimeApi<Block, Self>,
 		Backend: BackendT<Block>,
-		Client: BlockchainEvents<Block> + ProvideRuntimeApi<Block, Api = Runtime::RuntimeApi> + HeaderBackend<Block>
+		Backend::State: sp_api::StateBackend<BlakeTwo256>,
+		Client: BlockchainEvents<Block> + ProvideRuntimeApi<Block> + HeaderBackend<Block>
 			+ Sized + Send + Sync
 			+ CallApiAt<
 				Block,
 				Error = sp_blockchain::Error,
-				StateBackend = Backend ::State
-			>
+				StateBackend = Backend::State
+			>,
+		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>,
+			Backend::State: sp_api::StateBackend<BlakeTwo256>,
+			Api: crate::RuntimeApiCollection<StateBackend = Backend::State>,
+			Client: AbstractClient<Block, Backend, Api = Api> + 'static;
+}
+
+/// A client instance of Polkadot.
+///
+/// See [`ExecuteWithClient`] for more information.
+#[derive(Clone)]
+pub enum Client {
+	Polkadot(Arc<crate::FullClient<polkadot_runtime::RuntimeApi, crate::PolkadotExecutor>>),
+	Westend(Arc<crate::FullClient<westend_runtime::RuntimeApi, crate::WestendExecutor>>),
+	Kusama(Arc<crate::FullClient<kusama_runtime::RuntimeApi, crate::KusamaExecutor>>),
+	Rococo(Arc<crate::FullClient<rococo_runtime::RuntimeApi, crate::RococoExecutor>>),
+}
+
+impl Client {
+	/// Execute the given something with the client.
+	pub fn execute_with<T: ExecuteWithClient>(&self, t: T) -> T::Output {
+		match self {
+			Self::Polkadot(client) => {
+				T::execute_with_client::<_, _, crate::FullBackend>(t, client.clone())
+			},
+			Self::Westend(client) => {
+				T::execute_with_client::<_, _, crate::FullBackend>(t, client.clone())
+			},
+			Self::Kusama(client) => {
+				T::execute_with_client::<_, _, crate::FullBackend>(t, client.clone())
+			},
+			Self::Rococo(client) => {
+				T::execute_with_client::<_, _, crate::FullBackend>(t, client.clone())
+			}
+		}
+	}
+}
diff --git a/polkadot/service/src/lib.rs b/polkadot/service/src/lib.rs
index 30fb4c0cffae3167c2c49df28e9d9e82888976c5..1897e026ddab91bbfc1add08e88a42faab23454f 100644
--- a/polkadot/service/src/lib.rs
+++ b/polkadot/service/src/lib.rs
@@ -22,7 +22,7 @@ mod client;
 
 use std::sync::Arc;
 use std::time::Duration;
-use polkadot_primitives::v0::{self as parachain, Hash, BlockId, AccountId, Nonce, Balance};
+use polkadot_primitives::v0::{self as parachain, Hash, BlockId};
 #[cfg(feature = "full-node")]
 use polkadot_network::{legacy::gossip::Known, protocol as network_protocol};
 use service::{error::Error as ServiceError};
@@ -52,7 +52,7 @@ pub use polkadot_runtime;
 pub use kusama_runtime;
 pub use westend_runtime;
 use prometheus_endpoint::Registry;
-pub use self::client::PolkadotClient;
+pub use self::client::*;
 
 native_executor_instance!(
 	pub PolkadotExecutor,
@@ -82,42 +82,6 @@ native_executor_instance!(
 	frame_benchmarking::benchmarking::HostFunctions,
 );
 
-/// A set of APIs that polkadot-like runtimes must implement.
-pub trait RuntimeApiCollection:
-	sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block>
-	+ sp_api::ApiExt<Block, Error = sp_blockchain::Error>
-	+ babe_primitives::BabeApi<Block>
-	+ grandpa_primitives::GrandpaApi<Block>
-	+ ParachainHost<Block>
-	+ sp_block_builder::BlockBuilder<Block>
-	+ system_rpc_runtime_api::AccountNonceApi<Block, AccountId, Nonce>
-	+ pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<Block, Balance>
-	+ sp_api::Metadata<Block>
-	+ sp_offchain::OffchainWorkerApi<Block>
-	+ sp_session::SessionKeys<Block>
-	+ authority_discovery_primitives::AuthorityDiscoveryApi<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, Error = sp_blockchain::Error>
-	+ babe_primitives::BabeApi<Block>
-	+ grandpa_primitives::GrandpaApi<Block>
-	+ ParachainHost<Block>
-	+ sp_block_builder::BlockBuilder<Block>
-	+ system_rpc_runtime_api::AccountNonceApi<Block, AccountId, Nonce>
-	+ pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<Block, Balance>
-	+ sp_api::Metadata<Block>
-	+ sp_offchain::OffchainWorkerApi<Block>
-	+ sp_session::SessionKeys<Block>
-	+ authority_discovery_primitives::AuthorityDiscoveryApi<Block>,
-	<Self as sp_api::ApiExt<Block>>::StateBackend: sp_api::StateBackend<BlakeTwo256>,
-{}
-
 /// Can be called for a `Configuration` to check if it is a configuration for the `Kusama` network.
 pub trait IdentifyVariant {
 	/// Returns if this is a configuration for the `Kusama` network.
@@ -732,11 +696,7 @@ pub fn polkadot_new_full(
 )
 	-> Result<(
 		TaskManager,
-		Arc<impl PolkadotClient<
-			Block,
-			FullBackend,
-			polkadot_runtime::RuntimeApi
-		>>,
+		Arc<impl AbstractClient<Block, FullBackend>>,
 		FullNodeHandles,
 	), ServiceError>
 {
@@ -764,12 +724,7 @@ pub fn kusama_new_full(
 	grandpa_pause: Option<(u32, u32)>,
 ) -> Result<(
 		TaskManager,
-		Arc<impl PolkadotClient<
-			Block,
-			FullBackend,
-			kusama_runtime::RuntimeApi
-			>
-		>,
+		Arc<impl AbstractClient<Block, FullBackend>>,
 		FullNodeHandles
 	), ServiceError>
 {
@@ -798,11 +753,7 @@ pub fn westend_new_full(
 )
 	-> Result<(
 		TaskManager,
-		Arc<impl PolkadotClient<
-			Block,
-			FullBackend,
-			westend_runtime::RuntimeApi
-		>>,
+		Arc<impl AbstractClient<Block, FullBackend>>,
 		FullNodeHandles,
 	), ServiceError>
 {
@@ -831,11 +782,7 @@ pub fn rococo_new_full(
 )
 	-> Result<(
 		TaskManager,
-		Arc<impl PolkadotClient<
-			Block,
-			TFullBackend<Block>,
-			rococo_runtime::RuntimeApi
-		>>,
+		Arc<impl AbstractClient<Block, TFullBackend<Block>>>,
 		FullNodeHandles,
 	), ServiceError>
 {
@@ -863,90 +810,68 @@ pub struct FullNodeHandles {
 	pub validation_service_handle: Option<consensus::ServiceHandle>,
 }
 
-/// A builder for a node.
-pub struct NodeBuilder {
-	config: Configuration,
+/// Build a new light node.
+pub fn build_light(config: Configuration) -> Result<(TaskManager, Arc<RpcHandlers>), ServiceError> {
+	if config.chain_spec.is_kusama() {
+		new_light::<kusama_runtime::RuntimeApi, KusamaExecutor>(config)
+	} else if config.chain_spec.is_westend() {
+		new_light::<westend_runtime::RuntimeApi, WestendExecutor>(config)
+	} else if config.chain_spec.is_rococo() {
+		new_light::<rococo_runtime::RuntimeApi, RococoExecutor>(config)
+	} else {
+		new_light::<polkadot_runtime::RuntimeApi, PolkadotExecutor>(config)
+	}
 }
 
-impl NodeBuilder {
-	/// Create a new node builder.
-	pub fn new(config: Configuration) -> Self {
-		Self {
+/// Build a new full node.
+#[cfg(feature = "full-node")]
+pub fn build_full(
+	config: Configuration,
+	collating_for: Option<(CollatorId, parachain::Id)>,
+	max_block_data_size: Option<u64>,
+	authority_discovery_disabled: bool,
+	slot_duration: u64,
+	grandpa_pause: Option<(u32, u32)>,
+) -> Result<(TaskManager, Client, FullNodeHandles), ServiceError> {
+	if config.chain_spec.is_kusama() {
+		new_full::<kusama_runtime::RuntimeApi, KusamaExecutor>(
 			config,
-		}
-	}
-
-	/// Build a new light node.
-	pub fn build_light(self) -> Result<(TaskManager, Arc<RpcHandlers>), ServiceError> {
-		if self.config.chain_spec.is_kusama() {
-			new_light::<kusama_runtime::RuntimeApi, KusamaExecutor>(
-				self.config,
-			)
-		} else if self.config.chain_spec.is_westend() {
-			new_light::<westend_runtime::RuntimeApi, WestendExecutor>(
-				self.config,
-			)
-		} else if self.config.chain_spec.is_rococo() {
-			new_light::<rococo_runtime::RuntimeApi, RococoExecutor>(
-				self.config,
-			)
-		} else {
-			new_light::<polkadot_runtime::RuntimeApi, PolkadotExecutor>(
-				self.config,
-			)
-		}
-	}
-
-	/// Build a new full node.
-	#[cfg(feature = "full-node")]
-	pub fn build_full(
-		self,
-		collating_for: Option<(CollatorId, parachain::Id)>,
-		max_block_data_size: Option<u64>,
-		authority_discovery_disabled: bool,
-		slot_duration: u64,
-		grandpa_pause: Option<(u32, u32)>,
-	) -> Result<TaskManager, ServiceError> {
-		if self.config.chain_spec.is_kusama() {
-			new_full::<kusama_runtime::RuntimeApi, KusamaExecutor>(
-				self.config,
-				collating_for,
-				max_block_data_size,
-				authority_discovery_disabled,
-				slot_duration,
-				grandpa_pause,
-				false,
-			).map(|(task_manager, _, _, _, _)| task_manager)
-		} else if self.config.chain_spec.is_westend() {
-			new_full::<westend_runtime::RuntimeApi, WestendExecutor>(
-				self.config,
-				collating_for,
-				max_block_data_size,
-				authority_discovery_disabled,
-				slot_duration,
-				grandpa_pause,
-				false,
-			).map(|(task_manager, _, _, _, _)| task_manager)
-		} else if self.config.chain_spec.is_rococo() {
-			new_full::<rococo_runtime::RuntimeApi, RococoExecutor>(
-				self.config,
-				collating_for,
-				max_block_data_size,
-				authority_discovery_disabled,
-				slot_duration,
-				grandpa_pause,
-				false,
-			).map(|(task_manager, _, _, _, _)| task_manager)
-		} else {
-			new_full::<polkadot_runtime::RuntimeApi, PolkadotExecutor>(
-				self.config,
-				collating_for,
-				max_block_data_size,
-				authority_discovery_disabled,
-				slot_duration,
-				grandpa_pause,
-				false,
-			).map(|(task_manager, _, _, _, _)| task_manager)
-		}
+			collating_for,
+			max_block_data_size,
+			authority_discovery_disabled,
+			slot_duration,
+			grandpa_pause,
+			false,
+		).map(|(task_manager, client, handles, _, _)| (task_manager, Client::Kusama(client), handles))
+	} else if config.chain_spec.is_westend() {
+		new_full::<westend_runtime::RuntimeApi, WestendExecutor>(
+			config,
+			collating_for,
+			max_block_data_size,
+			authority_discovery_disabled,
+			slot_duration,
+			grandpa_pause,
+			false,
+		).map(|(task_manager, client, handles, _, _)| (task_manager, Client::Westend(client), handles))
+	} else if config.chain_spec.is_rococo() {
+		new_full::<rococo_runtime::RuntimeApi, RococoExecutor>(
+			config,
+			collating_for,
+			max_block_data_size,
+			authority_discovery_disabled,
+			slot_duration,
+			grandpa_pause,
+			false,
+		).map(|(task_manager, client, handles, _, _)| (task_manager, Client::Rococo(client), handles))
+	} else {
+		new_full::<polkadot_runtime::RuntimeApi, PolkadotExecutor>(
+			config,
+			collating_for,
+			max_block_data_size,
+			authority_discovery_disabled,
+			slot_duration,
+			grandpa_pause,
+			false,
+		).map(|(task_manager, client, handles, _, _)| (task_manager, Client::Polkadot(client), handles))
 	}
 }