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

difftreelog

refactor merge with new node template

Yaroslav Bolyukin2021-03-31parent: #de5a81f.patch.diff
in: master

6 files changed

modifiednode/src/chain_spec.rsdiffbeforeafterboth
before · node/src/chain_spec.rs
1//2// This file is subject to the terms and conditions defined in3// file 'LICENSE', which is part of this source code package.4//56// use nft_runtime::{7//     AccountId, AuraConfig, BalancesConfig, GenesisConfig, GrandpaConfig, Signature, SudoConfig,8//     SystemConfig, WASM_BINARY,9// };10// use nft_runtime::{ContractsConfig, ContractsSchedule, NftConfig, CollectionType};11use nft_runtime::*;12use sc_service::ChainType;13use sp_consensus_aura::sr25519::AuthorityId as AuraId;14use sp_core::{sr25519, Pair, Public};15use sp_finality_grandpa::AuthorityId as GrandpaId;16use sp_runtime::traits::{IdentifyAccount, Verify};17use serde_json::map::Map;18// use crate::chain_spec::api::chain_extension::*;1920// Note this is the URL for the telemetry server21//const STAGING_TELEMETRY_URL: &str = "wss://telemetry.polkadot.io/submit/";2223/// Specialized `ChainSpec`. This is a specialization of the general Substrate ChainSpec type.24pub type ChainSpec = sc_service::GenericChainSpec<GenesisConfig>;2526/// Helper function to generate a crypto pair from seed27pub fn get_from_seed<TPublic: Public>(seed: &str) -> <TPublic::Pair as Pair>::Public {28    TPublic::Pair::from_string(&format!("//{}", seed), None)29        .expect("static values are valid; qed")30        .public()31}3233type AccountPublic = <Signature as Verify>::Signer;3435/// Helper function to generate an account ID from seed36pub fn get_account_id_from_seed<TPublic: Public>(seed: &str) -> AccountId37where38    AccountPublic: From<<TPublic::Pair as Pair>::Public>,39{40    AccountPublic::from(get_from_seed::<TPublic>(seed)).into_account()41}4243/// Helper function to generate an authority key for Aura44pub fn authority_keys_from_seed(s: &str) -> (AuraId, GrandpaId) {45    (get_from_seed::<AuraId>(s), get_from_seed::<GrandpaId>(s))46}4748pub fn development_config() -> Result<ChainSpec, String> {49	let wasm_binary = WASM_BINARY.ok_or("Development wasm binary not available".to_string())?;5051	let mut properties = Map::new();52	properties.insert("tokenSymbol".into(), "UniqueTest".into());53	properties.insert("tokenDecimals".into(), 15.into());54	properties.insert("ss58Format".into(), 42.into()); // Generic Substrate wildcard (SS58 checksum preimage)5556	Ok(ChainSpec::from_genesis(57		// Name58		"Development",59		// ID60		"dev",61		ChainType::Development,62		move || testnet_genesis(63			wasm_binary,64			// Initial PoA authorities65			vec![66				authority_keys_from_seed("Alice"),67			],68			// Sudo account69			get_account_id_from_seed::<sr25519::Public>("Alice"),70			// Pre-funded accounts71			vec![72				get_account_id_from_seed::<sr25519::Public>("Alice"),73				get_account_id_from_seed::<sr25519::Public>("Bob"),74				get_account_id_from_seed::<sr25519::Public>("Alice//stash"),75				get_account_id_from_seed::<sr25519::Public>("Bob//stash"),76			],77			true,78		),79		// Bootnodes80		vec![],81		// Telemetry82		None,83		// Protocol ID84		None,85		// Properties86		Some(properties),87		// Extensions88		None,89	))90}9192pub fn local_testnet_config() -> Result<ChainSpec, String> {93	let wasm_binary = WASM_BINARY.ok_or("Development wasm binary not available".to_string())?;9495	Ok(ChainSpec::from_genesis(96		// Name97		"Local Testnet",98		// ID99		"local_testnet",100		ChainType::Local,101		move || testnet_genesis(102			wasm_binary,103			// Initial PoA authorities104			vec![105				authority_keys_from_seed("Alice"),106				authority_keys_from_seed("Bob"),107			],108			// Sudo account109			get_account_id_from_seed::<sr25519::Public>("Alice"),110			// Pre-funded accounts111			vec![112				get_account_id_from_seed::<sr25519::Public>("Alice"),113				get_account_id_from_seed::<sr25519::Public>("Bob"),114				get_account_id_from_seed::<sr25519::Public>("Charlie"),115				get_account_id_from_seed::<sr25519::Public>("Dave"),116				get_account_id_from_seed::<sr25519::Public>("Eve"),117				get_account_id_from_seed::<sr25519::Public>("Ferdie"),118				get_account_id_from_seed::<sr25519::Public>("Alice//stash"),119				get_account_id_from_seed::<sr25519::Public>("Bob//stash"),120				get_account_id_from_seed::<sr25519::Public>("Charlie//stash"),121				get_account_id_from_seed::<sr25519::Public>("Dave//stash"),122				get_account_id_from_seed::<sr25519::Public>("Eve//stash"),123				get_account_id_from_seed::<sr25519::Public>("Ferdie//stash"),124			],125			true,126		),127		// Bootnodes128		vec![],129		// Telemetry130		None,131		// Protocol ID132		None,133		// Properties134		None,135		// Extensions136		None,137	))138}139140fn testnet_genesis(141    wasm_binary: &[u8],142    initial_authorities: Vec<(AuraId, GrandpaId)>,143    root_key: AccountId,144    endowed_accounts: Vec<AccountId>,145    enable_println: bool,146) -> GenesisConfig {147148	let vested_accounts = vec![149		get_account_id_from_seed::<sr25519::Public>("Bob"),150	];151152    GenesisConfig {153        system: Some(SystemConfig {154            code: wasm_binary.to_vec(),155            changes_trie_config: Default::default(),156        }),157        pallet_balances: Some(BalancesConfig {158            balances: endowed_accounts159                .iter()160                .cloned()161                .map(|k| (k, 1 << 100))162                .collect(),163        }),164        pallet_aura: Some(AuraConfig {165            authorities: initial_authorities.iter().map(|x| (x.0.clone())).collect(),166        }),167		pallet_grandpa: Some(GrandpaConfig {168            authorities: initial_authorities169                .iter()170                .map(|x| (x.1.clone(), 1))171                .collect(),172		}),173		pallet_treasury: Some(Default::default()),174		pallet_sudo: Some(SudoConfig { key: root_key }),175		pallet_vesting: Some(VestingConfig {176            vesting: vested_accounts177                .iter()178                .cloned()179                .map(|k| (k, 1000, 100, 1 << 98))180                .collect(),181        }),182        pallet_nft: Some(NftConfig {183            collection_id: vec![(184                1,185                Collection {186                    owner: get_account_id_from_seed::<sr25519::Public>("Alice"),187                    mode: CollectionMode::NFT,188                    access: AccessMode::Normal,189                    decimal_points: 0,190                    name: vec![],191                    description: vec![],192                    token_prefix: vec![],193                    mint_mode: false,194					offchain_schema: vec![],195					schema_version: SchemaVersion::default(),196                    sponsorship: SponsorshipState::Confirmed(get_account_id_from_seed::<sr25519::Public>("Alice")),197                    const_on_chain_schema: vec![],198					variable_on_chain_schema: vec![],199					limits: CollectionLimits::default()200                },201            )],202            nft_item_id: vec![],203            fungible_item_id: vec![],204            refungible_item_id: vec![],205            chain_limit: ChainLimits {206                collection_numbers_limit: 100000,207                account_token_ownership_limit: 1000000,208                collections_admins_limit: 5,209                custom_data_limit: 2048,210                nft_sponsor_transfer_timeout: 15,211                fungible_sponsor_transfer_timeout: 15,212				refungible_sponsor_transfer_timeout: 15,213				offchain_schema_limit: 1024,214				variable_on_chain_schema_limit: 1024,215				const_on_chain_schema_limit: 1024,216            },217        }),218        pallet_contracts: Some(ContractsConfig {219            current_schedule: ContractsSchedule {220                enable_println,221                ..Default::default()222            },223        }),224    }225}
after · node/src/chain_spec.rs
1//2// This file is subject to the terms and conditions defined in3// file 'LICENSE', which is part of this source code package.4//56use nft_runtime::*;7use sp_core::{Pair, Public, sr25519};8use nft_runtime::{9	AccountId, AuraConfig, BalancesConfig, EVMConfig, EthereumConfig, GenesisConfig, GrandpaConfig,10	SudoConfig, SystemConfig, WASM_BINARY, Signature11};12use sp_consensus_aura::sr25519::AuthorityId as AuraId;13use sp_finality_grandpa::AuthorityId as GrandpaId;14use sp_runtime::traits::{Verify, IdentifyAccount};15use sc_service::ChainType;16use serde_json::map::Map;17use std::collections::BTreeMap;1819// Note this is the URL for the telemetry server20//const STAGING_TELEMETRY_URL: &str = "wss://telemetry.polkadot.io/submit/";2122/// Specialized `ChainSpec`. This is a specialization of the general Substrate ChainSpec type.23pub type ChainSpec = sc_service::GenericChainSpec<GenesisConfig>;2425/// Helper function to generate a crypto pair from seed26pub fn get_from_seed<TPublic: Public>(seed: &str) -> <TPublic::Pair as Pair>::Public {27	TPublic::Pair::from_string(&format!("//{}", seed), None)28		.expect("static values are valid; qed")29		.public()30}3132type AccountPublic = <Signature as Verify>::Signer;3334/// Helper function to generate an account ID from seed35pub fn get_account_id_from_seed<TPublic: Public>(seed: &str) -> AccountId36where37	AccountPublic: From<<TPublic::Pair as Pair>::Public>,38{39	AccountPublic::from(get_from_seed::<TPublic>(seed)).into_account()40}4142/// Helper function to generate an authority key for Aura43pub fn authority_keys_from_seed(s: &str) -> (AuraId, GrandpaId) {44	(get_from_seed::<AuraId>(s), get_from_seed::<GrandpaId>(s))45}4647pub fn development_config() -> Result<ChainSpec, String> {48	let wasm_binary = WASM_BINARY.ok_or("Development wasm binary not available".to_string())?;4950	let mut properties = Map::new();51	properties.insert("tokenSymbol".into(), "UniqueTest".into());52	properties.insert("tokenDecimals".into(), 15.into());53	properties.insert("ss58Format".into(), 42.into()); // Generic Substrate wildcard (SS58 checksum preimage)5455	Ok(ChainSpec::from_genesis(56		// Name57		"Development",58		// ID59		"dev",60		ChainType::Development,61		move || testnet_genesis(62			wasm_binary,63			// Initial PoA authorities64			vec![65				authority_keys_from_seed("Alice"),66			],67			// Sudo account68			get_account_id_from_seed::<sr25519::Public>("Alice"),69			// Pre-funded accounts70			vec![71				get_account_id_from_seed::<sr25519::Public>("Alice"),72				get_account_id_from_seed::<sr25519::Public>("Bob"),73				get_account_id_from_seed::<sr25519::Public>("Alice//stash"),74				get_account_id_from_seed::<sr25519::Public>("Bob//stash"),75			],76			true,77		),78		// Bootnodes79		vec![],80		// Telemetry81		None,82		// Protocol ID83		None,84		// Properties85		Some(properties),86		// Extensions87		None,88	))89}9091pub fn local_testnet_config() -> Result<ChainSpec, String> {92	let wasm_binary = WASM_BINARY.ok_or("Development wasm binary not available".to_string())?;9394	Ok(ChainSpec::from_genesis(95		// Name96		"Local Testnet",97		// ID98		"local_testnet",99		ChainType::Local,100		move || testnet_genesis(101			wasm_binary,102			// Initial PoA authorities103			vec![104				authority_keys_from_seed("Alice"),105				authority_keys_from_seed("Bob"),106			],107			// Sudo account108			get_account_id_from_seed::<sr25519::Public>("Alice"),109			// Pre-funded accounts110			vec![111				get_account_id_from_seed::<sr25519::Public>("Alice"),112				get_account_id_from_seed::<sr25519::Public>("Bob"),113				get_account_id_from_seed::<sr25519::Public>("Charlie"),114				get_account_id_from_seed::<sr25519::Public>("Dave"),115				get_account_id_from_seed::<sr25519::Public>("Eve"),116				get_account_id_from_seed::<sr25519::Public>("Ferdie"),117				get_account_id_from_seed::<sr25519::Public>("Alice//stash"),118				get_account_id_from_seed::<sr25519::Public>("Bob//stash"),119				get_account_id_from_seed::<sr25519::Public>("Charlie//stash"),120				get_account_id_from_seed::<sr25519::Public>("Dave//stash"),121				get_account_id_from_seed::<sr25519::Public>("Eve//stash"),122				get_account_id_from_seed::<sr25519::Public>("Ferdie//stash"),123			],124			true,125		),126		// Bootnodes127		vec![],128		// Telemetry129		None,130		// Protocol ID131		None,132		// Properties133		None,134		// Extensions135		None,136	))137}138139fn testnet_genesis(140	wasm_binary: &[u8],141	initial_authorities: Vec<(AuraId, GrandpaId)>,142	root_key: AccountId,143	endowed_accounts: Vec<AccountId>,144	enable_println: bool,145) -> GenesisConfig {146147	let vested_accounts = vec![148		get_account_id_from_seed::<sr25519::Public>("Bob"),149	];150151	GenesisConfig {152		system: SystemConfig {153			code: wasm_binary.to_vec(),154			changes_trie_config: Default::default(),155		},156		pallet_balances: BalancesConfig {157			balances: endowed_accounts158				.iter()159				.cloned()160				.map(|k| (k, 1 << 100))161				.collect(),162		},163		pallet_aura: AuraConfig {164			authorities: initial_authorities.iter().map(|x| (x.0.clone())).collect(),165		},166		pallet_grandpa: GrandpaConfig {167			authorities: initial_authorities168				.iter()169				.map(|x| (x.1.clone(), 1))170				.collect(),171		},172		pallet_treasury: Default::default(),173		pallet_sudo: SudoConfig { key: root_key },174		pallet_vesting: VestingConfig {175			vesting: vested_accounts176				.iter()177				.cloned()178				.map(|k| (k, 1000, 100, 1 << 98))179				.collect(),180		},181		pallet_nft: NftConfig {182			collection_id: vec![(183				1,184				Collection {185					owner: get_account_id_from_seed::<sr25519::Public>("Alice"),186					mode: CollectionMode::NFT,187					access: AccessMode::Normal,188					decimal_points: 0,189					name: vec![],190					description: vec![],191					token_prefix: vec![],192					mint_mode: false,193					offchain_schema: vec![],194					schema_version: SchemaVersion::default(),195					sponsorship: SponsorshipState::Confirmed(get_account_id_from_seed::<sr25519::Public>("Alice")),196					const_on_chain_schema: vec![],197					variable_on_chain_schema: vec![],198					limits: CollectionLimits::default()199				},200			)],201			nft_item_id: vec![],202			fungible_item_id: vec![],203			refungible_item_id: vec![],204			chain_limit: ChainLimits {205				collection_numbers_limit: 100000,206				account_token_ownership_limit: 1000000,207				collections_admins_limit: 5,208				custom_data_limit: 2048,209				nft_sponsor_transfer_timeout: 15,210				fungible_sponsor_transfer_timeout: 15,211				refungible_sponsor_transfer_timeout: 15,212				offchain_schema_limit: 1024,213				variable_on_chain_schema_limit: 1024,214				const_on_chain_schema_limit: 1024,215			},216		},217		pallet_contracts: ContractsConfig {218			current_schedule: ContractsSchedule {219				enable_println,220				..Default::default()221			},222		},223		pallet_evm: EVMConfig {224			accounts: BTreeMap::new(),225		},226		pallet_ethereum: EthereumConfig {},227	}228}
modifiednode/src/command.rsdiffbeforeafterboth
--- a/node/src/command.rs
+++ b/node/src/command.rs
@@ -75,7 +75,7 @@
 			let runner = cli.create_runner(cmd)?;
 			runner.async_run(|config| {
 				let PartialComponents { client, task_manager, import_queue, ..}
-					= service::new_partial(&config)?;
+					= service::new_partial(&config, &cli)?;
 				Ok((cmd.run(client, import_queue), task_manager))
 			})
 		},
@@ -83,7 +83,7 @@
 			let runner = cli.create_runner(cmd)?;
 			runner.async_run(|config| {
 				let PartialComponents { client, task_manager, ..}
-					= service::new_partial(&config)?;
+					= service::new_partial(&config, &cli)?;
 				Ok((cmd.run(client, config.database), task_manager))
 			})
 		},
@@ -91,7 +91,7 @@
 			let runner = cli.create_runner(cmd)?;
 			runner.async_run(|config| {
 				let PartialComponents { client, task_manager, ..}
-					= service::new_partial(&config)?;
+					= service::new_partial(&config, &cli)?;
 				Ok((cmd.run(client, config.chain_spec), task_manager))
 			})
 		},
@@ -99,7 +99,7 @@
 			let runner = cli.create_runner(cmd)?;
 			runner.async_run(|config| {
 				let PartialComponents { client, task_manager, import_queue, ..}
-					= service::new_partial(&config)?;
+					= service::new_partial(&config, &cli)?;
 				Ok((cmd.run(client, import_queue), task_manager))
 			})
 		},
@@ -111,7 +111,7 @@
 			let runner = cli.create_runner(cmd)?;
 			runner.async_run(|config| {
 				let PartialComponents { client, task_manager, backend, ..}
-					= service::new_partial(&config)?;
+					= service::new_partial(&config, &cli)?;
 				Ok((cmd.run(client, backend), task_manager))
 			})
 		},
@@ -130,7 +130,7 @@
 			runner.run_node_until_exit(|config| async move {
 				match config.role {
 					Role::Light => service::new_light(config),
-					_ => service::new_full(config),
+					_ => service::new_full(config, &cli),
 				}.map_err(sc_cli::Error::Service)
 			})
 		}
deletednode/src/lib.rsdiffbeforeafterboth
--- a/node/src/lib.rs
+++ /dev/null
@@ -1,3 +0,0 @@
-pub mod chain_spec;
-pub mod service;
-pub mod rpc;
modifiednode/src/main.rsdiffbeforeafterboth
--- a/node/src/main.rs
+++ b/node/src/main.rs
@@ -14,5 +14,5 @@
 mod rpc;
 
 fn main() -> sc_cli::Result<()> {
-    command::run()
+	command::run()
 }
modifiednode/src/rpc.rsdiffbeforeafterboth
--- a/node/src/rpc.rs
+++ b/node/src/rpc.rs
@@ -3,17 +3,38 @@
 //! used by Substrate nodes. This file extends those RPC definitions with
 //! capabilities that are specific to this project's runtime configuration.
 
-#![warn(missing_docs)]
-
 use std::sync::Arc;
 
-use nft_runtime::{opaque::Block, AccountId, Balance, Index, BlockNumber};
+use std::collections::BTreeMap;
+use fc_rpc_core::types::{PendingTransactions, FilterPool};
+use nft_runtime::{Hash, AccountId, Index, opaque::Block, Balance};
 use sp_api::ProvideRuntimeApi;
 use sp_blockchain::{Error as BlockChainError, HeaderMetadata, HeaderBackend};
+use sc_client_api::{
+	backend::{StorageProvider, Backend, StateBackend, AuxStore},
+	client::BlockchainEvents
+};
+use sc_rpc::SubscriptionTaskExecutor;
+use sp_runtime::traits::BlakeTwo256;
 use sp_block_builder::BlockBuilder;
-pub use sc_rpc_api::DenyUnsafe;
+use sc_rpc_api::DenyUnsafe;
 use sp_transaction_pool::TransactionPool;
-use pallet_contracts_rpc::{Contracts, ContractsApi};
+use sc_network::NetworkService;
+use jsonrpc_pubsub::manager::SubscriptionManager;
+use pallet_ethereum::EthereumStorageSchema;
+use fc_rpc::{StorageOverride, SchemaV1Override};
+
+/// Light client extra dependencies.
+pub struct LightDeps<C, F, P> {
+	/// The client instance to use.
+	pub client: Arc<C>,
+	/// Transaction pool instance.
+	pub pool: Arc<P>,
+	/// Remote access to the blockchain (async).
+	pub remote_blockchain: Arc<dyn sc_client_api::light::RemoteBlockchain<Block>>,
+	/// Fetcher instance.
+	pub fetcher: Arc<F>,
+}
 
 /// Full client dependencies.
 pub struct FullDeps<C, P> {
@@ -23,47 +44,155 @@
 	pub pool: Arc<P>,
 	/// Whether to deny unsafe calls
 	pub deny_unsafe: DenyUnsafe,
+	/// The Node authority flag
+	pub is_authority: bool,
+	/// Whether to enable dev signer
+	pub enable_dev_signer: bool,
+	/// Network service
+	pub network: Arc<NetworkService<Block, Hash>>,
+	/// Ethereum pending transactions.
+	pub pending_transactions: PendingTransactions,
+	/// EthFilterApi pool.
+	pub filter_pool: Option<FilterPool>,
+	/// Backend.
+	pub backend: Arc<fc_db::Backend<Block>>,
 }
 
 /// Instantiate all full RPC extensions.
-pub fn create_full<C, P>(
+pub fn create_full<C, P, BE>(
 	deps: FullDeps<C, P>,
+	subscription_task_executor: SubscriptionTaskExecutor
 ) -> jsonrpc_core::IoHandler<sc_rpc::Metadata> where
-	C: ProvideRuntimeApi<Block>,
-	C: HeaderBackend<Block> + HeaderMetadata<Block, Error=BlockChainError> + 'static,
+	BE: Backend<Block> + 'static,
+	BE::State: StateBackend<BlakeTwo256>,
+	C: ProvideRuntimeApi<Block> + StorageProvider<Block, BE> + AuxStore,
+	C: BlockchainEvents<Block>,
+	C: HeaderBackend<Block> + HeaderMetadata<Block, Error=BlockChainError>,
 	C: Send + Sync + 'static,
 	C::Api: substrate_frame_rpc_system::AccountNonceApi<Block, AccountId, Index>,
-	C::Api: pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi<Block, Balance>,
 	C::Api: BlockBuilder<Block>,
-	C::Api: pallet_contracts_rpc::ContractsRuntimeApi<Block, AccountId, Balance, BlockNumber>,
-	P: TransactionPool + 'static,
+	C::Api: pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi<Block, Balance>,
+	C::Api: fp_rpc::EthereumRuntimeRPCApi<Block>,
+	P: TransactionPool<Block=Block> + 'static,
 {
 	use substrate_frame_rpc_system::{FullSystem, SystemApi};
 	use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApi};
+	use fc_rpc::{
+		EthApi, EthApiServer, EthFilterApi, EthFilterApiServer, NetApi, NetApiServer,
+		EthPubSubApi, EthPubSubApiServer, Web3Api, Web3ApiServer, EthDevSigner, EthSigner,
+		HexEncodedIdProvider,
+	};
 
 	let mut io = jsonrpc_core::IoHandler::default();
 	let FullDeps {
 		client,
 		pool,
 		deny_unsafe,
+		is_authority,
+		network,
+		pending_transactions,
+		filter_pool,
+		backend,
+		enable_dev_signer,
 	} = deps;
 
 	io.extend_with(
-		SystemApi::to_delegate(FullSystem::new(client.clone(), pool, deny_unsafe))
+		SystemApi::to_delegate(FullSystem::new(client.clone(), pool.clone(), deny_unsafe))
 	);
 
 	io.extend_with(
 		TransactionPaymentApi::to_delegate(TransactionPayment::new(client.clone()))
 	);
 
-    io.extend_with(
-        ContractsApi::to_delegate(Contracts::new(client.clone()))
+	// io.extend_with(
+	// 	ContractsApi::to_delegate(Contracts::new(client.clone()))
+	// );
+
+	let mut signers = Vec::new();
+	if enable_dev_signer {
+		signers.push(Box::new(EthDevSigner::new()) as Box<dyn EthSigner>);
+	}
+	let mut overrides = BTreeMap::new();
+	overrides.insert(
+		EthereumStorageSchema::V1,
+		Box::new(SchemaV1Override::new(client.clone())) as Box<dyn StorageOverride<_> + Send + Sync>
+	);
+	io.extend_with(
+		EthApiServer::to_delegate(EthApi::new(
+			client.clone(),
+			pool.clone(),
+			nft_runtime::TransactionConverter,
+			network.clone(),
+			pending_transactions.clone(),
+			signers,
+			overrides,
+			backend,
+			is_authority,
+		))
+	);
+
+	if let Some(filter_pool) = filter_pool {
+		io.extend_with(
+			EthFilterApiServer::to_delegate(EthFilterApi::new(
+				client.clone(),
+				filter_pool.clone(),
+				500 as usize, // max stored filters
+			))
+		);
+	}
+
+	io.extend_with(
+		NetApiServer::to_delegate(NetApi::new(
+			client.clone(),
+			network.clone(),
+		))
 	);
-		
-	// Extend this RPC with a custom API by using the following syntax.
-	// `YourRpcStruct` should have a reference to a client, which is needed
-	// to call into the runtime.
-	// `io.extend_with(YourRpcTrait::to_delegate(YourRpcStruct::new(ReferenceToClient, ...)));`
 
+	io.extend_with(
+		Web3ApiServer::to_delegate(Web3Api::new(
+			client.clone(),
+		))
+	);
+
+	io.extend_with(
+		EthPubSubApiServer::to_delegate(EthPubSubApi::new(
+			pool.clone(),
+			client.clone(),
+			network.clone(),
+			SubscriptionManager::<HexEncodedIdProvider>::with_id_provider(
+				HexEncodedIdProvider::default(),
+				Arc::new(subscription_task_executor)
+			),
+		))
+	);
+
+	io
+}
+
+/// Instantiate all Light RPC extensions.
+pub fn create_light<C, P, M, F>(
+	deps: LightDeps<C, F, P>,
+) -> jsonrpc_core::IoHandler<M> where
+	C: sp_blockchain::HeaderBackend<Block>,
+	C: Send + Sync + 'static,
+	F: sc_client_api::light::Fetcher<Block> + 'static,
+	P: TransactionPool + 'static,
+	M: jsonrpc_core::Metadata + Default,
+{
+	use substrate_frame_rpc_system::{LightSystem, SystemApi};
+
+	let LightDeps {
+		client,
+		pool,
+		remote_blockchain,
+		fetcher
+	} = deps;
+	let mut io = jsonrpc_core::IoHandler::default();
+	io.extend_with(
+		SystemApi::<Hash, AccountId, Index>::to_delegate(
+			LightSystem::new(client, remote_blockchain, fetcher, pool)
+		)
+	);
+
 	io
 }
modifiednode/src/service.rsdiffbeforeafterboth
--- a/node/src/service.rs
+++ b/node/src/service.rs
@@ -5,17 +5,26 @@
 // file 'LICENSE', which is part of this source code package.
 //
 
-use std::sync::Arc;
-use std::time::Duration;
-use sc_client_api::{ExecutorProvider, RemoteBackend};
-use nft_runtime::{self, opaque::Block, RuntimeApi};
-use sc_service::{error::Error as ServiceError, Configuration, TaskManager};
-use sp_inherents::InherentDataProviders;
+use std::{sync::{Arc, Mutex}, cell::RefCell, time::Duration, collections::{HashMap, BTreeMap}};
+use fc_rpc::EthTask;
+use fc_rpc_core::types::{FilterPool, PendingTransactions};
+use sc_client_api::{ExecutorProvider, RemoteBackend, BlockchainEvents};
+use fc_consensus::FrontierBlockImport;
+use fc_mapping_sync::MappingSyncWorker;
+use nft_runtime::{self, opaque::Block, RuntimeApi, SLOT_DURATION};
+use sc_service::{error::Error as ServiceError, Configuration, TaskManager, BasePath};
+use sp_inherents::{InherentDataProviders, ProvideInherentData, InherentIdentifier, InherentData};
 use sc_executor::native_executor_instance;
 pub use sc_executor::NativeExecutor;
+use sc_consensus_aura::{ImportQueueParams, StartAuraParams, SlotProportion};
 use sp_consensus_aura::sr25519::{AuthorityPair as AuraPair};
 use sc_finality_grandpa::SharedVoterState;
-use sc_keystore::LocalKeystore;
+use sp_timestamp::InherentError;
+use sc_telemetry::{Telemetry, TelemetryWorker};
+use sc_cli::SubstrateCli;
+use futures::StreamExt;
+
+use crate::cli::Cli;
 
 // Our native executor instance.
 native_executor_instance!(
@@ -29,30 +38,96 @@
 type FullBackend = sc_service::TFullBackend<Block>;
 type FullSelectChain = sc_consensus::LongestChain<FullBackend, Block>;
 
-pub fn new_partial(config: &Configuration) -> Result<sc_service::PartialComponents<
-	FullClient, FullBackend, FullSelectChain,
-	sp_consensus::DefaultImportQueue<Block, FullClient>,
-	sc_transaction_pool::FullPool<Block, FullClient>,
-	(
-		sc_consensus_aura::AuraBlockImport<
+pub type ConsensusResult = (
+	sc_consensus_aura::AuraBlockImport<
+		Block,
+		FullClient,
+		FrontierBlockImport<
 			Block,
-			FullClient,
 			sc_finality_grandpa::GrandpaBlockImport<FullBackend, Block, FullClient, FullSelectChain>,
-			AuraPair
+			FullClient
 		>,
-		sc_finality_grandpa::LinkHalf<Block, FullClient, FullSelectChain>,
-	)
->, ServiceError> {
-	if config.keystore_remote.is_some() {
-		return Err(ServiceError::Other(
-			format!("Remote Keystores are not supported.")))
+		AuraPair
+	>,
+	sc_finality_grandpa::LinkHalf<Block, FullClient, FullSelectChain>
+);
+
+/// Provide a mock duration starting at 0 in millisecond for timestamp inherent.
+/// Each call will increment timestamp by slot_duration making Aura think time has passed.
+pub struct MockTimestampInherentDataProvider;
+
+pub const INHERENT_IDENTIFIER: InherentIdentifier = *b"timstap0";
+
+thread_local!(static TIMESTAMP: RefCell<u64> = RefCell::new(0));
+
+impl ProvideInherentData for MockTimestampInherentDataProvider {
+	fn inherent_identifier(&self) -> &'static InherentIdentifier {
+		&INHERENT_IDENTIFIER
 	}
+
+	fn provide_inherent_data(
+		&self,
+		inherent_data: &mut InherentData,
+	) -> Result<(), sp_inherents::Error> {
+		TIMESTAMP.with(|x| {
+			*x.borrow_mut() += SLOT_DURATION;
+			inherent_data.put_data(INHERENT_IDENTIFIER, &*x.borrow())
+		})
+	}
+
+	fn error_to_string(&self, error: &[u8]) -> Option<String> {
+		InherentError::try_from(&INHERENT_IDENTIFIER, error).map(|e| format!("{:?}", e))
+	}
+}
+
+pub fn open_frontier_backend(config: &Configuration) -> Result<Arc<fc_db::Backend<Block>>, String> {
+	let config_dir = config.base_path.as_ref()
+		.map(|base_path| base_path.config_dir(config.chain_spec.id()))
+		.unwrap_or_else(|| {
+			BasePath::from_project("", "", &crate::cli::Cli::executable_name())
+				.config_dir(config.chain_spec.id())
+		});
+	let database_dir = config_dir.join("frontier").join("db");
+
+	Ok(Arc::new(fc_db::Backend::<Block>::new(&fc_db::DatabaseSettings {
+		source: fc_db::DatabaseSettingsSrc::RocksDb {
+			path: database_dir,
+			cache_size: 0,
+		}
+	})?))
+}
+
+pub fn new_partial(config: &Configuration, #[allow(unused_variables)] cli: &Cli) -> Result<
+	sc_service::PartialComponents<
+		FullClient, FullBackend, FullSelectChain,
+		sp_consensus::import_queue::BasicQueue<Block, sp_api::TransactionFor<FullClient, Block>>,
+		sc_transaction_pool::FullPool<Block, FullClient>,
+		(ConsensusResult, PendingTransactions, Option<FilterPool>, Arc<fc_db::Backend<Block>>, Option<Telemetry>),
+>, ServiceError> {
 	let inherent_data_providers = sp_inherents::InherentDataProviders::new();
 
+	let telemetry = config.telemetry_endpoints.clone()
+		.filter(|x| !x.is_empty())
+		.map(|endpoints| -> Result<_, sc_telemetry::Error> {
+			let worker = TelemetryWorker::new(16)?;
+			let telemetry = worker.handle().new_telemetry(endpoints);
+			Ok((worker, telemetry))
+		})
+		.transpose()?;
+
 	let (client, backend, keystore_container, task_manager) =
-		sc_service::new_full_parts::<Block, RuntimeApi, Executor>(&config)?;
+		sc_service::new_full_parts::<Block, RuntimeApi, Executor>(
+			&config,
+			telemetry.as_ref().map(|(_, telemetry)| telemetry.handle()),
+		)?;
 	let client = Arc::new(client);
 
+	let telemetry = telemetry
+		.map(|(worker, telemetry)| {
+			task_manager.spawn_handle().spawn("telemetry", worker.run());
+			telemetry
+		});
+
 	let select_chain = sc_consensus::LongestChain::new(backend.clone());
 
 	let transaction_pool = sc_transaction_pool::BasicPool::new_full(
@@ -63,64 +138,77 @@
 		client.clone(),
 	);
 
+	let pending_transactions: PendingTransactions
+		= Some(Arc::new(Mutex::new(HashMap::new())));
+
+	let filter_pool: Option<FilterPool>
+		= Some(Arc::new(Mutex::new(BTreeMap::new())));
+
+	let frontier_backend = open_frontier_backend(config)?;
+
 	let (grandpa_block_import, grandpa_link) = sc_finality_grandpa::block_import(
-		client.clone(), &(client.clone() as Arc<_>), select_chain.clone(),
+		client.clone(),
+		&(client.clone() as Arc<_>),
+		select_chain.clone(),
+		telemetry.as_ref().map(|x| x.handle()),
 	)?;
 
+	let frontier_block_import = FrontierBlockImport::new(
+		grandpa_block_import.clone(),
+		client.clone(),
+		frontier_backend.clone(),
+	);
+
 	let aura_block_import = sc_consensus_aura::AuraBlockImport::<_, _, _, AuraPair>::new(
-		grandpa_block_import.clone(), client.clone(),
+		frontier_block_import, client.clone(),
 	);
 
-	let import_queue = sc_consensus_aura::import_queue::<_, _, _, AuraPair, _, _>(
-		sc_consensus_aura::slot_duration(&*client)?,
-		aura_block_import.clone(),
-		Some(Box::new(grandpa_block_import.clone())),
-		client.clone(),
-		inherent_data_providers.clone(),
-		&task_manager.spawn_handle(),
-		config.prometheus_registry(),
-		sp_consensus::CanAuthorWithNativeVersion::new(client.executor().clone()),
+	let import_queue = sc_consensus_aura::import_queue::<AuraPair, _, _, _, _, _>(
+		ImportQueueParams {
+			slot_duration: sc_consensus_aura::slot_duration(&*client)?,
+			block_import: aura_block_import.clone(),
+			justification_import: Some(Box::new(grandpa_block_import.clone())),
+			client: client.clone(),
+			inherent_data_providers: inherent_data_providers.clone(),
+			spawner: &task_manager.spawn_essential_handle(),
+			registry: config.prometheus_registry(),
+			can_author_with: sp_consensus::CanAuthorWithNativeVersion::new(client.executor().clone()),
+			check_for_equivocation: Default::default(),
+			telemetry: telemetry.as_ref().map(|x| x.handle()),
+		}
 	)?;
 
 	Ok(sc_service::PartialComponents {
-		client, backend, task_manager, import_queue, keystore_container, select_chain, transaction_pool,
-		inherent_data_providers,
-		other: (aura_block_import, grandpa_link),
+		client, backend, task_manager, import_queue, keystore_container,
+		select_chain, transaction_pool, inherent_data_providers,
+		other: (
+			(aura_block_import, grandpa_link),
+			pending_transactions,
+			filter_pool,
+			frontier_backend,
+			telemetry,
+		)
 	})
 }
 
-fn remote_keystore(_url: &String) -> Result<Arc<LocalKeystore>, &'static str> {
-	// FIXME: here would the concrete keystore be built,
-	//        must return a concrete type (NOT `LocalKeystore`) that
-	//        implements `CryptoStore` and `SyncCryptoStore`
-	Err("Remote Keystore not supported.")
-}
-
 /// Builds a new service for a full client.
-pub fn new_full(mut config: Configuration) -> Result<TaskManager, ServiceError> {
-	let sc_service::PartialComponents {
-		client, backend, mut task_manager, import_queue, mut keystore_container, select_chain, transaction_pool,
-		inherent_data_providers,
-		other: (block_import, grandpa_link),
-	} = new_partial(&config)?;
+pub fn new_full(
+	config: Configuration,
+	cli: &Cli,
+) -> Result<TaskManager, ServiceError> {
+	let enable_dev_signer = cli.run.shared_params.dev;
 
-	if let Some(url) = &config.keystore_remote {
-		match remote_keystore(url) {
-			Ok(k) => keystore_container.set_remote_keystore(k),
-			Err(e) => {
-				return Err(ServiceError::Other(
-					format!("Error hooking up remote keystore for {}: {}", url, e)))
-			}
-		};
-	}
-
-	config.network.extra_sets.push(sc_finality_grandpa::grandpa_peers_set_config());
+	let sc_service::PartialComponents {
+		client, backend, mut task_manager, import_queue, keystore_container,
+		select_chain, transaction_pool, inherent_data_providers,
+		other: (consensus_result, pending_transactions, filter_pool, frontier_backend, mut telemetry),
+	} = new_partial(&config, cli)?;
 
 	let (network, network_status_sinks, system_rpc_tx, network_starter) =
 		sc_service::build_network(sc_service::BuildNetworkParams {
 			config: &config,
-			client: client.clone(),
-			transaction_pool: transaction_pool.clone(),
+			client: Arc::clone(&client),
+			transaction_pool: Arc::clone(&transaction_pool),
 			spawn_handle: task_manager.spawn_handle(),
 			import_queue,
 			on_demand: None,
@@ -129,7 +217,7 @@
 
 	if config.offchain_worker.enabled {
 		sc_service::build_offchain_workers(
-			&config, backend.clone(), task_manager.spawn_handle(), client.clone(), network.clone(),
+			&config, task_manager.spawn_handle(), Arc::clone(&client), network.clone(),
 		);
 	}
 
@@ -139,121 +227,191 @@
 	let name = config.network.node_name.clone();
 	let enable_grandpa = !config.disable_grandpa;
 	let prometheus_registry = config.prometheus_registry().cloned();
+	let is_authority = role.is_authority();
+	let subscription_task_executor = sc_rpc::SubscriptionTaskExecutor::new(task_manager.spawn_handle());
 
 	let rpc_extensions_builder = {
-		let client = client.clone();
-		let pool = transaction_pool.clone();
+		let client = Arc::clone(&client);
+		let pool = Arc::clone(&transaction_pool);
+		let network = network.clone();
+		let pending = pending_transactions.clone();
+		let filter_pool = filter_pool.clone();
+		let frontier_backend = frontier_backend.clone();
 
 		Box::new(move |deny_unsafe, _| {
 			let deps = crate::rpc::FullDeps {
-				client: client.clone(),
-				pool: pool.clone(),
+				client: Arc::clone(&client),
+				pool: Arc::clone(&pool),
 				deny_unsafe,
+				is_authority,
+				enable_dev_signer,
+				network: network.clone(),
+				pending_transactions: pending.clone(),
+				filter_pool: filter_pool.clone(),
+				backend: frontier_backend.clone(),
 			};
-
-			crate::rpc::create_full(deps)
+			crate::rpc::create_full(
+				deps,
+				subscription_task_executor.clone()
+			)
 		})
 	};
 
-	let (_rpc_handlers, telemetry_connection_notifier) = sc_service::spawn_tasks(
-		sc_service::SpawnTasksParams {
-			network: network.clone(),
-			client: client.clone(),
-			keystore: keystore_container.sync_keystore(),
-			task_manager: &mut task_manager,
-			transaction_pool: transaction_pool.clone(),
-			rpc_extensions_builder,
-			on_demand: None,
-			remote_blockchain: None,
-			backend,
-			network_status_sinks,
-			system_rpc_tx,
-			config,
-		},
-	)?;
+	task_manager.spawn_essential_handle().spawn(
+		"frontier-mapping-sync-worker",
+		MappingSyncWorker::new(
+			client.import_notification_stream(),
+			Duration::new(6, 0),
+			Arc::clone(&client),
+			Arc::clone(&backend),
+			frontier_backend.clone(),
+		).for_each(|()| futures::future::ready(()))
+	);
+
+	let _rpc_handlers = sc_service::spawn_tasks(sc_service::SpawnTasksParams {
+		network: network.clone(),
+		client: Arc::clone(&client),
+		keystore: keystore_container.sync_keystore(),
+		task_manager: &mut task_manager,
+		transaction_pool: Arc::clone(&transaction_pool),
+		rpc_extensions_builder: rpc_extensions_builder,
+		on_demand: None,
+		remote_blockchain: None,
+		backend, network_status_sinks, system_rpc_tx, config, telemetry: telemetry.as_mut(),
+	})?;
+
+	// Spawn Frontier EthFilterApi maintenance task.
+	if let Some(filter_pool) = filter_pool {
+		// Each filter is allowed to stay in the pool for 100 blocks.
+		const FILTER_RETAIN_THRESHOLD: u64 = 100;
+		task_manager.spawn_essential_handle().spawn(
+			"frontier-filter-pool",
+			EthTask::filter_pool_task(
+					Arc::clone(&client),
+					filter_pool,
+					FILTER_RETAIN_THRESHOLD,
+			)
+		);
+	}
 
+	// Spawn Frontier pending transactions maintenance task (as essential, otherwise we leak).
+	if let Some(pending_transactions) = pending_transactions {
+		const TRANSACTION_RETAIN_THRESHOLD: u64 = 5;
+		task_manager.spawn_essential_handle().spawn(
+			"frontier-pending-transactions",
+			EthTask::pending_transaction_task(
+				Arc::clone(&client),
+					pending_transactions,
+					TRANSACTION_RETAIN_THRESHOLD,
+				)
+		);
+	}
+
+	let (aura_block_import, grandpa_link) = consensus_result;
+
 	if role.is_authority() {
 		let proposer = sc_basic_authorship::ProposerFactory::new(
 			task_manager.spawn_handle(),
-			client.clone(),
-			transaction_pool,
+			Arc::clone(&client),
+			Arc::clone(&transaction_pool),
 			prometheus_registry.as_ref(),
+			telemetry.as_ref().map(|x| x.handle()),
 		);
 
 		let can_author_with =
 			sp_consensus::CanAuthorWithNativeVersion::new(client.executor().clone());
-
-		let aura = sc_consensus_aura::start_aura::<_, _, _, _, _, AuraPair, _, _, _, _>(
-			sc_consensus_aura::slot_duration(&*client)?,
-			client.clone(),
-			select_chain,
-			block_import,
-			proposer,
-			network.clone(),
-			inherent_data_providers.clone(),
-			force_authoring,
-			backoff_authoring_blocks,
-			keystore_container.sync_keystore(),
-			can_author_with,
+		let aura = sc_consensus_aura::start_aura::<AuraPair, _, _, _, _, _, _, _, _, _>(
+			StartAuraParams {
+				slot_duration: sc_consensus_aura::slot_duration(&*client)?,
+				client: Arc::clone(&client),
+				select_chain,
+				block_import: aura_block_import,
+				proposer_factory: proposer,
+				sync_oracle: network.clone(),
+				inherent_data_providers: inherent_data_providers.clone(),
+				force_authoring,
+				backoff_authoring_blocks,
+				keystore: keystore_container.sync_keystore(),
+				can_author_with,
+				block_proposal_slot_portion: SlotProportion::new(2f32 / 3f32),
+				telemetry: telemetry.as_ref().map(|x| x.handle()),
+			}
 		)?;
 
 		// the AURA authoring task is considered essential, i.e. if it
 		// fails we take down the service with it.
 		task_manager.spawn_essential_handle().spawn_blocking("aura", aura);
-	}
 
-	// if the node isn't actively participating in consensus then it doesn't
-	// need a keystore, regardless of which protocol we use below.
-	let keystore = if role.is_authority() {
-		Some(keystore_container.sync_keystore())
-	} else {
-		None
-	};
+		// if the node isn't actively participating in consensus then it doesn't
+		// need a keystore, regardless of which protocol we use below.
+		let keystore = if role.is_authority() {
+			Some(keystore_container.sync_keystore())
+		} else {
+			None
+		};
 
-	let grandpa_config = sc_finality_grandpa::Config {
-		// FIXME #1578 make this available through chainspec
-		gossip_duration: Duration::from_millis(333),
-		justification_period: 512,
-		name: Some(name),
-		observer_enabled: false,
-		keystore,
-		is_authority: role.is_network_authority(),
-	};
-
-	if enable_grandpa {
-		// start the full GRANDPA voter
-		// NOTE: non-authorities could run the GRANDPA observer protocol, but at
-		// this point the full voter should provide better guarantees of block
-		// and vote data availability than the observer. The observer has not
-		// been tested extensively yet and having most nodes in a network run it
-		// could lead to finality stalls.
-		let grandpa_config = sc_finality_grandpa::GrandpaParams {
-			config: grandpa_config,
-			link: grandpa_link,
-			network,
-			telemetry_on_connect: telemetry_connection_notifier.map(|x| x.on_connect_stream()),
-			voting_rule: sc_finality_grandpa::VotingRulesBuilder::default().build(),
-			prometheus_registry,
-			shared_voter_state: SharedVoterState::empty(),
+		let grandpa_config = sc_finality_grandpa::Config {
+			// FIXME #1578 make this available through chainspec
+			gossip_duration: Duration::from_millis(333),
+			justification_period: 512,
+			name: Some(name),
+			observer_enabled: false,
+			keystore,
+			is_authority: role.is_authority(),
+			telemetry: telemetry.as_ref().map(|x| x.handle()),
 		};
 
-		// the GRANDPA voter task is considered infallible, i.e.
-		// if it fails we take down the service with it.
-		task_manager.spawn_essential_handle().spawn_blocking(
-			"grandpa-voter",
-			sc_finality_grandpa::run_grandpa_voter(grandpa_config)?
-		);
+		if enable_grandpa {
+			// start the full GRANDPA voter
+			// NOTE: non-authorities could run the GRANDPA observer protocol, but at
+			// this point the full voter should provide better guarantees of block
+			// and vote data availability than the observer. The observer has not
+			// been tested extensively yet and having most nodes in a network run it
+			// could lead to finality stalls.
+			let grandpa_config = sc_finality_grandpa::GrandpaParams {
+				config: grandpa_config,
+				link: grandpa_link,
+				network,
+				telemetry: telemetry.as_ref().map(|x| x.handle()),
+				voting_rule: sc_finality_grandpa::VotingRulesBuilder::default().build(),
+				prometheus_registry,
+				shared_voter_state: SharedVoterState::empty(),
+			};
+
+			// the GRANDPA voter task is considered infallible, i.e.
+			// if it fails we take down the service with it.
+			task_manager.spawn_essential_handle().spawn_blocking(
+				"grandpa-voter",
+				sc_finality_grandpa::run_grandpa_voter(grandpa_config)?
+			);
+		}
 	}
 
 	network_starter.start_network();
 	Ok(task_manager)
 }
 /// Builds a new service for a light client.
-pub fn new_light(mut config: Configuration) -> Result<TaskManager, ServiceError> {
+pub fn new_light(config: Configuration) -> Result<TaskManager, ServiceError> {
+	let telemetry = config.telemetry_endpoints.clone()
+		.filter(|x| !x.is_empty())
+		.map(|endpoints| -> Result<_, sc_telemetry::Error> {
+			let worker = TelemetryWorker::new(16)?;
+			let telemetry = worker.handle().new_telemetry(endpoints);
+			Ok((worker, telemetry))
+		})
+		.transpose()?;
+
 	let (client, backend, keystore_container, mut task_manager, on_demand) =
-		sc_service::new_light_parts::<Block, RuntimeApi, Executor>(&config)?;
+		sc_service::new_light_parts::<Block, RuntimeApi, Executor>(
+			&config,
+			telemetry.as_ref().map(|(_, telemetry)| telemetry.handle()),
+		)?;
 
-	config.network.extra_sets.push(sc_finality_grandpa::grandpa_peers_set_config());
+	let mut telemetry = telemetry
+		.map(|(worker, telemetry)| {
+			task_manager.spawn_handle().spawn("telemetry", worker.run());
+			telemetry
+		});
 
 	let select_chain = sc_consensus::LongestChain::new(backend.clone());
 
@@ -269,23 +427,32 @@
 		client.clone(),
 		&(client.clone() as Arc<_>),
 		select_chain.clone(),
+		telemetry.as_ref().map(|x| x.handle()),
+	)?;
+
+	let import_queue = sc_consensus_aura::import_queue::<AuraPair, _, _, _, _, _>(
+		ImportQueueParams {
+			slot_duration: sc_consensus_aura::slot_duration(&*client)?,
+			block_import: grandpa_block_import.clone(),
+			justification_import: Some(Box::new(grandpa_block_import)),
+			client: client.clone(),
+			inherent_data_providers: InherentDataProviders::new(),
+			spawner: &task_manager.spawn_essential_handle(),
+			registry: config.prometheus_registry(),
+			can_author_with: sp_consensus::NeverCanAuthor,
+			check_for_equivocation: Default::default(),
+			telemetry: telemetry.as_ref().map(|x| x.handle()),
+		}
 	)?;
 
-	let aura_block_import = sc_consensus_aura::AuraBlockImport::<_, _, _, AuraPair>::new(
-		grandpa_block_import.clone(),
-		client.clone(),
-	);
+	let light_deps = crate::rpc::LightDeps {
+		remote_blockchain: backend.remote_blockchain(),
+		fetcher: on_demand.clone(),
+		client: client.clone(),
+		pool: transaction_pool.clone(),
+	};
 
-	let import_queue = sc_consensus_aura::import_queue::<_, _, _, AuraPair, _, _>(
-		sc_consensus_aura::slot_duration(&*client)?,
-		aura_block_import,
-		Some(Box::new(grandpa_block_import)),
-		client.clone(),
-		InherentDataProviders::new(),
-		&task_manager.spawn_handle(),
-		config.prometheus_registry(),
-		sp_consensus::NeverCanAuthor,
-	)?;
+	let rpc_extensions = crate::rpc::create_light(light_deps);
 
 	let (network, network_status_sinks, system_rpc_tx, network_starter) =
 		sc_service::build_network(sc_service::BuildNetworkParams {
@@ -300,7 +467,7 @@
 
 	if config.offchain_worker.enabled {
 		sc_service::build_offchain_workers(
-			&config, backend.clone(), task_manager.spawn_handle(), client.clone(), network.clone(),
+			&config, task_manager.spawn_handle(), client.clone(), network.clone(),
 		);
 	}
 
@@ -309,7 +476,7 @@
 		transaction_pool,
 		task_manager: &mut task_manager,
 		on_demand: Some(on_demand),
-		rpc_extensions_builder: Box::new(|_, _| ()),
+		rpc_extensions_builder: Box::new(sc_service::NoopRpcExtensionBuilder(rpc_extensions)),
 		config,
 		client,
 		keystore: keystore_container.sync_keystore(),
@@ -317,6 +484,7 @@
 		network,
 		network_status_sinks,
 		system_rpc_tx,
+		telemetry: telemetry.as_mut(),
 	})?;
 
 	network_starter.start_network();