git.delta.rocks / unique-network / refs/commits / 5189324f5050

difftreelog

Adjust node and rpc to work with different runtimes

Daniel Shiposha2022-03-14parent: #ea9e87e.patch.diff
in: master

7 files changed

modifiedCargo.lockdiffbeforeafterboth
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -11942,6 +11942,7 @@
  "opal-runtime",
  "pallet-ethereum",
  "pallet-transaction-payment-rpc",
+ "pallet-transaction-payment-rpc-runtime-api",
  "parity-scale-codec",
  "parking_lot 0.11.2",
  "polkadot-cli",
@@ -11988,7 +11989,9 @@
  "substrate-prometheus-endpoint",
  "unique-rpc",
  "unique-runtime",
+ "unique-runtime-common",
  "up-data-structs",
+ "up-rpc",
 ]
 
 [[package]]
@@ -12003,12 +12006,11 @@
  "futures 0.3.21",
  "jsonrpc-core",
  "jsonrpc-pubsub",
- "opal-runtime",
+ "pallet-common",
  "pallet-ethereum",
  "pallet-transaction-payment-rpc",
  "pallet-transaction-payment-rpc-runtime-api",
  "pallet-unique",
- "quartz-runtime",
  "sc-client-api",
  "sc-consensus-aura",
  "sc-consensus-epochs",
@@ -12020,6 +12022,7 @@
  "sc-rpc-api",
  "sc-service",
  "sc-transaction-pool",
+ "serde",
  "sp-api",
  "sp-block-builder",
  "sp-blockchain",
@@ -12034,7 +12037,7 @@
  "substrate-frame-rpc-system",
  "tokio 0.2.25",
  "uc-rpc",
- "unique-runtime",
+ "unique-runtime-common",
  "up-rpc",
 ]
 
@@ -12118,10 +12121,13 @@
 name = "unique-runtime-common"
 version = "0.1.0"
 dependencies = [
+ "fp-rpc",
  "frame-support",
  "frame-system",
+ "pallet-common",
  "parity-scale-codec",
  "scale-info",
+ "sp-consensus-aura",
  "sp-core",
  "sp-runtime",
 ]
modifiednode/cli/Cargo.tomldiffbeforeafterboth
--- a/node/cli/Cargo.toml
+++ b/node/cli/Cargo.toml
@@ -238,6 +238,10 @@
 ################################################################################
 # Local dependencies
 
+[dependencies.unique-runtime-common]
+default-features = false
+path = "../../runtime/common"
+
 [dependencies.unique-runtime]
 path = '../../runtime/unique'
 optional = true
@@ -254,6 +258,13 @@
 path = "../../primitives/data-structs"
 default-features = false
 
+[dependencies.up-rpc]
+path = "../../primitives/rpc"
+
+[dependencies.pallet-transaction-payment-rpc-runtime-api]
+git = 'https://github.com/paritytech/substrate.git'
+branch = 'polkadot-v0.9.17'
+
 ################################################################################
 # Package
 
@@ -295,7 +306,7 @@
 unique-rpc = { default-features = false, path = "../rpc" }
 
 [features]
-default = ["unique-runtime"]
+default = ["unique-runtime", "quartz-runtime", "opal-runtime"]
 runtime-benchmarks = [
     'unique-runtime/runtime-benchmarks',
     'polkadot-service/runtime-benchmarks',
modifiednode/cli/src/chain_spec.rsdiffbeforeafterboth
--- a/node/cli/src/chain_spec.rs
+++ b/node/cli/src/chain_spec.rs
@@ -24,20 +24,33 @@
 use serde::{Deserialize, Serialize};
 use serde_json::map::Map;
 
-#[cfg(feature = "unique-runtime")]
-use unique_runtime as runtime;
+use unique_runtime_common::types::*;
 
-#[cfg(feature = "quartz-runtime")]
-use quartz_runtime as runtime;
+/// Specialized `ChainSpec`. This is a specialization of the general Substrate ChainSpec type.
+pub type ChainSpec = sc_service::GenericChainSpec<unique_runtime::GenesisConfig, Extensions>;
 
-#[cfg(feature = "opal-runtime")]
-use opal_runtime as runtime;
+pub trait RuntimeIdentification {
+	fn is_unique(&self) -> bool;
+
+	fn is_quartz(&self) -> bool;
 
-use runtime::{*, opaque::*};
+	fn is_opal(&self) -> bool;
+}
 
-/// Specialized `ChainSpec`. This is a specialization of the general Substrate ChainSpec type.
-pub type ChainSpec = sc_service::GenericChainSpec<runtime::GenesisConfig, Extensions>;
+impl RuntimeIdentification for Box<dyn sc_service::ChainSpec> {
+	fn is_unique(&self) -> bool {
+		self.id().starts_with("unique")
+	}
 
+	fn is_quartz(&self) -> bool {
+		self.id().starts_with("quartz")
+	}
+
+	fn is_opal(&self) -> bool {
+		self.id().starts_with("opal")
+	}
+}
+
 /// Helper function to generate a crypto pair from seed
 pub fn get_from_seed<TPublic: Public>(seed: &str) -> <TPublic::Pair as Pair>::Public {
 	TPublic::Pair::from_string(&format!("//{}", seed), None)
@@ -225,10 +238,12 @@
 	initial_authorities: Vec<AuraId>,
 	endowed_accounts: Vec<AccountId>,
 	id: ParaId,
-) -> GenesisConfig {
+) -> unique_runtime::GenesisConfig {
+	use unique_runtime::*;
+
 	GenesisConfig {
-		system: runtime::SystemConfig {
-			code: runtime::WASM_BINARY
+		system: SystemConfig {
+			code: WASM_BINARY
 				.expect("WASM binary was not build, please build it!")
 				.to_vec(),
 		},
@@ -245,9 +260,9 @@
 			key: Some(root_key),
 		},
 		vesting: VestingConfig { vesting: vec![] },
-		parachain_info: runtime::ParachainInfoConfig { parachain_id: id },
+		parachain_info: ParachainInfoConfig { parachain_id: id },
 		parachain_system: Default::default(),
-		aura: runtime::AuraConfig {
+		aura: AuraConfig {
 			authorities: initial_authorities,
 		},
 		aura_ext: Default::default(),
modifiednode/cli/src/command.rsdiffbeforeafterboth
before · node/cli/src/command.rs
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617// Original license18// This file is part of Substrate.1920// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd.21// SPDX-License-Identifier: Apache-2.02223// Licensed under the Apache License, Version 2.0 (the "License");24// you may not use this file except in compliance with the License.25// You may obtain a copy of the License at26//27// 	http://www.apache.org/licenses/LICENSE-2.028//29// Unless required by applicable law or agreed to in writing, software30// distributed under the License is distributed on an "AS IS" BASIS,31// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.32// See the License for the specific language governing permissions and33// limitations under the License.3435use crate::{36	chain_spec,37	cli::{Cli, RelayChainCli, Subcommand},38	service::{new_partial, ParachainRuntimeExecutor},39};40use codec::Encode;41use cumulus_primitives_core::ParaId;42use cumulus_client_service::genesis::generate_genesis_block;43use log::info;44use polkadot_parachain::primitives::AccountIdConversion;45use sc_cli::{46	ChainSpec, CliConfiguration, DefaultConfigurationValues, ImportParams, KeystoreParams,47	NetworkParams, Result, RuntimeVersion, SharedParams, SubstrateCli,48};49use sc_service::{50	config::{BasePath, PrometheusConfig},51};52use sp_core::hexdisplay::HexDisplay;53use sp_runtime::traits::Block as BlockT;54use std::{io::Write, net::SocketAddr};5556#[cfg(feature = "unique-runtime")]57use unique_runtime as runtime;5859#[cfg(feature = "quartz-runtime")]60use quartz_runtime as runtime;6162#[cfg(feature = "opal-runtime")]63use opal_runtime as runtime;6465use runtime::Block;6667fn load_spec(id: &str) -> std::result::Result<Box<dyn sc_service::ChainSpec>, String> {68	Ok(match id {69		"westend-local" => Box::new(chain_spec::local_testnet_westend_config()),70		"rococo-local" => Box::new(chain_spec::local_testnet_rococo_config()),71		"dev" => Box::new(chain_spec::development_config()),72		"" | "local" => Box::new(chain_spec::local_testnet_rococo_config()),73		path => Box::new(chain_spec::ChainSpec::from_json_file(74			std::path::PathBuf::from(path),75		)?),76	})77}7879impl SubstrateCli for Cli {80	// TODO use args81	fn impl_name() -> String {82		format!("{} Node", runtime::RUNTIME_NAME)83	}8485	fn impl_version() -> String {86		env!("SUBSTRATE_CLI_IMPL_VERSION").into()87	}88	// TODO use args89	fn description() -> String {90		format!(91			"{} Node\n\nThe command-line arguments provided first will be \92		passed to the parachain node, while the arguments provided after -- will be passed \93		to the relaychain node.\n\n\94		{} [parachain-args] -- [relaychain-args]",95			runtime::RUNTIME_NAME,96			Self::executable_name()97		)98	}99100	fn author() -> String {101		env!("CARGO_PKG_AUTHORS").into()102	}103104	//TODO use args105	fn support_url() -> String {106		"support@unique.network".into()107	}108109	fn copyright_start_year() -> i32 {110		2019111	}112113	fn load_spec(&self, id: &str) -> std::result::Result<Box<dyn sc_service::ChainSpec>, String> {114		load_spec(id)115	}116117	fn native_runtime_version(_: &Box<dyn ChainSpec>) -> &'static RuntimeVersion {118		&runtime::VERSION119	}120}121122impl SubstrateCli for RelayChainCli {123	// TODO use args124	fn impl_name() -> String {125		format!("{} Node", runtime::RUNTIME_NAME)126	}127128	fn impl_version() -> String {129		env!("SUBSTRATE_CLI_IMPL_VERSION").into()130	}131	// TODO use args132	fn description() -> String {133		format!(134			"{} Node\n\nThe command-line arguments provided first will be \135		passed to the parachain node, while the arguments provided after -- will be passed \136		to the relaychain node.\n\n\137		parachain-collator [parachain-args] -- [relaychain-args]",138			runtime::RUNTIME_NAME139		)140	}141142	fn author() -> String {143		env!("CARGO_PKG_AUTHORS").into()144	}145	// TODO use args146	fn support_url() -> String {147		"support@unique.network".into()148	}149150	fn copyright_start_year() -> i32 {151		2019152	}153154	fn load_spec(&self, id: &str) -> std::result::Result<Box<dyn sc_service::ChainSpec>, String> {155		polkadot_cli::Cli::from_iter([RelayChainCli::executable_name()].iter()).load_spec(id)156	}157158	fn native_runtime_version(chain_spec: &Box<dyn ChainSpec>) -> &'static RuntimeVersion {159		polkadot_cli::Cli::native_runtime_version(chain_spec)160	}161}162163#[allow(clippy::borrowed_box)]164fn extract_genesis_wasm(chain_spec: &Box<dyn sc_service::ChainSpec>) -> Result<Vec<u8>> {165	let mut storage = chain_spec.build_storage()?;166167	storage168		.top169		.remove(sp_core::storage::well_known_keys::CODE)170		.ok_or_else(|| "Could not find wasm file in genesis state!".into())171}172173macro_rules! construct_async_run {174	(|$components:ident, $cli:ident, $cmd:ident, $config:ident| $( $code:tt )* ) => {{175		let runner = $cli.create_runner($cmd)?;176		runner.async_run(|$config| {177			let $components = new_partial::<178				_179			>(180				&$config,181				crate::service::parachain_build_import_queue,182			)?;183			let task_manager = $components.task_manager;184			{ $( $code )* }.map(|v| (v, task_manager))185		})186	}}187}188189/// Parse command line arguments into service configuration.190pub fn run() -> Result<()> {191	let cli = Cli::from_args();192193	match &cli.subcommand {194		Some(Subcommand::BuildSpec(cmd)) => {195			let runner = cli.create_runner(cmd)?;196			runner.sync_run(|config| cmd.run(config.chain_spec, config.network))197		}198		Some(Subcommand::CheckBlock(cmd)) => {199			construct_async_run!(|components, cli, cmd, config| {200				Ok(cmd.run(components.client, components.import_queue))201			})202		}203		Some(Subcommand::ExportBlocks(cmd)) => {204			construct_async_run!(|components, cli, cmd, config| {205				Ok(cmd.run(components.client, config.database))206			})207		}208		Some(Subcommand::ExportState(cmd)) => {209			construct_async_run!(|components, cli, cmd, config| {210				Ok(cmd.run(components.client, config.chain_spec))211			})212		}213		Some(Subcommand::ImportBlocks(cmd)) => {214			construct_async_run!(|components, cli, cmd, config| {215				Ok(cmd.run(components.client, components.import_queue))216			})217		}218		Some(Subcommand::PurgeChain(cmd)) => {219			let runner = cli.create_runner(cmd)?;220221			runner.sync_run(|config| {222				let polkadot_cli = RelayChainCli::new(223					&config,224					[RelayChainCli::executable_name()]225						.iter()226						.chain(cli.relaychain_args.iter()),227				);228229				let polkadot_config = SubstrateCli::create_configuration(230					&polkadot_cli,231					&polkadot_cli,232					config.tokio_handle.clone(),233				)234				.map_err(|err| format!("Relay chain argument error: {}", err))?;235236				cmd.run(config, polkadot_config)237			})238		}239		Some(Subcommand::Revert(cmd)) => construct_async_run!(|components, cli, cmd, config| {240			Ok(cmd.run(components.client, components.backend))241		}),242		Some(Subcommand::ExportGenesisState(params)) => {243			let mut builder = sc_cli::LoggerBuilder::new("");244			builder.with_profiling(sc_tracing::TracingReceiver::Log, "");245			let _ = builder.init();246247			let spec = load_spec(&params.chain.clone().unwrap_or_default())?;248			let state_version = Cli::native_runtime_version(&spec).state_version();249			let block: Block = generate_genesis_block(&spec, state_version)?;250			let raw_header = block.header().encode();251			let output_buf = if params.raw {252				raw_header253			} else {254				format!("0x{:?}", HexDisplay::from(&block.header().encode())).into_bytes()255			};256257			if let Some(output) = &params.output {258				std::fs::write(output, output_buf)?;259			} else {260				std::io::stdout().write_all(&output_buf)?;261			}262263			Ok(())264		}265		Some(Subcommand::ExportGenesisWasm(params)) => {266			let mut builder = sc_cli::LoggerBuilder::new("");267			builder.with_profiling(sc_tracing::TracingReceiver::Log, "");268			let _ = builder.init();269270			let raw_wasm_blob =271				extract_genesis_wasm(&cli.load_spec(&params.chain.clone().unwrap_or_default())?)?;272			let output_buf = if params.raw {273				raw_wasm_blob274			} else {275				format!("0x{:?}", HexDisplay::from(&raw_wasm_blob)).into_bytes()276			};277278			if let Some(output) = &params.output {279				std::fs::write(output, output_buf)?;280			} else {281				std::io::stdout().write_all(&output_buf)?;282			}283284			Ok(())285		}286		Some(Subcommand::Benchmark(cmd)) => {287			if cfg!(feature = "runtime-benchmarks") {288				let runner = cli.create_runner(cmd)?;289290				runner.sync_run(|config| cmd.run::<Block, ParachainRuntimeExecutor>(config))291			} else {292				Err("Benchmarking wasn't enabled when building the node. \293				You can enable it with `--features runtime-benchmarks`."294					.into())295			}296		}297		None => {298			let runner = cli.create_runner(&cli.run.normalize())?;299300			runner.run_node_until_exit(|config| async move {301				let para_id = chain_spec::Extensions::try_get(&*config.chain_spec)302					.map(|e| e.para_id)303					.ok_or("Could not find parachain ID in chain-spec.")?;304305				let polkadot_cli = RelayChainCli::new(306					&config,307					[RelayChainCli::executable_name()]308						.iter()309						.chain(cli.relaychain_args.iter()),310				);311312				let id = ParaId::from(para_id);313314				let parachain_account =315					AccountIdConversion::<polkadot_primitives::v0::AccountId>::into_account(&id);316317				let state_version =318					RelayChainCli::native_runtime_version(&config.chain_spec).state_version();319				let block: Block = generate_genesis_block(&config.chain_spec, state_version)320					.map_err(|e| format!("{:?}", e))?;321				let genesis_state = format!("0x{:?}", HexDisplay::from(&block.header().encode()));322				let genesis_hash = format!("0x{:?}", HexDisplay::from(&block.header().hash().0));323324				let polkadot_config = SubstrateCli::create_configuration(325					&polkadot_cli,326					&polkadot_cli,327					config.tokio_handle.clone(),328				)329				.map_err(|err| format!("Relay chain argument error: {}", err))?;330331				info!("Parachain id: {:?}", id);332				info!("Parachain Account: {}", parachain_account);333				info!("Parachain genesis state: {}", genesis_state);334				info!("Parachain genesis hash: {}", genesis_hash);335				info!(336					"Is collating: {}",337					if config.role.is_authority() {338						"yes"339					} else {340						"no"341					}342				);343344				crate::service::start_node(config, polkadot_config, id)345					.await346					.map(|r| r.0)347					.map_err(Into::into)348			})349		}350	}351}352353impl DefaultConfigurationValues for RelayChainCli {354	fn p2p_listen_port() -> u16 {355		30334356	}357358	fn rpc_ws_listen_port() -> u16 {359		9945360	}361362	fn rpc_http_listen_port() -> u16 {363		9934364	}365366	fn prometheus_listen_port() -> u16 {367		9616368	}369}370371impl CliConfiguration<Self> for RelayChainCli {372	fn shared_params(&self) -> &SharedParams {373		self.base.base.shared_params()374	}375376	fn import_params(&self) -> Option<&ImportParams> {377		self.base.base.import_params()378	}379380	fn network_params(&self) -> Option<&NetworkParams> {381		self.base.base.network_params()382	}383384	fn keystore_params(&self) -> Option<&KeystoreParams> {385		self.base.base.keystore_params()386	}387388	fn base_path(&self) -> Result<Option<BasePath>> {389		Ok(self390			.shared_params()391			.base_path()392			.or_else(|| self.base_path.clone().map(Into::into)))393	}394395	fn rpc_http(&self, default_listen_port: u16) -> Result<Option<SocketAddr>> {396		self.base.base.rpc_http(default_listen_port)397	}398399	fn rpc_ipc(&self) -> Result<Option<String>> {400		self.base.base.rpc_ipc()401	}402403	fn rpc_ws(&self, default_listen_port: u16) -> Result<Option<SocketAddr>> {404		self.base.base.rpc_ws(default_listen_port)405	}406407	fn prometheus_config(408		&self,409		default_listen_port: u16,410		chain_spec: &Box<dyn ChainSpec>,411	) -> Result<Option<PrometheusConfig>> {412		self.base413			.base414			.prometheus_config(default_listen_port, chain_spec)415	}416417	fn init<F>(418		&self,419		_support_url: &String,420		_impl_version: &String,421		_logger_hook: F,422		_config: &sc_service::Configuration,423	) -> Result<()> {424		unreachable!("PolkadotCli is never initialized; qed");425	}426427	fn chain_id(&self, is_dev: bool) -> Result<String> {428		let chain_id = self.base.base.chain_id(is_dev)?;429430		Ok(if chain_id.is_empty() {431			self.chain_id.clone().unwrap_or_default()432		} else {433			chain_id434		})435	}436437	fn role(&self, is_dev: bool) -> Result<sc_service::Role> {438		self.base.base.role(is_dev)439	}440441	fn transaction_pool(&self) -> Result<sc_service::config::TransactionPoolOptions> {442		self.base.base.transaction_pool()443	}444445	fn state_cache_child_ratio(&self) -> Result<Option<usize>> {446		self.base.base.state_cache_child_ratio()447	}448449	fn rpc_methods(&self) -> Result<sc_service::config::RpcMethods> {450		self.base.base.rpc_methods()451	}452453	fn rpc_ws_max_connections(&self) -> Result<Option<usize>> {454		self.base.base.rpc_ws_max_connections()455	}456457	fn rpc_cors(&self, is_dev: bool) -> Result<Option<Vec<String>>> {458		self.base.base.rpc_cors(is_dev)459	}460461	fn default_heap_pages(&self) -> Result<Option<u64>> {462		self.base.base.default_heap_pages()463	}464465	fn force_authoring(&self) -> Result<bool> {466		self.base.base.force_authoring()467	}468469	fn disable_grandpa(&self) -> Result<bool> {470		self.base.base.disable_grandpa()471	}472473	fn max_runtime_instances(&self) -> Result<Option<usize>> {474		self.base.base.max_runtime_instances()475	}476477	fn announce_block(&self) -> Result<bool> {478		self.base.base.announce_block()479	}480481	fn telemetry_endpoints(482		&self,483		chain_spec: &Box<dyn ChainSpec>,484	) -> Result<Option<sc_telemetry::TelemetryEndpoints>> {485		self.base.base.telemetry_endpoints(chain_spec)486	}487}
after · node/cli/src/command.rs
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617// Original license18// This file is part of Substrate.1920// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd.21// SPDX-License-Identifier: Apache-2.02223// Licensed under the Apache License, Version 2.0 (the "License");24// you may not use this file except in compliance with the License.25// You may obtain a copy of the License at26//27// 	http://www.apache.org/licenses/LICENSE-2.028//29// Unless required by applicable law or agreed to in writing, software30// distributed under the License is distributed on an "AS IS" BASIS,31// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.32// See the License for the specific language governing permissions and33// limitations under the License.3435use crate::{36	chain_spec::{self, RuntimeIdentification},37	cli::{Cli, RelayChainCli, Subcommand},38	service::new_partial,39};4041#[cfg(feature = "unique-runtime")]42use crate::service::UniqueRuntimeExecutor;4344#[cfg(feature = "quartz-runtime")]45use crate::service::QuartzRuntimeExecutor;4647#[cfg(feature = "opal-runtime")]48use crate::service::OpalRuntimeExecutor;4950use codec::Encode;51use cumulus_primitives_core::ParaId;52use cumulus_client_service::genesis::generate_genesis_block;53use log::info;54use polkadot_parachain::primitives::AccountIdConversion;55use sc_cli::{56	ChainSpec, CliConfiguration, DefaultConfigurationValues, ImportParams, KeystoreParams,57	NetworkParams, Result, RuntimeVersion, SharedParams, SubstrateCli,58};59use sc_service::{60	config::{BasePath, PrometheusConfig},61};62use sp_core::hexdisplay::HexDisplay;63use sp_runtime::traits::Block as BlockT;64use std::{io::Write, net::SocketAddr};6566use unique_runtime_common::types::Block;6768macro_rules! no_runtime_err {69	($chain_spec:expr) => {70		format!("No runtime valid runtime was found, chain id: {}",71			$chain_spec.id())72	};73}7475fn load_spec(id: &str) -> std::result::Result<Box<dyn sc_service::ChainSpec>, String> {76	Ok(match id {77		"westend-local" => Box::new(chain_spec::local_testnet_westend_config()),78		"rococo-local" => Box::new(chain_spec::local_testnet_rococo_config()),79		"dev" => Box::new(chain_spec::development_config()),80		"" | "local" => Box::new(chain_spec::local_testnet_rococo_config()),81		path => Box::new(chain_spec::ChainSpec::from_json_file(82			std::path::PathBuf::from(path),83		)?),84	})85}8687impl SubstrateCli for Cli {88	// TODO use args89	fn impl_name() -> String {90		"Unique Node".into()91	}9293	fn impl_version() -> String {94		env!("SUBSTRATE_CLI_IMPL_VERSION").into()95	}96	// TODO use args97	fn description() -> String {98		format!(99			"Unique Node\n\nThe command-line arguments provided first will be \100		passed to the parachain node, while the arguments provided after -- will be passed \101		to the relaychain node.\n\n\102		{} [parachain-args] -- [relaychain-args]",103			Self::executable_name()104		)105	}106107	fn author() -> String {108		env!("CARGO_PKG_AUTHORS").into()109	}110111	//TODO use args112	fn support_url() -> String {113		"support@unique.network".into()114	}115116	fn copyright_start_year() -> i32 {117		2019118	}119120	fn load_spec(&self, id: &str) -> std::result::Result<Box<dyn sc_service::ChainSpec>, String> {121		load_spec(id)122	}123124	fn native_runtime_version(chain_spec: &Box<dyn ChainSpec>) -> &'static RuntimeVersion {125		#[cfg(feature = "unique-runtime")]126		if chain_spec.is_unique() {127			return &unique_runtime::VERSION;128		}129130		#[cfg(feature = "quartz-runtime")]131		if chain_spec.is_quartz() {132			return &quartz_runtime::VERSION;133		}134135		#[cfg(feature = "opal-runtime")]136		if chain_spec.is_opal() {137			return &opal_runtime::VERSION;138		}139140		panic!("{}", no_runtime_err!(chain_spec));141	}142}143144impl SubstrateCli for RelayChainCli {145	// TODO use args146	fn impl_name() -> String {147		"Unique Node".into()148	}149150	fn impl_version() -> String {151		env!("SUBSTRATE_CLI_IMPL_VERSION").into()152	}153	// TODO use args154	fn description() -> String {155		"Unique Node\n\nThe command-line arguments provided first will be \156		passed to the parachain node, while the arguments provided after -- will be passed \157		to the relaychain node.\n\n\158		parachain-collator [parachain-args] -- [relaychain-args]"159			.into()160	}161162	fn author() -> String {163		env!("CARGO_PKG_AUTHORS").into()164	}165	// TODO use args166	fn support_url() -> String {167		"support@unique.network".into()168	}169170	fn copyright_start_year() -> i32 {171		2019172	}173174	fn load_spec(&self, id: &str) -> std::result::Result<Box<dyn sc_service::ChainSpec>, String> {175		polkadot_cli::Cli::from_iter([RelayChainCli::executable_name()].iter()).load_spec(id)176	}177178	fn native_runtime_version(chain_spec: &Box<dyn ChainSpec>) -> &'static RuntimeVersion {179		polkadot_cli::Cli::native_runtime_version(chain_spec)180	}181}182183#[allow(clippy::borrowed_box)]184fn extract_genesis_wasm(chain_spec: &Box<dyn sc_service::ChainSpec>) -> Result<Vec<u8>> {185	let mut storage = chain_spec.build_storage()?;186187	storage188		.top189		.remove(sp_core::storage::well_known_keys::CODE)190		.ok_or_else(|| "Could not find wasm file in genesis state!".into())191}192193macro_rules! construct_async_run {194	(|$components:ident, $cli:ident, $cmd:ident, $config:ident| $( $code:tt )* ) => {{195		let runner = $cli.create_runner($cmd)?;196197		#[cfg(feature = "unique-runtime")]198		if runner.config().chain_spec.is_unique() {199			return runner.async_run(|$config| {200				let $components = new_partial::<201					unique_runtime::RuntimeApi, UniqueRuntimeExecutor, _202				>(203					&$config,204					crate::service::parachain_build_import_queue,205				)?;206				let task_manager = $components.task_manager;207				{ $( $code )* }.map(|v| (v, task_manager))208			});209		}210211		#[cfg(feature = "quartz-runtime")]212		if runner.config().chain_spec.is_quartz() {213			return runner.async_run(|$config| {214				let $components = new_partial::<215					quartz_runtime::RuntimeApi, QuartzRuntimeExecutor, _216				>(217					&$config,218					crate::service::parachain_build_import_queue,219				)?;220				let task_manager = $components.task_manager;221				{ $( $code )* }.map(|v| (v, task_manager))222			});223		}224225		#[cfg(feature = "opal-runtime")]226		if runner.config().chain_spec.is_opal() {227			return runner.async_run(|$config| {228				let $components = new_partial::<229					opal_runtime::RuntimeApi, OpalRuntimeExecutor, _230				>(231					&$config,232					crate::service::parachain_build_import_queue,233				)?;234				let task_manager = $components.task_manager;235				{ $( $code )* }.map(|v| (v, task_manager))236			});237		}238239		Err(no_runtime_err!(runner.config().chain_spec).into())240	}}241}242243/// Parse command line arguments into service configuration.244pub fn run() -> Result<()> {245	let cli = Cli::from_args();246247	match &cli.subcommand {248		Some(Subcommand::BuildSpec(cmd)) => {249			let runner = cli.create_runner(cmd)?;250			runner.sync_run(|config| cmd.run(config.chain_spec, config.network))251		}252		Some(Subcommand::CheckBlock(cmd)) => {253			construct_async_run!(|components, cli, cmd, config| {254				Ok(cmd.run(components.client, components.import_queue))255			})256		}257		Some(Subcommand::ExportBlocks(cmd)) => {258			construct_async_run!(|components, cli, cmd, config| {259				Ok(cmd.run(components.client, config.database))260			})261		}262		Some(Subcommand::ExportState(cmd)) => {263			construct_async_run!(|components, cli, cmd, config| {264				Ok(cmd.run(components.client, config.chain_spec))265			})266		}267		Some(Subcommand::ImportBlocks(cmd)) => {268			construct_async_run!(|components, cli, cmd, config| {269				Ok(cmd.run(components.client, components.import_queue))270			})271		}272		Some(Subcommand::PurgeChain(cmd)) => {273			let runner = cli.create_runner(cmd)?;274275			runner.sync_run(|config| {276				let polkadot_cli = RelayChainCli::new(277					&config,278					[RelayChainCli::executable_name()]279						.iter()280						.chain(cli.relaychain_args.iter()),281				);282283				let polkadot_config = SubstrateCli::create_configuration(284					&polkadot_cli,285					&polkadot_cli,286					config.tokio_handle.clone(),287				)288				.map_err(|err| format!("Relay chain argument error: {}", err))?;289290				cmd.run(config, polkadot_config)291			})292		}293		Some(Subcommand::Revert(cmd)) => construct_async_run!(|components, cli, cmd, config| {294			Ok(cmd.run(components.client, components.backend))295		}),296		Some(Subcommand::ExportGenesisState(params)) => {297			let mut builder = sc_cli::LoggerBuilder::new("");298			builder.with_profiling(sc_tracing::TracingReceiver::Log, "");299			let _ = builder.init();300301			let spec = load_spec(&params.chain.clone().unwrap_or_default())?;302			let state_version = Cli::native_runtime_version(&spec).state_version();303			let block: Block = generate_genesis_block(&spec, state_version)?;304			let raw_header = block.header().encode();305			let output_buf = if params.raw {306				raw_header307			} else {308				format!("0x{:?}", HexDisplay::from(&block.header().encode())).into_bytes()309			};310311			if let Some(output) = &params.output {312				std::fs::write(output, output_buf)?;313			} else {314				std::io::stdout().write_all(&output_buf)?;315			}316317			Ok(())318		}319		Some(Subcommand::ExportGenesisWasm(params)) => {320			let mut builder = sc_cli::LoggerBuilder::new("");321			builder.with_profiling(sc_tracing::TracingReceiver::Log, "");322			let _ = builder.init();323324			let raw_wasm_blob =325				extract_genesis_wasm(&cli.load_spec(&params.chain.clone().unwrap_or_default())?)?;326			let output_buf = if params.raw {327				raw_wasm_blob328			} else {329				format!("0x{:?}", HexDisplay::from(&raw_wasm_blob)).into_bytes()330			};331332			if let Some(output) = &params.output {333				std::fs::write(output, output_buf)?;334			} else {335				std::io::stdout().write_all(&output_buf)?;336			}337338			Ok(())339		}340		Some(Subcommand::Benchmark(cmd)) => {341			if cfg!(feature = "runtime-benchmarks") {342				let runner = cli.create_runner(cmd)?;343				runner.sync_run(|config| {344					#[cfg(feature = "unique-runtime")]345					if config.chain_spec.is_unique() {346						return cmd.run::<Block, UniqueRuntimeExecutor>(config);347					}348349					#[cfg(feature = "quartz-runtime")]350					if config.chain_spec.is_quartz() {351						return cmd.run::<Block, QuartzRuntimeExecutor>(config);352					}353354					#[cfg(feature = "opal-runtime")]355					if config.chain_spec.is_opal() {356						return cmd.run::<Block, OpalRuntimeExecutor>(config);357					}358359					Err(no_runtime_err!(config.chain_spec).into())360				})361			} else {362				Err("Benchmarking wasn't enabled when building the node. \363				You can enable it with `--features runtime-benchmarks`."364					.into())365			}366		}367		None => {368			let runner = cli.create_runner(&cli.run.normalize())?;369370			runner.run_node_until_exit(|config| async move {371				let para_id = chain_spec::Extensions::try_get(&*config.chain_spec)372					.map(|e| e.para_id)373					.ok_or("Could not find parachain ID in chain-spec.")?;374375				let polkadot_cli = RelayChainCli::new(376					&config,377					[RelayChainCli::executable_name()]378						.iter()379						.chain(cli.relaychain_args.iter()),380				);381382				let id = ParaId::from(para_id);383384				let parachain_account =385					AccountIdConversion::<polkadot_primitives::v0::AccountId>::into_account(&id);386387				let state_version =388					RelayChainCli::native_runtime_version(&config.chain_spec).state_version();389				let block: Block = generate_genesis_block(&config.chain_spec, state_version)390					.map_err(|e| format!("{:?}", e))?;391				let genesis_state = format!("0x{:?}", HexDisplay::from(&block.header().encode()));392				let genesis_hash = format!("0x{:?}", HexDisplay::from(&block.header().hash().0));393394				let polkadot_config = SubstrateCli::create_configuration(395					&polkadot_cli,396					&polkadot_cli,397					config.tokio_handle.clone(),398				)399				.map_err(|err| format!("Relay chain argument error: {}", err))?;400401				info!("Parachain id: {:?}", id);402				info!("Parachain Account: {}", parachain_account);403				info!("Parachain genesis state: {}", genesis_state);404				info!("Parachain genesis hash: {}", genesis_hash);405				info!(406					"Is collating: {}",407					if config.role.is_authority() {408						"yes"409					} else {410						"no"411					}412				);413414				#[cfg(feature = "unique-runtime")]415				if config.chain_spec.is_unique() {416					return crate::service::start_node::<417						unique_runtime::Runtime,418						unique_runtime::RuntimeApi,419						UniqueRuntimeExecutor,420					>(config, polkadot_config, id)421					.await422					.map(|r| r.0)423					.map_err(Into::into);424				}425426				#[cfg(feature = "quartz-runtime")]427				if config.chain_spec.is_quartz() {428					return crate::service::start_node::<429						quartz_runtime::Runtime,430						quartz_runtime::RuntimeApi,431						QuartzRuntimeExecutor,432					>(config, polkadot_config, id)433					.await434					.map(|r| r.0)435					.map_err(Into::into);436				}437438				#[cfg(feature = "opal-runtime")]439				if config.chain_spec.is_opal() {440					return crate::service::start_node::<441						opal_runtime::Runtime,442						opal_runtime::RuntimeApi,443						OpalRuntimeExecutor,444					>(config, polkadot_config, id)445					.await446					.map(|r| r.0)447					.map_err(Into::into);448				}449450				Err(no_runtime_err!(config.chain_spec).into())451			})452		}453	}454}455456impl DefaultConfigurationValues for RelayChainCli {457	fn p2p_listen_port() -> u16 {458		30334459	}460461	fn rpc_ws_listen_port() -> u16 {462		9945463	}464465	fn rpc_http_listen_port() -> u16 {466		9934467	}468469	fn prometheus_listen_port() -> u16 {470		9616471	}472}473474impl CliConfiguration<Self> for RelayChainCli {475	fn shared_params(&self) -> &SharedParams {476		self.base.base.shared_params()477	}478479	fn import_params(&self) -> Option<&ImportParams> {480		self.base.base.import_params()481	}482483	fn network_params(&self) -> Option<&NetworkParams> {484		self.base.base.network_params()485	}486487	fn keystore_params(&self) -> Option<&KeystoreParams> {488		self.base.base.keystore_params()489	}490491	fn base_path(&self) -> Result<Option<BasePath>> {492		Ok(self493			.shared_params()494			.base_path()495			.or_else(|| self.base_path.clone().map(Into::into)))496	}497498	fn rpc_http(&self, default_listen_port: u16) -> Result<Option<SocketAddr>> {499		self.base.base.rpc_http(default_listen_port)500	}501502	fn rpc_ipc(&self) -> Result<Option<String>> {503		self.base.base.rpc_ipc()504	}505506	fn rpc_ws(&self, default_listen_port: u16) -> Result<Option<SocketAddr>> {507		self.base.base.rpc_ws(default_listen_port)508	}509510	fn prometheus_config(511		&self,512		default_listen_port: u16,513		chain_spec: &Box<dyn ChainSpec>,514	) -> Result<Option<PrometheusConfig>> {515		self.base516			.base517			.prometheus_config(default_listen_port, chain_spec)518	}519520	fn init<F>(521		&self,522		_support_url: &String,523		_impl_version: &String,524		_logger_hook: F,525		_config: &sc_service::Configuration,526	) -> Result<()> {527		unreachable!("PolkadotCli is never initialized; qed");528	}529530	fn chain_id(&self, is_dev: bool) -> Result<String> {531		let chain_id = self.base.base.chain_id(is_dev)?;532533		Ok(if chain_id.is_empty() {534			self.chain_id.clone().unwrap_or_default()535		} else {536			chain_id537		})538	}539540	fn role(&self, is_dev: bool) -> Result<sc_service::Role> {541		self.base.base.role(is_dev)542	}543544	fn transaction_pool(&self) -> Result<sc_service::config::TransactionPoolOptions> {545		self.base.base.transaction_pool()546	}547548	fn state_cache_child_ratio(&self) -> Result<Option<usize>> {549		self.base.base.state_cache_child_ratio()550	}551552	fn rpc_methods(&self) -> Result<sc_service::config::RpcMethods> {553		self.base.base.rpc_methods()554	}555556	fn rpc_ws_max_connections(&self) -> Result<Option<usize>> {557		self.base.base.rpc_ws_max_connections()558	}559560	fn rpc_cors(&self, is_dev: bool) -> Result<Option<Vec<String>>> {561		self.base.base.rpc_cors(is_dev)562	}563564	fn default_heap_pages(&self) -> Result<Option<u64>> {565		self.base.base.default_heap_pages()566	}567568	fn force_authoring(&self) -> Result<bool> {569		self.base.base.force_authoring()570	}571572	fn disable_grandpa(&self) -> Result<bool> {573		self.base.base.disable_grandpa()574	}575576	fn max_runtime_instances(&self) -> Result<Option<usize>> {577		self.base.base.max_runtime_instances()578	}579580	fn announce_block(&self) -> Result<bool> {581		self.base.base.announce_block()582	}583584	fn telemetry_endpoints(585		&self,586		chain_spec: &Box<dyn ChainSpec>,587	) -> Result<Option<sc_telemetry::TelemetryEndpoints>> {588		self.base.base.telemetry_endpoints(chain_spec)589	}590}
modifiednode/cli/src/service.rsdiffbeforeafterboth
--- a/node/cli/src/service.rs
+++ b/node/cli/src/service.rs
@@ -25,17 +25,8 @@
 use futures::StreamExt;
 
 use unique_rpc::overrides_handle;
-// Local Runtime Types
-#[cfg(feature = "unique-runtime")]
-use unique_runtime as runtime;
-
-#[cfg(feature = "quartz-runtime")]
-use quartz_runtime as runtime;
 
-#[cfg(feature = "opal-runtime")]
-use opal_runtime as runtime;
-
-use runtime::RuntimeApi;
+use serde::{Serialize, Deserialize};
 
 // Cumulus Imports
 use cumulus_client_consensus_aura::{AuraConsensus, BuildAuraConsensusParams, SlotProportion};
@@ -71,18 +62,46 @@
 pub type Block = sp_runtime::generic::Block<Header, sp_runtime::OpaqueExtrinsic>;
 type Hash = sp_core::H256;
 
+use unique_runtime_common::types::{AuraId, RuntimeInstance, AccountId, Balance, Index};
+
 /// Native executor instance.
-pub struct ParachainRuntimeExecutor;
+pub struct UniqueRuntimeExecutor;
+pub struct QuartzRuntimeExecutor;
+pub struct OpalRuntimeExecutor;
+
+impl NativeExecutionDispatch for UniqueRuntimeExecutor {
+	type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions;
+
+	fn dispatch(method: &str, data: &[u8]) -> Option<Vec<u8>> {
+		unique_runtime::api::dispatch(method, data)
+	}
+
+	fn native_version() -> sc_executor::NativeVersion {
+		unique_runtime::native_version()
+	}
+}
+
+impl NativeExecutionDispatch for QuartzRuntimeExecutor {
+	type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions;
 
-impl NativeExecutionDispatch for ParachainRuntimeExecutor {
+	fn dispatch(method: &str, data: &[u8]) -> Option<Vec<u8>> {
+		unique_runtime::api::dispatch(method, data)
+	}
+
+	fn native_version() -> sc_executor::NativeVersion {
+		unique_runtime::native_version()
+	}
+}
+
+impl NativeExecutionDispatch for OpalRuntimeExecutor {
 	type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions;
 
 	fn dispatch(method: &str, data: &[u8]) -> Option<Vec<u8>> {
-		runtime::api::dispatch(method, data)
+		unique_runtime::api::dispatch(method, data)
 	}
 
 	fn native_version() -> sc_executor::NativeVersion {
-		runtime::native_version()
+		unique_runtime::native_version()
 	}
 }
 
@@ -106,9 +125,7 @@
 	)?))
 }
 
-type ExecutorDispatch = ParachainRuntimeExecutor;
-
-type FullClient =
+type FullClient<RuntimeApi, ExecutorDispatch> =
 	sc_service::TFullClient<Block, RuntimeApi, NativeElseWasmExecutor<ExecutorDispatch>>;
 type FullBackend = sc_service::TFullBackend<Block>;
 type FullSelectChain = sc_consensus::LongestChain<FullBackend, Block>;
@@ -118,16 +135,16 @@
 /// Use this macro if you don't actually need the full service, but just the builder in order to
 /// be able to perform chain operations.
 #[allow(clippy::type_complexity)]
-pub fn new_partial<BIQ>(
+pub fn new_partial<RuntimeApi, ExecutorDispatch, BIQ>(
 	config: &Configuration,
 	build_import_queue: BIQ,
 ) -> Result<
 	PartialComponents<
-		FullClient,
+		FullClient<RuntimeApi, ExecutorDispatch>,
 		FullBackend,
 		FullSelectChain,
-		sc_consensus::DefaultImportQueue<Block, FullClient>,
-		sc_transaction_pool::FullPool<Block, FullClient>,
+		sc_consensus::DefaultImportQueue<Block, FullClient<RuntimeApi, ExecutorDispatch>>,
+		sc_transaction_pool::FullPool<Block, FullClient<RuntimeApi, ExecutorDispatch>>,
 		(
 			Option<Telemetry>,
 			Option<FilterPool>,
@@ -140,13 +157,21 @@
 >
 where
 	sc_client_api::StateBackendFor<FullBackend, Block>: sp_api::StateBackend<BlakeTwo256>,
+	RuntimeApi: sp_api::ConstructRuntimeApi<Block, FullClient<RuntimeApi, ExecutorDispatch>>
+		+ Send
+		+ Sync
+		+ 'static,
+	RuntimeApi::RuntimeApi: sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block>,
 	ExecutorDispatch: NativeExecutionDispatch + 'static,
 	BIQ: FnOnce(
-		Arc<FullClient>,
+		Arc<FullClient<RuntimeApi, ExecutorDispatch>>,
 		&Configuration,
 		Option<TelemetryHandle>,
 		&TaskManager,
-	) -> Result<sc_consensus::DefaultImportQueue<Block, FullClient>, sc_service::Error>,
+	) -> Result<
+		sc_consensus::DefaultImportQueue<Block, FullClient<RuntimeApi, ExecutorDispatch>>,
+		sc_service::Error,
+	>,
 {
 	let _telemetry = config
 		.telemetry_endpoints
@@ -240,29 +265,50 @@
 ///
 /// This is the actual implementation that is abstract over the executor and the runtime api.
 #[sc_tracing::logging::prefix_logs_with("Parachain")]
-async fn start_node_impl<BIQ, BIC>(
+async fn start_node_impl<Runtime, RuntimeApi, ExecutorDispatch, BIQ, BIC>(
 	parachain_config: Configuration,
 	polkadot_config: Configuration,
 	id: ParaId,
 	build_import_queue: BIQ,
 	build_consensus: BIC,
-) -> sc_service::error::Result<(TaskManager, Arc<FullClient>)>
+) -> sc_service::error::Result<(TaskManager, Arc<FullClient<RuntimeApi, ExecutorDispatch>>)>
 where
 	sc_client_api::StateBackendFor<FullBackend, Block>: sp_api::StateBackend<BlakeTwo256>,
+	Runtime: RuntimeInstance + Send + Sync + 'static,
+	<Runtime as RuntimeInstance>::CrossAccountId: Serialize,
+	for<'de> <Runtime as RuntimeInstance>::CrossAccountId: Deserialize<'de>,
+	RuntimeApi: sp_api::ConstructRuntimeApi<Block, FullClient<RuntimeApi, ExecutorDispatch>>
+		+ Send
+		+ Sync
+		+ 'static,
+	RuntimeApi::RuntimeApi: sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block>
+		+ fp_rpc::EthereumRuntimeRPCApi<Block>
+		+ sp_session::SessionKeys<Block>
+		+ sp_block_builder::BlockBuilder<Block>
+		+ pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<Block, Balance>
+		+ sp_api::ApiExt<Block, StateBackend = sc_client_api::StateBackendFor<FullBackend, Block>>
+		+ up_rpc::UniqueApi<Block, Runtime::CrossAccountId, AccountId>
+		+ substrate_frame_rpc_system::AccountNonceApi<Block, AccountId, Index>
+		+ sp_api::Metadata<Block>
+		+ sp_offchain::OffchainWorkerApi<Block>
+		+ cumulus_primitives_core::CollectCollationInfo<Block>,
 	ExecutorDispatch: NativeExecutionDispatch + 'static,
 	BIQ: FnOnce(
-		Arc<FullClient>,
+		Arc<FullClient<RuntimeApi, ExecutorDispatch>>,
 		&Configuration,
 		Option<TelemetryHandle>,
 		&TaskManager,
-	) -> Result<sc_consensus::DefaultImportQueue<Block, FullClient>, sc_service::Error>,
+	) -> Result<
+		sc_consensus::DefaultImportQueue<Block, FullClient<RuntimeApi, ExecutorDispatch>>,
+		sc_service::Error,
+	>,
 	BIC: FnOnce(
-		Arc<FullClient>,
+		Arc<FullClient<RuntimeApi, ExecutorDispatch>>,
 		Option<&Registry>,
 		Option<TelemetryHandle>,
 		&TaskManager,
 		Arc<dyn RelayChainInterface>,
-		Arc<sc_transaction_pool::FullPool<Block, FullClient>>,
+		Arc<sc_transaction_pool::FullPool<Block, FullClient<RuntimeApi, ExecutorDispatch>>>,
 		Arc<NetworkService<Block, Hash>>,
 		SyncCryptoStorePtr,
 		bool,
@@ -274,7 +320,8 @@
 
 	let parachain_config = prepare_node_config(parachain_config);
 
-	let params = new_partial::<BIQ>(&parachain_config, build_import_queue)?;
+	let params =
+		new_partial::<RuntimeApi, ExecutorDispatch, BIQ>(&parachain_config, build_import_queue)?;
 	let (mut telemetry, filter_pool, frontier_backend, telemetry_worker_handle, fee_history_cache) =
 		params.other;
 
@@ -320,7 +367,7 @@
 
 	let block_data_cache = Arc::new(fc_rpc::EthBlockDataCache::new(
 		task_manager.spawn_handle(),
-		overrides_handle(client.clone()),
+		overrides_handle::<_, _, Runtime>(client.clone()),
 		50,
 		50,
 	));
@@ -346,10 +393,12 @@
 			fee_history_limit: 2048,
 		};
 
-		Ok(unique_rpc::create_full::<_, _, _, _, RuntimeApi, _>(
-			full_deps,
-			subscription_executor.clone(),
-		))
+		Ok(
+			unique_rpc::create_full::<_, _, _, _, Runtime, RuntimeApi, _>(
+				full_deps,
+				subscription_executor.clone(),
+			),
+		)
 	});
 
 	task_manager.spawn_essential_handle().spawn(
@@ -436,12 +485,26 @@
 }
 
 /// Build the import queue for the the parachain runtime.
-pub fn parachain_build_import_queue(
-	client: Arc<FullClient>,
+pub fn parachain_build_import_queue<RuntimeApi, ExecutorDispatch>(
+	client: Arc<FullClient<RuntimeApi, ExecutorDispatch>>,
 	config: &Configuration,
 	telemetry: Option<TelemetryHandle>,
 	task_manager: &TaskManager,
-) -> Result<sc_consensus::DefaultImportQueue<Block, FullClient>, sc_service::Error> {
+) -> Result<
+	sc_consensus::DefaultImportQueue<Block, FullClient<RuntimeApi, ExecutorDispatch>>,
+	sc_service::Error,
+>
+where
+	RuntimeApi: sp_api::ConstructRuntimeApi<Block, FullClient<RuntimeApi, ExecutorDispatch>>
+		+ Send
+		+ Sync
+		+ 'static,
+	RuntimeApi::RuntimeApi: sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block>
+		+ sp_block_builder::BlockBuilder<Block>
+		+ sp_consensus_aura::AuraApi<Block, AuraId>
+		+ sp_api::ApiExt<Block, StateBackend = sc_client_api::StateBackendFor<FullBackend, Block>>,
+	ExecutorDispatch: NativeExecutionDispatch + 'static,
+{
 	let slot_duration = cumulus_client_consensus_aura::slot_duration(&*client)?;
 
 	cumulus_client_consensus_aura::import_queue::<
@@ -475,12 +538,34 @@
 }
 
 /// Start a normal parachain node.
-pub async fn start_node(
+pub async fn start_node<Runtime, RuntimeApi, ExecutorDispatch>(
 	parachain_config: Configuration,
 	polkadot_config: Configuration,
 	id: ParaId,
-) -> sc_service::error::Result<(TaskManager, Arc<FullClient>)> {
-	start_node_impl::<_, _>(
+) -> sc_service::error::Result<(TaskManager, Arc<FullClient<RuntimeApi, ExecutorDispatch>>)>
+where
+	Runtime: RuntimeInstance + Send + Sync + 'static,
+	<Runtime as RuntimeInstance>::CrossAccountId: Serialize,
+	for<'de> <Runtime as RuntimeInstance>::CrossAccountId: Deserialize<'de>,
+	RuntimeApi: sp_api::ConstructRuntimeApi<Block, FullClient<RuntimeApi, ExecutorDispatch>>
+		+ Send
+		+ Sync
+		+ 'static,
+	RuntimeApi::RuntimeApi: sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block>
+		+ fp_rpc::EthereumRuntimeRPCApi<Block>
+		+ sp_session::SessionKeys<Block>
+		+ sp_block_builder::BlockBuilder<Block>
+		+ pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<Block, Balance>
+		+ sp_api::ApiExt<Block, StateBackend = sc_client_api::StateBackendFor<FullBackend, Block>>
+		+ up_rpc::UniqueApi<Block, Runtime::CrossAccountId, AccountId>
+		+ substrate_frame_rpc_system::AccountNonceApi<Block, AccountId, Index>
+		+ sp_api::Metadata<Block>
+		+ sp_offchain::OffchainWorkerApi<Block>
+		+ cumulus_primitives_core::CollectCollationInfo<Block>
+		+ sp_consensus_aura::AuraApi<Block, AuraId>,
+	ExecutorDispatch: NativeExecutionDispatch + 'static,
+{
+	start_node_impl::<Runtime, RuntimeApi, ExecutorDispatch, _, _>(
 		parachain_config,
 		polkadot_config,
 		id,
modifiednode/rpc/Cargo.tomldiffbeforeafterboth
--- a/node/rpc/Cargo.toml
+++ b/node/rpc/Cargo.toml
@@ -48,13 +48,16 @@
 fc-db = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.17" }
 fc-mapping-sync = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.17" }
 
+pallet-common = { default-features = false, path = "../../pallets/common" }
+unique-runtime-common = { default-features = false, path = "../../runtime/common" }
 pallet-unique = { path = "../../pallets/unique" }
 uc-rpc = { path = "../../client/rpc" }
 up-rpc = { path = "../../primitives/rpc" }
-unique-runtime = { path = "../../runtime/unique", optional = true }
-quartz-runtime = { path = "../../runtime/quartz", optional = true }
-opal-runtime = { path = "../../runtime/opal", optional = true }
 
+[dependencies.serde]
+features = ['derive']
+version = '1.0.130'
+
 [features]
-default = ["unique-runtime"]
+default = []
 std = []
modifiednode/rpc/src/lib.rsdiffbeforeafterboth
--- a/node/rpc/src/lib.rs
+++ b/node/rpc/src/lib.rs
@@ -40,16 +40,9 @@
 use sc_service::TransactionPool;
 use std::{collections::BTreeMap, marker::PhantomData, sync::Arc};
 
-#[cfg(feature = "unique-runtime")]
-use unique_runtime as runtime;
-
-#[cfg(feature = "quartz-runtime")]
-use quartz_runtime as runtime;
-
-#[cfg(feature = "opal-runtime")]
-use opal_runtime as runtime;
-
-use runtime::opaque::{Hash, AccountId, CrossAccountId, Index, Block, BlockNumber, Balance};
+use unique_runtime_common::types::{
+	Hash, AccountId, RuntimeInstance, Index, Block, BlockNumber, Balance,
+};
 
 /// Public io handler for exporting into other modules
 pub type IoHandler = jsonrpc_core::IoHandler<sc_rpc::Metadata>;
@@ -100,29 +93,33 @@
 	pub block_data_cache: Arc<EthBlockDataCache<Block>>,
 }
 
-struct AccountCodes<C, B> {
+struct AccountCodes<C, B, R> {
 	client: Arc<C>,
-	_marker: PhantomData<B>,
+	_blk_marker: PhantomData<B>,
+	_runtime_marker: PhantomData<R>,
 }
 
-impl<C, Block> AccountCodes<C, Block>
+impl<C, Block, R> AccountCodes<C, Block, R>
 where
 	Block: sp_api::BlockT,
 	C: ProvideRuntimeApi<Block>,
+	R: RuntimeInstance,
 {
 	fn new(client: Arc<C>) -> Self {
 		Self {
 			client,
-			_marker: PhantomData,
+			_blk_marker: PhantomData,
+			_runtime_marker: PhantomData,
 		}
 	}
 }
 
-impl<C, Block> fc_rpc::AccountCodeProvider<Block> for AccountCodes<C, Block>
+impl<C, Block, Runtime> fc_rpc::AccountCodeProvider<Block> for AccountCodes<C, Block, Runtime>
 where
 	Block: sp_api::BlockT,
 	C: ProvideRuntimeApi<Block>,
-	C::Api: up_rpc::UniqueApi<Block, CrossAccountId, AccountId>,
+	C::Api: up_rpc::UniqueApi<Block, <Runtime as RuntimeInstance>::CrossAccountId, AccountId>,
+	Runtime: RuntimeInstance,
 {
 	fn code(&self, block: &sp_api::BlockId<Block>, account: sp_core::H160) -> Option<Vec<u8>> {
 		use up_rpc::UniqueApi;
@@ -134,22 +131,23 @@
 	}
 }
 
-pub fn overrides_handle<C, BE>(client: Arc<C>) -> Arc<OverrideHandle<Block>>
+pub fn overrides_handle<C, BE, R>(client: Arc<C>) -> Arc<OverrideHandle<Block>>
 where
 	C: ProvideRuntimeApi<Block> + StorageProvider<Block, BE> + AuxStore,
 	C: HeaderBackend<Block> + HeaderMetadata<Block, Error = BlockChainError>,
 	C: Send + Sync + 'static,
 	C::Api: fp_rpc::EthereumRuntimeRPCApi<Block>,
-	C::Api: up_rpc::UniqueApi<Block, CrossAccountId, AccountId>,
+	C::Api: up_rpc::UniqueApi<Block, <R as RuntimeInstance>::CrossAccountId, AccountId>,
 	BE: Backend<Block> + 'static,
 	BE::State: StateBackend<BlakeTwo256>,
+	R: RuntimeInstance + Send + Sync + 'static,
 {
 	let mut overrides_map = BTreeMap::new();
 	overrides_map.insert(
 		EthereumStorageSchema::V1,
 		Box::new(SchemaV1Override::new_with_code_provider(
 			client.clone(),
-			Arc::new(AccountCodes::<C, Block>::new(client.clone())),
+			Arc::new(AccountCodes::<C, Block, R>::new(client.clone())),
 		)) as Box<dyn StorageOverride<_> + Send + Sync>,
 	);
 	overrides_map.insert(
@@ -170,7 +168,7 @@
 }
 
 /// Instantiate all Full RPC extensions.
-pub fn create_full<C, P, SC, CA, A, B>(
+pub fn create_full<C, P, SC, CA, R, A, B>(
 	deps: FullDeps<C, P, SC, CA>,
 	subscription_task_executor: SubscriptionTaskExecutor,
 ) -> jsonrpc_core::IoHandler<sc_rpc_api::Metadata>
@@ -184,11 +182,14 @@
 	// C::Api: pallet_contracts_rpc::ContractsRuntimeApi<Block, AccountId, Balance, BlockNumber, Hash>,
 	C::Api: pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi<Block, Balance>,
 	C::Api: fp_rpc::EthereumRuntimeRPCApi<Block>,
-	C::Api: up_rpc::UniqueApi<Block, CrossAccountId, AccountId>,
+	C::Api: up_rpc::UniqueApi<Block, <R as RuntimeInstance>::CrossAccountId, AccountId>,
 	B: sc_client_api::Backend<Block> + Send + Sync + 'static,
 	B::State: sc_client_api::backend::StateBackend<sp_runtime::traits::HashFor<Block>>,
 	P: TransactionPool<Block = Block> + 'static,
 	CA: ChainApi<Block = Block> + 'static,
+	R: RuntimeInstance + Send + Sync + 'static,
+	<R as RuntimeInstance>::CrossAccountId: serde::Serialize,
+	for<'de> <R as RuntimeInstance>::CrossAccountId: serde::Deserialize<'de>,
 {
 	use fc_rpc::{
 		EthApi, EthApiServer, EthDevSigner, EthFilterApi, EthFilterApiServer, EthPubSubApi,
@@ -235,13 +236,13 @@
 		signers.push(Box::new(EthDevSigner::new()) as Box<dyn EthSigner>);
 	}
 
-	let overrides = overrides_handle(client.clone());
+	let overrides = overrides_handle::<_, _, R>(client.clone());
 
 	io.extend_with(EthApiServer::to_delegate(EthApi::new(
 		client.clone(),
 		pool.clone(),
 		graph,
-		runtime::TransactionConverter,
+		<R as RuntimeInstance>::get_transaction_converter(),
 		network.clone(),
 		signers,
 		overrides.clone(),