From 79143f6ec6982db01edd44a252885f9cf812e4ef Mon Sep 17 00:00:00 2001
From: Svyatoslav Nikolsky <svyatonik@gmail.com>
Date: Mon, 13 Sep 2021 14:00:13 +0300
Subject: [PATCH] Add parachain pallets to rialto runtime (#1053)

* use BABE to author blocks on Rialto (previously: Aura)

* removed extra script

* use bp_rialto::Moment

* fix tests

* Babe should control session end

* add parachain pallets to Rialto runtime

* add parachain pallets to rialto runtime + add parachains inherent data provider to node

* remove script again

* fmt

* allow unlicensed crates

* spellcheck

* fix compilation
---
 bridges/bin/rialto/node/Cargo.toml            |  48 +-
 bridges/bin/rialto/node/src/chain_spec.rs     | 101 ++-
 bridges/bin/rialto/node/src/cli.rs            |  15 +
 bridges/bin/rialto/node/src/command.rs        |  75 +-
 bridges/bin/rialto/node/src/main.rs           |   2 +
 bridges/bin/rialto/node/src/overseer.rs       | 245 +++++++
 bridges/bin/rialto/node/src/parachains_db.rs  |  99 +++
 bridges/bin/rialto/node/src/service.rs        | 649 +++++++++++++-----
 bridges/bin/rialto/runtime/Cargo.toml         |  12 +
 bridges/bin/rialto/runtime/src/lib.rs         | 126 +++-
 bridges/bin/rialto/runtime/src/parachains.rs  | 158 +++++
 bridges/primitives/chain-rialto/src/lib.rs    |   2 +-
 .../relays/bin-substrate/src/chains/rialto.rs |   6 +-
 .../bin-substrate/src/cli/encode_call.rs      |   2 +-
 bridges/relays/client-rialto/src/lib.rs       |   4 +-
 15 files changed, 1348 insertions(+), 196 deletions(-)
 create mode 100644 bridges/bin/rialto/node/src/overseer.rs
 create mode 100644 bridges/bin/rialto/node/src/parachains_db.rs
 create mode 100644 bridges/bin/rialto/runtime/src/parachains.rs

diff --git a/bridges/bin/rialto/node/Cargo.toml b/bridges/bin/rialto/node/Cargo.toml
index 99c9eb80d14..833cea604dc 100644
--- a/bridges/bin/rialto/node/Cargo.toml
+++ b/bridges/bin/rialto/node/Cargo.toml
@@ -10,9 +10,13 @@ repository = "https://github.com/paritytech/parity-bridges-common/"
 license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
 
 [dependencies]
+futures = "0.3"
 jsonrpc-core = "15.1.0"
+kvdb = "0.10"
+kvdb-rocksdb = "0.12"
 structopt = "0.3.21"
 serde_json = "1.0.59"
+thiserror = "1.0"
 
 # Bridge dependencies
 
@@ -23,31 +27,73 @@ rialto-runtime = { path = "../runtime" }
 
 # Substrate Dependencies
 
-
 frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "master" }
 frame-benchmarking-cli = { git = "https://github.com/paritytech/substrate", branch = "master" }
+frame-system-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
 node-inspect = { git = "https://github.com/paritytech/substrate", branch = "master" }
 pallet-transaction-payment-rpc = { git = "https://github.com/paritytech/substrate", branch = "master" }
+pallet-transaction-payment-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
+sc-authority-discovery = { git = "https://github.com/paritytech/substrate", branch = "master" }
 sc-basic-authorship = { git = "https://github.com/paritytech/substrate", branch = "master" }
 sc-cli = { git = "https://github.com/paritytech/substrate", branch = "master", features = ["wasmtime"] }
 sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
 sc-consensus = { git = "https://github.com/paritytech/substrate", branch = "master" }
 sc-consensus-babe = { git = "https://github.com/paritytech/substrate", branch = "master" }
+sc-consensus-slots = { git = "https://github.com/paritytech/substrate", branch = "master" }
+sc-consensus-uncles = { git = "https://github.com/paritytech/substrate", branch = "master" }
 sc-executor = { git = "https://github.com/paritytech/substrate", branch = "master" }
 sc-finality-grandpa = { git = "https://github.com/paritytech/substrate", branch = "master" }
 sc-finality-grandpa-rpc = { git = "https://github.com/paritytech/substrate", branch = "master" }
+sc-finality-grandpa-warp-sync = { git = "https://github.com/paritytech/substrate", branch = "master" }
 sc-keystore = { git = "https://github.com/paritytech/substrate", branch = "master" }
+sc-network = { git = "https://github.com/paritytech/substrate", branch = "master" }
 sc-rpc = { git = "https://github.com/paritytech/substrate", branch = "master" }
 sc-service = { git = "https://github.com/paritytech/substrate", branch = "master" }
 sc-telemetry = { git = "https://github.com/paritytech/substrate", branch = "master" }
 sc-transaction-pool = { git = "https://github.com/paritytech/substrate", branch = "master" }
+sp-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
+sp-authority-discovery = { git = "https://github.com/paritytech/substrate", branch = "master" }
+sp-authorship = { git = "https://github.com/paritytech/substrate", branch = "master" }
+sp-blockchain = { git = "https://github.com/paritytech/substrate", branch = "master" }
+sp-block-builder = { git = "https://github.com/paritytech/substrate", branch = "master" }
 sp-consensus = { git = "https://github.com/paritytech/substrate", branch = "master" }
 sp-consensus-babe = { git = "https://github.com/paritytech/substrate", branch = "master" }
 sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
 sp-finality-grandpa = { git = "https://github.com/paritytech/substrate", branch = "master" }
+sp-inherents = { git = "https://github.com/paritytech/substrate", branch = "master" }
+sp-offchain = { git = "https://github.com/paritytech/substrate", branch = "master" }
+sp-session = { git = "https://github.com/paritytech/substrate", branch = "master" }
+sp-transaction-pool = { git = "https://github.com/paritytech/substrate", branch = "master" }
 sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" }
 sp-timestamp = { git = "https://github.com/paritytech/substrate", branch = "master" }
 substrate-frame-rpc-system = { git = "https://github.com/paritytech/substrate", branch = "master" }
+substrate-prometheus-endpoint = { git = "https://github.com/paritytech/substrate", branch = "master" }
+
+# Polkadot (parachain) Dependencies
+
+polkadot-approval-distribution = { git = "https://github.com/paritytech/polkadot", branch = "master" }
+polkadot-availability-bitfield-distribution = { git = "https://github.com/paritytech/polkadot", branch = "master" }
+polkadot-availability-distribution = { git = "https://github.com/paritytech/polkadot", branch = "master" }
+polkadot-availability-recovery = { git = "https://github.com/paritytech/polkadot", branch = "master" }
+polkadot-collator-protocol = { git = "https://github.com/paritytech/polkadot", branch = "master" }
+polkadot-gossip-support = { git = "https://github.com/paritytech/polkadot", branch = "master" }
+polkadot-network-bridge = { git = "https://github.com/paritytech/polkadot", branch = "master" }
+polkadot-node-collation-generation = { git = "https://github.com/paritytech/polkadot", branch = "master" }
+polkadot-node-core-approval-voting = { git = "https://github.com/paritytech/polkadot", branch = "master" }
+polkadot-node-core-av-store = { git = "https://github.com/paritytech/polkadot", branch = "master" }
+polkadot-node-core-backing = { git = "https://github.com/paritytech/polkadot", branch = "master" }
+polkadot-node-core-bitfield-signing = { git = "https://github.com/paritytech/polkadot", branch = "master" }
+polkadot-node-core-candidate-validation = { git = "https://github.com/paritytech/polkadot", branch = "master" }
+polkadot-node-core-chain-api = { git = "https://github.com/paritytech/polkadot", branch = "master" }
+polkadot-node-core-parachains-inherent = { git = "https://github.com/paritytech/polkadot", branch = "master" }
+polkadot-node-core-provisioner = { git = "https://github.com/paritytech/polkadot", branch = "master" }
+polkadot-node-core-pvf = { git = "https://github.com/paritytech/polkadot", branch = "master" }
+polkadot-node-core-runtime-api = { git = "https://github.com/paritytech/polkadot", branch = "master" }
+polkadot-node-subsystem-util = { git = "https://github.com/paritytech/polkadot", branch = "master" }
+polkadot-overseer = { git = "https://github.com/paritytech/polkadot", branch = "master" }
+polkadot-primitives = { git = "https://github.com/paritytech/polkadot", branch = "master" }
+polkadot-runtime-parachains = { git = "https://github.com/paritytech/polkadot", branch = "master" }
+polkadot-statement-distribution = { git = "https://github.com/paritytech/polkadot", branch = "master" }
 
 [build-dependencies]
 substrate-build-script-utils = { git = "https://github.com/paritytech/substrate", branch = "master" }
diff --git a/bridges/bin/rialto/node/src/chain_spec.rs b/bridges/bin/rialto/node/src/chain_spec.rs
index 977ee179461..b77b1d6acf6 100644
--- a/bridges/bin/rialto/node/src/chain_spec.rs
+++ b/bridges/bin/rialto/node/src/chain_spec.rs
@@ -15,11 +15,14 @@
 // along with Parity Bridges Common.  If not, see <http://www.gnu.org/licenses/>.
 
 use bp_rialto::derive_account_from_millau_id;
+use polkadot_primitives::v1::{AssignmentId, ValidatorId};
 use rialto_runtime::{
 	AccountId, BabeConfig, BalancesConfig, BridgeKovanConfig, BridgeMillauMessagesConfig, BridgeRialtoPoaConfig,
-	GenesisConfig, GrandpaConfig, SessionConfig, SessionKeys, Signature, SudoConfig, SystemConfig, WASM_BINARY,
+	GenesisConfig, GrandpaConfig, ParachainsConfigurationConfig, SessionConfig, SessionKeys, Signature, SudoConfig,
+	SystemConfig, WASM_BINARY,
 };
 use serde_json::json;
+use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId;
 use sp_consensus_babe::AuthorityId as BabeId;
 use sp_core::{sr25519, Pair, Public};
 use sp_finality_grandpa::AuthorityId as GrandpaId;
@@ -56,12 +59,24 @@ where
 	AccountPublic::from(get_from_seed::<TPublic>(seed)).into_account()
 }
 
-/// Helper function to generate an authority key for Babe
-pub fn get_authority_keys_from_seed(s: &str) -> (AccountId, BabeId, GrandpaId) {
+/// Helper function to generate authority keys.
+pub fn get_authority_keys_from_seed(
+	s: &str,
+) -> (
+	AccountId,
+	BabeId,
+	GrandpaId,
+	ValidatorId,
+	AssignmentId,
+	AuthorityDiscoveryId,
+) {
 	(
 		get_account_id_from_seed::<sr25519::Public>(s),
 		get_from_seed::<BabeId>(s),
 		get_from_seed::<GrandpaId>(s),
+		get_from_seed::<ValidatorId>(s),
+		get_from_seed::<AssignmentId>(s),
+		get_from_seed::<AuthorityDiscoveryId>(s),
 	)
 }
 
@@ -172,12 +187,31 @@ impl Alternative {
 	}
 }
 
-fn session_keys(babe: BabeId, grandpa: GrandpaId) -> SessionKeys {
-	SessionKeys { babe, grandpa }
+fn session_keys(
+	babe: BabeId,
+	grandpa: GrandpaId,
+	para_validator: ValidatorId,
+	para_assignment: AssignmentId,
+	authority_discovery: AuthorityDiscoveryId,
+) -> SessionKeys {
+	SessionKeys {
+		babe,
+		grandpa,
+		para_validator,
+		para_assignment,
+		authority_discovery,
+	}
 }
 
 fn testnet_genesis(
-	initial_authorities: Vec<(AccountId, BabeId, GrandpaId)>,
+	initial_authorities: Vec<(
+		AccountId,
+		BabeId,
+		GrandpaId,
+		ValidatorId,
+		AssignmentId,
+		AuthorityDiscoveryId,
+	)>,
 	root_key: AccountId,
 	endowed_accounts: Vec<AccountId>,
 	_enable_println: bool,
@@ -203,9 +237,62 @@ fn testnet_genesis(
 		session: SessionConfig {
 			keys: initial_authorities
 				.iter()
-				.map(|x| (x.0.clone(), x.0.clone(), session_keys(x.1.clone(), x.2.clone())))
+				.map(|x| {
+					(
+						x.0.clone(),
+						x.0.clone(),
+						session_keys(x.1.clone(), x.2.clone(), x.3.clone(), x.4.clone(), x.5.clone()),
+					)
+				})
 				.collect::<Vec<_>>(),
 		},
+		authority_discovery: Default::default(),
+		hrmp: Default::default(),
+		// this configuration is exact copy of configuration from Polkadot repo
+		// (see /node/service/src/chain_spec.rs:default_parachains_host_configuration)
+		parachains_configuration: ParachainsConfigurationConfig {
+			config: polkadot_runtime_parachains::configuration::HostConfiguration {
+				validation_upgrade_frequency: 1u32,
+				validation_upgrade_delay: 1,
+				code_retention_period: 1200,
+				max_code_size: polkadot_primitives::v1::MAX_CODE_SIZE,
+				max_pov_size: polkadot_primitives::v1::MAX_POV_SIZE,
+				max_head_data_size: 32 * 1024,
+				group_rotation_frequency: 20,
+				chain_availability_period: 4,
+				thread_availability_period: 4,
+				max_upward_queue_count: 8,
+				max_upward_queue_size: 1024 * 1024,
+				max_downward_message_size: 1024,
+				// this is approximatelly 4ms.
+				//
+				// Same as `4 * frame_support::weights::WEIGHT_PER_MILLIS`. We don't bother with
+				// an import since that's a made up number and should be replaced with a constant
+				// obtained by benchmarking anyway.
+				ump_service_total_weight: 4 * 1_000_000_000,
+				max_upward_message_size: 1024 * 1024,
+				max_upward_message_num_per_candidate: 5,
+				hrmp_open_request_ttl: 5,
+				hrmp_sender_deposit: 0,
+				hrmp_recipient_deposit: 0,
+				hrmp_channel_max_capacity: 8,
+				hrmp_channel_max_total_size: 8 * 1024,
+				hrmp_max_parachain_inbound_channels: 4,
+				hrmp_max_parathread_inbound_channels: 4,
+				hrmp_channel_max_message_size: 1024 * 1024,
+				hrmp_max_parachain_outbound_channels: 4,
+				hrmp_max_parathread_outbound_channels: 4,
+				hrmp_max_message_num_per_candidate: 5,
+				dispute_period: 6,
+				no_show_slots: 2,
+				n_delay_tranches: 25,
+				needed_approvals: 2,
+				relay_vrf_modulo_samples: 2,
+				zeroth_delay_tranche_width: 0,
+				..Default::default()
+			},
+		},
+		paras: Default::default(),
 		bridge_millau_messages: BridgeMillauMessagesConfig {
 			owner: Some(get_account_id_from_seed::<sr25519::Public>("MillauMessagesOwner")),
 			..Default::default()
diff --git a/bridges/bin/rialto/node/src/cli.rs b/bridges/bin/rialto/node/src/cli.rs
index 086def633c5..3f85a69a713 100644
--- a/bridges/bin/rialto/node/src/cli.rs
+++ b/bridges/bin/rialto/node/src/cli.rs
@@ -67,4 +67,19 @@ pub enum Subcommand {
 
 	/// Benchmark runtime pallets.
 	Benchmark(frame_benchmarking_cli::BenchmarkCmd),
+
+	/// FOR INTERNAL USE: analog of the "prepare-worker" command of the polkadot binary.
+	#[structopt(name = "prepare-worker", setting = structopt::clap::AppSettings::Hidden)]
+	PvfPrepareWorker(ValidationWorkerCommand),
+
+	/// FOR INTERNAL USE: analog of the "execute-worker" command of the polkadot binary.
+	#[structopt(name = "execute-worker", setting = structopt::clap::AppSettings::Hidden)]
+	PvfExecuteWorker(ValidationWorkerCommand),
+}
+
+/// Validation worker command.
+#[derive(Debug, StructOpt)]
+pub struct ValidationWorkerCommand {
+	/// The path to the validation host's socket.
+	pub socket_path: String,
 }
diff --git a/bridges/bin/rialto/node/src/command.rs b/bridges/bin/rialto/node/src/command.rs
index 226a21d841d..4fe40251e63 100644
--- a/bridges/bin/rialto/node/src/command.rs
+++ b/bridges/bin/rialto/node/src/command.rs
@@ -15,7 +15,6 @@
 // along with Parity Bridges Common.  If not, see <http://www.gnu.org/licenses/>.
 
 use crate::cli::{Cli, Subcommand};
-use crate::service;
 use crate::service::new_partial;
 use rialto_runtime::{Block, RuntimeApi};
 use sc_cli::{ChainSpec, Role, RuntimeVersion, SubstrateCli};
@@ -78,7 +77,7 @@ pub fn run() -> sc_cli::Result<()> {
 			if cfg!(feature = "runtime-benchmarks") {
 				let runner = cli.create_runner(cmd)?;
 
-				runner.sync_run(|config| cmd.run::<Block, service::Executor>(config))
+				runner.sync_run(|config| cmd.run::<Block, crate::service::Executor>(config))
 			} else {
 				println!(
 					"Benchmarking wasn't enabled when building the node. \
@@ -97,43 +96,43 @@ pub fn run() -> sc_cli::Result<()> {
 		}
 		Some(Subcommand::CheckBlock(cmd)) => {
 			let runner = cli.create_runner(cmd)?;
-			runner.async_run(|config| {
+			runner.async_run(|mut config| {
 				let PartialComponents {
 					client,
 					task_manager,
 					import_queue,
 					..
-				} = new_partial(&config)?;
+				} = new_partial(&mut config).map_err(service_error)?;
 				Ok((cmd.run(client, import_queue), task_manager))
 			})
 		}
 		Some(Subcommand::ExportBlocks(cmd)) => {
 			let runner = cli.create_runner(cmd)?;
-			runner.async_run(|config| {
+			runner.async_run(|mut config| {
 				let PartialComponents {
 					client, task_manager, ..
-				} = new_partial(&config)?;
+				} = new_partial(&mut config).map_err(service_error)?;
 				Ok((cmd.run(client, config.database), task_manager))
 			})
 		}
 		Some(Subcommand::ExportState(cmd)) => {
 			let runner = cli.create_runner(cmd)?;
-			runner.async_run(|config| {
+			runner.async_run(|mut config| {
 				let PartialComponents {
 					client, task_manager, ..
-				} = new_partial(&config)?;
+				} = new_partial(&mut config).map_err(service_error)?;
 				Ok((cmd.run(client, config.chain_spec), task_manager))
 			})
 		}
 		Some(Subcommand::ImportBlocks(cmd)) => {
 			let runner = cli.create_runner(cmd)?;
-			runner.async_run(|config| {
+			runner.async_run(|mut config| {
 				let PartialComponents {
 					client,
 					task_manager,
 					import_queue,
 					..
-				} = new_partial(&config)?;
+				} = new_partial(&mut config).map_err(service_error)?;
 				Ok((cmd.run(client, import_queue), task_manager))
 			})
 		}
@@ -143,32 +142,62 @@ pub fn run() -> sc_cli::Result<()> {
 		}
 		Some(Subcommand::Revert(cmd)) => {
 			let runner = cli.create_runner(cmd)?;
-			runner.async_run(|config| {
+			runner.async_run(|mut config| {
 				let PartialComponents {
 					client,
 					task_manager,
 					backend,
 					..
-				} = new_partial(&config)?;
+				} = new_partial(&mut config).map_err(service_error)?;
 				Ok((cmd.run(client, backend), task_manager))
 			})
 		}
 		Some(Subcommand::Inspect(cmd)) => {
 			let runner = cli.create_runner(cmd)?;
-			runner.sync_run(|config| cmd.run::<Block, RuntimeApi, service::Executor>(config))
+			runner.sync_run(|config| cmd.run::<Block, RuntimeApi, crate::service::Executor>(config))
+		}
+		Some(Subcommand::PvfPrepareWorker(cmd)) => {
+			let mut builder = sc_cli::LoggerBuilder::new("");
+			builder.with_colors(false);
+			let _ = builder.init();
+
+			polkadot_node_core_pvf::prepare_worker_entrypoint(&cmd.socket_path);
+			Ok(())
+		}
+		Some(crate::cli::Subcommand::PvfExecuteWorker(cmd)) => {
+			let mut builder = sc_cli::LoggerBuilder::new("");
+			builder.with_colors(false);
+			let _ = builder.init();
+
+			polkadot_node_core_pvf::execute_worker_entrypoint(&cmd.socket_path);
+			Ok(())
 		}
 		None => {
 			let runner = cli.create_runner(&cli.run)?;
-			runner
-				.run_node_until_exit(|config| async move {
-					match config.role {
-						Role::Light => Err(sc_service::Error::Other(
-							"Light client is not supported by this node".into(),
-						)),
-						_ => service::new_full(config),
-					}
-				})
-				.map_err(sc_cli::Error::Service)
+
+			// some parameters that are used by polkadot nodes, but that are not used by our binary
+			// let jaeger_agent = None;
+			// let grandpa_pause = None;
+			// let no_beefy = true;
+			// let telemetry_worker_handler = None;
+			// let is_collator = crate::service::IsCollator::No;
+			let overseer_gen = crate::overseer::RealOverseerGen;
+			runner.run_node_until_exit(|config| async move {
+				match config.role {
+					Role::Light => Err(sc_cli::Error::Service(sc_service::Error::Other(
+						"Light client is not supported by this node".into(),
+					))),
+					_ => crate::service::build_full(config, overseer_gen)
+						.map(|full| full.task_manager)
+						.map_err(service_error),
+				}
+			})
 		}
 	}
 }
+
+// We don't want to change 'service.rs' too much to ease future updates => it'll keep using
+// its own error enum like original polkadot service does.
+fn service_error(err: crate::service::Error) -> sc_cli::Error {
+	sc_cli::Error::Application(Box::new(err))
+}
diff --git a/bridges/bin/rialto/node/src/main.rs b/bridges/bin/rialto/node/src/main.rs
index f319d1437a9..824814224e5 100644
--- a/bridges/bin/rialto/node/src/main.rs
+++ b/bridges/bin/rialto/node/src/main.rs
@@ -23,6 +23,8 @@ mod chain_spec;
 mod service;
 mod cli;
 mod command;
+mod overseer;
+mod parachains_db;
 
 /// Run the Rialto Node
 fn main() -> sc_cli::Result<()> {
diff --git a/bridges/bin/rialto/node/src/overseer.rs b/bridges/bin/rialto/node/src/overseer.rs
new file mode 100644
index 00000000000..f7aaef4b5d4
--- /dev/null
+++ b/bridges/bin/rialto/node/src/overseer.rs
@@ -0,0 +1,245 @@
+// Copyright 2019-2021 Parity Technologies (UK) Ltd.
+// This file is part of Parity Bridges Common.
+
+// Parity Bridges Common is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Parity Bridges Common is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Parity Bridges Common.  If not, see <http://www.gnu.org/licenses/>.
+
+//! This is almost 1:1 copy of `node/service/src/overseer.rs` file from Polkadot repository.
+//! The only exception is that we don't support db upgrades => no `upgrade.rs` module.
+
+// this warning comes from `polkadot_overseer::AllSubsystems` type
+#![allow(clippy::type_complexity)]
+
+use crate::service::Error;
+
+use polkadot_network_bridge::RequestMultiplexer;
+use polkadot_node_core_approval_voting::Config as ApprovalVotingConfig;
+use polkadot_node_core_av_store::Config as AvailabilityConfig;
+use polkadot_node_core_candidate_validation::Config as CandidateValidationConfig;
+use polkadot_overseer::{AllSubsystems, BlockInfo, Overseer, OverseerHandler};
+use polkadot_primitives::v1::{Block, Hash, ParachainHost};
+use sc_authority_discovery::Service as AuthorityDiscoveryService;
+use sc_client_api::AuxStore;
+use sc_keystore::LocalKeystore;
+use sp_api::ProvideRuntimeApi;
+use sp_authority_discovery::AuthorityDiscoveryApi;
+use sp_blockchain::HeaderBackend;
+use sp_consensus_babe::BabeApi;
+use sp_core::traits::SpawnNamed;
+use std::sync::Arc;
+use substrate_prometheus_endpoint::Registry;
+
+pub use polkadot_approval_distribution::ApprovalDistribution as ApprovalDistributionSubsystem;
+pub use polkadot_availability_bitfield_distribution::BitfieldDistribution as BitfieldDistributionSubsystem;
+pub use polkadot_availability_distribution::AvailabilityDistributionSubsystem;
+pub use polkadot_availability_recovery::AvailabilityRecoverySubsystem;
+pub use polkadot_collator_protocol::{CollatorProtocolSubsystem, ProtocolSide};
+pub use polkadot_gossip_support::GossipSupport as GossipSupportSubsystem;
+pub use polkadot_network_bridge::NetworkBridge as NetworkBridgeSubsystem;
+pub use polkadot_node_collation_generation::CollationGenerationSubsystem;
+pub use polkadot_node_core_approval_voting::ApprovalVotingSubsystem;
+pub use polkadot_node_core_av_store::AvailabilityStoreSubsystem;
+pub use polkadot_node_core_backing::CandidateBackingSubsystem;
+pub use polkadot_node_core_bitfield_signing::BitfieldSigningSubsystem;
+pub use polkadot_node_core_candidate_validation::CandidateValidationSubsystem;
+pub use polkadot_node_core_chain_api::ChainApiSubsystem;
+pub use polkadot_node_core_provisioner::ProvisioningSubsystem as ProvisionerSubsystem;
+pub use polkadot_node_core_runtime_api::RuntimeApiSubsystem;
+pub use polkadot_statement_distribution::StatementDistribution as StatementDistributionSubsystem;
+
+/// Arguments passed for overseer construction.
+pub struct OverseerGenArgs<'a, Spawner, RuntimeClient>
+where
+	RuntimeClient: 'static + ProvideRuntimeApi<Block> + HeaderBackend<Block> + AuxStore,
+	RuntimeClient::Api: ParachainHost<Block> + BabeApi<Block> + AuthorityDiscoveryApi<Block>,
+	Spawner: 'static + SpawnNamed + Clone + Unpin,
+{
+	/// Set of initial relay chain leaves to track.
+	pub leaves: Vec<BlockInfo>,
+	/// The keystore to use for i.e. validator keys.
+	pub keystore: Arc<LocalKeystore>,
+	/// Runtime client generic, providing the `ProvieRuntimeApi` trait besides others.
+	pub runtime_client: Arc<RuntimeClient>,
+	/// The underlying key value store for the parachains.
+	pub parachains_db: Arc<dyn kvdb::KeyValueDB>,
+	/// Configuration for the availability store subsystem.
+	pub availability_config: AvailabilityConfig,
+	/// Configuration for the approval voting subsystem.
+	pub approval_voting_config: ApprovalVotingConfig,
+	/// Underlying network service implementation.
+	pub network_service: Arc<sc_network::NetworkService<Block, Hash>>,
+	/// Underlying authority discovery service.
+	pub authority_discovery_service: AuthorityDiscoveryService,
+	/// A multiplexer to arbitrate incoming `IncomingRequest`s from the network.
+	pub request_multiplexer: RequestMultiplexer,
+	/// Prometheus registry, commonly used for production systems, less so for test.
+	pub registry: Option<&'a Registry>,
+	/// Task spawner to be used throughout the overseer and the APIs it provides.
+	pub spawner: Spawner,
+	/// Configuration for the candidate validation subsystem.
+	pub candidate_validation_config: CandidateValidationConfig,
+}
+
+/// Create a default, unaltered set of subsystems.
+///
+/// A convenience for usage with malus, to avoid
+/// repetitive code across multiple behavior strain implementations.
+pub fn create_default_subsystems<Spawner, RuntimeClient>(
+	OverseerGenArgs {
+		keystore,
+		runtime_client,
+		parachains_db,
+		availability_config,
+		approval_voting_config,
+		network_service,
+		authority_discovery_service,
+		request_multiplexer,
+		registry,
+		spawner,
+		candidate_validation_config,
+		..
+	}: OverseerGenArgs<Spawner, RuntimeClient>,
+) -> Result<
+	AllSubsystems<
+		CandidateValidationSubsystem,
+		CandidateBackingSubsystem<Spawner>,
+		StatementDistributionSubsystem,
+		AvailabilityDistributionSubsystem,
+		AvailabilityRecoverySubsystem,
+		BitfieldSigningSubsystem<Spawner>,
+		BitfieldDistributionSubsystem,
+		ProvisionerSubsystem<Spawner>,
+		RuntimeApiSubsystem<RuntimeClient>,
+		AvailabilityStoreSubsystem,
+		NetworkBridgeSubsystem<Arc<sc_network::NetworkService<Block, Hash>>, AuthorityDiscoveryService>,
+		ChainApiSubsystem<RuntimeClient>,
+		CollationGenerationSubsystem,
+		CollatorProtocolSubsystem,
+		ApprovalDistributionSubsystem,
+		ApprovalVotingSubsystem,
+		GossipSupportSubsystem,
+	>,
+	Error,
+>
+where
+	RuntimeClient: 'static + ProvideRuntimeApi<Block> + HeaderBackend<Block> + AuxStore,
+	RuntimeClient::Api: ParachainHost<Block> + BabeApi<Block> + AuthorityDiscoveryApi<Block>,
+	Spawner: 'static + SpawnNamed + Clone + Unpin,
+{
+	use polkadot_node_subsystem_util::metrics::Metrics;
+
+	let all_subsystems = AllSubsystems {
+		availability_distribution: AvailabilityDistributionSubsystem::new(
+			keystore.clone(),
+			Metrics::register(registry)?,
+		),
+		availability_recovery: AvailabilityRecoverySubsystem::with_chunks_only(),
+		availability_store: AvailabilityStoreSubsystem::new(
+			parachains_db.clone(),
+			availability_config,
+			Metrics::register(registry)?,
+		),
+		bitfield_distribution: BitfieldDistributionSubsystem::new(Metrics::register(registry)?),
+		bitfield_signing: BitfieldSigningSubsystem::new(
+			spawner.clone(),
+			keystore.clone(),
+			Metrics::register(registry)?,
+		),
+		candidate_backing: CandidateBackingSubsystem::new(
+			spawner.clone(),
+			keystore.clone(),
+			Metrics::register(registry)?,
+		),
+		candidate_validation: CandidateValidationSubsystem::with_config(
+			candidate_validation_config,
+			Metrics::register(registry)?,
+		),
+		chain_api: ChainApiSubsystem::new(runtime_client.clone(), Metrics::register(registry)?),
+		collation_generation: CollationGenerationSubsystem::new(Metrics::register(registry)?),
+		collator_protocol: {
+			let side = ProtocolSide::Validator {
+				keystore: keystore.clone(),
+				eviction_policy: Default::default(),
+				metrics: Metrics::register(registry)?,
+			};
+			CollatorProtocolSubsystem::new(side)
+		},
+		network_bridge: NetworkBridgeSubsystem::new(
+			network_service.clone(),
+			authority_discovery_service,
+			request_multiplexer,
+			Box::new(network_service.clone()),
+			Metrics::register(registry)?,
+		),
+		provisioner: ProvisionerSubsystem::new(spawner.clone(), (), Metrics::register(registry)?),
+		runtime_api: RuntimeApiSubsystem::new(runtime_client, Metrics::register(registry)?, spawner),
+		statement_distribution: StatementDistributionSubsystem::new(keystore.clone(), Metrics::register(registry)?),
+		approval_distribution: ApprovalDistributionSubsystem::new(Metrics::register(registry)?),
+		approval_voting: ApprovalVotingSubsystem::with_config(
+			approval_voting_config,
+			parachains_db,
+			keystore.clone(),
+			Box::new(network_service),
+			Metrics::register(registry)?,
+		),
+		gossip_support: GossipSupportSubsystem::new(keystore),
+	};
+	Ok(all_subsystems)
+}
+
+/// Trait for the `fn` generating the overseer.
+///
+/// Default behavior is to create an unmodified overseer, as `RealOverseerGen`
+/// would do.
+pub trait OverseerGen {
+	/// Overwrite the full generation of the overseer, including the subsystems.
+	fn generate<Spawner, RuntimeClient>(
+		&self,
+		args: OverseerGenArgs<Spawner, RuntimeClient>,
+	) -> Result<(Overseer<Spawner, Arc<RuntimeClient>>, OverseerHandler), Error>
+	where
+		RuntimeClient: 'static + ProvideRuntimeApi<Block> + HeaderBackend<Block> + AuxStore,
+		RuntimeClient::Api: ParachainHost<Block> + BabeApi<Block> + AuthorityDiscoveryApi<Block>,
+		Spawner: 'static + SpawnNamed + Clone + Unpin,
+	{
+		let gen = RealOverseerGen;
+		RealOverseerGen::generate::<Spawner, RuntimeClient>(&gen, args)
+	}
+	// It would be nice to make `create_subsystems` part of this trait,
+	// but the amount of generic arguments that would be required as
+	// as consequence make this rather annoying to implement and use.
+}
+
+/// The regular set of subsystems.
+pub struct RealOverseerGen;
+
+impl OverseerGen for RealOverseerGen {
+	fn generate<Spawner, RuntimeClient>(
+		&self,
+		args: OverseerGenArgs<Spawner, RuntimeClient>,
+	) -> Result<(Overseer<Spawner, Arc<RuntimeClient>>, OverseerHandler), Error>
+	where
+		RuntimeClient: 'static + ProvideRuntimeApi<Block> + HeaderBackend<Block> + AuxStore,
+		RuntimeClient::Api: ParachainHost<Block> + BabeApi<Block> + AuthorityDiscoveryApi<Block>,
+		Spawner: 'static + SpawnNamed + Clone + Unpin,
+	{
+		let spawner = args.spawner.clone();
+		let leaves = args.leaves.clone();
+		let runtime_client = args.runtime_client.clone();
+		let registry = args.registry;
+
+		let all_subsystems = create_default_subsystems::<Spawner, RuntimeClient>(args)?;
+
+		Overseer::new(leaves, all_subsystems, registry, runtime_client, spawner).map_err(|e| e.into())
+	}
+}
diff --git a/bridges/bin/rialto/node/src/parachains_db.rs b/bridges/bin/rialto/node/src/parachains_db.rs
new file mode 100644
index 00000000000..aa70d45cd73
--- /dev/null
+++ b/bridges/bin/rialto/node/src/parachains_db.rs
@@ -0,0 +1,99 @@
+// Copyright 2019-2021 Parity Technologies (UK) Ltd.
+// This file is part of Parity Bridges Common.
+
+// Parity Bridges Common is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Parity Bridges Common is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Parity Bridges Common.  If not, see <http://www.gnu.org/licenses/>.
+
+//! This is almost 1:1 copy of `node/service/parachains_db/mod.rs` file from Polkadot repository.
+//! The only exception is that we don't support db upgrades => no `upgrade.rs` module.
+
+use {kvdb::KeyValueDB, std::io, std::path::PathBuf, std::sync::Arc};
+
+mod columns {
+	pub const NUM_COLUMNS: u32 = 3;
+
+	pub const COL_AVAILABILITY_DATA: u32 = 0;
+	pub const COL_AVAILABILITY_META: u32 = 1;
+	pub const COL_APPROVAL_DATA: u32 = 2;
+}
+
+/// Columns used by different subsystems.
+#[derive(Debug, Clone)]
+pub struct ColumnsConfig {
+	/// The column used by the av-store for data.
+	pub col_availability_data: u32,
+	/// The column used by the av-store for meta information.
+	pub col_availability_meta: u32,
+	/// The column used by approval voting for data.
+	pub col_approval_data: u32,
+}
+
+/// The real columns used by the parachains DB.
+pub const REAL_COLUMNS: ColumnsConfig = ColumnsConfig {
+	col_availability_data: columns::COL_AVAILABILITY_DATA,
+	col_availability_meta: columns::COL_AVAILABILITY_META,
+	col_approval_data: columns::COL_APPROVAL_DATA,
+};
+
+/// The cache size for each column, in megabytes.
+#[derive(Debug, Clone)]
+pub struct CacheSizes {
+	/// Cache used by availability data.
+	pub availability_data: usize,
+	/// Cache used by availability meta.
+	pub availability_meta: usize,
+	/// Cache used by approval data.
+	pub approval_data: usize,
+}
+
+impl Default for CacheSizes {
+	fn default() -> Self {
+		CacheSizes {
+			availability_data: 25,
+			availability_meta: 1,
+			approval_data: 5,
+		}
+	}
+}
+
+fn other_io_error(err: String) -> io::Error {
+	io::Error::new(io::ErrorKind::Other, err)
+}
+
+/// Open the database on disk, creating it if it doesn't exist.
+pub fn open_creating(root: PathBuf, cache_sizes: CacheSizes) -> io::Result<Arc<dyn KeyValueDB>> {
+	use kvdb_rocksdb::{Database, DatabaseConfig};
+
+	let path = root.join("parachains").join("db");
+
+	let mut db_config = DatabaseConfig::with_columns(columns::NUM_COLUMNS);
+
+	let _ = db_config
+		.memory_budget
+		.insert(columns::COL_AVAILABILITY_DATA, cache_sizes.availability_data);
+	let _ = db_config
+		.memory_budget
+		.insert(columns::COL_AVAILABILITY_META, cache_sizes.availability_meta);
+	let _ = db_config
+		.memory_budget
+		.insert(columns::COL_APPROVAL_DATA, cache_sizes.approval_data);
+
+	let path_str = path
+		.to_str()
+		.ok_or_else(|| other_io_error(format!("Bad database path: {:?}", path)))?;
+
+	std::fs::create_dir_all(&path_str)?;
+	let db = Database::open(&db_config, path_str)?;
+
+	Ok(Arc::new(db))
+}
diff --git a/bridges/bin/rialto/node/src/service.rs b/bridges/bin/rialto/node/src/service.rs
index 77d63a68dd9..71ab93d8589 100644
--- a/bridges/bin/rialto/node/src/service.rs
+++ b/bridges/bin/rialto/node/src/service.rs
@@ -14,30 +14,36 @@
 // You should have received a copy of the GNU General Public License
 // along with Parity Bridges Common.  If not, see <http://www.gnu.org/licenses/>.
 
-//! Service and ServiceFactory implementation. Specialized wrapper over substrate service.
-
-// =====================================================================================
-// =====================================================================================
-// =====================================================================================
-// There's no easy way to update this file. Currently it is a merge of two files:
-// 1) node-template/src/service.rs from Substrate repo;
-// 2) node/service/src/lib.rs from Polkadot repo.
-//
-// The main things to notice when updating are:
-// 1) we are using Babe for authoring blocks;
-// 2) support for light client is dropped as we are not using it now.
-// ===========================================s==========================================
-// =====================================================================================
-// =====================================================================================
-
+//! Rialto chain node service.
+//!
+//! The code is mostly copy of `service/src/lib.rs` file from Polkadot repository
+//! without optional functions.
+
+// this warning comes from Error enum (sc_cli::Error in particular) && it isn't easy to use box there
+#![allow(clippy::large_enum_variant)]
+// this warning comes from `sc_service::PartialComponents` type
+#![allow(clippy::type_complexity)]
+
+use crate::overseer::{OverseerGen, OverseerGenArgs};
+
+use polkadot_network_bridge::RequestMultiplexer;
+use polkadot_node_core_approval_voting::Config as ApprovalVotingConfig;
+use polkadot_node_core_av_store::Config as AvailabilityConfig;
+use polkadot_node_core_candidate_validation::Config as CandidateValidationConfig;
+use polkadot_overseer::{BlockInfo, OverseerHandler};
+use polkadot_primitives::v1::BlockId;
 use rialto_runtime::{self, opaque::Block, RuntimeApi};
 use sc_client_api::ExecutorProvider;
-use sc_consensus_babe::SlotProportion;
-use sc_executor::native_executor_instance;
-use sc_keystore::LocalKeystore;
-use sc_service::{error::Error as ServiceError, Configuration, TaskManager};
+use sc_executor::{native_executor_instance, NativeExecutionDispatch};
+use sc_finality_grandpa::FinalityProofProvider as GrandpaFinalityProofProvider;
+use sc_service::{config::PrometheusConfig, Configuration, TaskManager};
 use sc_telemetry::{Telemetry, TelemetryWorker};
+use sp_api::{ConstructRuntimeApi, HeaderT};
+use sp_blockchain::HeaderBackend;
+use sp_consensus::SelectChain;
+use sp_runtime::traits::{BlakeTwo256, Block as BlockT};
 use std::{sync::Arc, time::Duration};
+use substrate_prometheus_endpoint::Registry;
 
 pub use sc_executor::NativeExecutor;
 
@@ -49,34 +55,126 @@ native_executor_instance!(
 	frame_benchmarking::benchmarking::HostFunctions,
 );
 
+#[derive(thiserror::Error, Debug)]
+pub enum Error {
+	#[error(transparent)]
+	Io(#[from] std::io::Error),
+
+	#[error(transparent)]
+	Cli(#[from] sc_cli::Error),
+
+	#[error(transparent)]
+	Blockchain(#[from] sp_blockchain::Error),
+
+	#[error(transparent)]
+	Consensus(#[from] sp_consensus::Error),
+
+	#[error(transparent)]
+	Service(#[from] sc_service::Error),
+
+	#[error(transparent)]
+	Telemetry(#[from] sc_telemetry::Error),
+
+	#[error("Failed to create an overseer")]
+	Overseer(#[from] polkadot_overseer::SubsystemError),
+
+	#[error(transparent)]
+	Prometheus(#[from] substrate_prometheus_endpoint::PrometheusError),
+
+	#[error("Authorities require the real overseer implementation")]
+	AuthoritiesRequireRealOverseer,
+
+	#[error("Creating a custom database is required for validators")]
+	DatabasePathRequired,
+}
+
 type FullClient = sc_service::TFullClient<Block, RuntimeApi, Executor>;
 type FullBackend = sc_service::TFullBackend<Block>;
 type FullSelectChain = sc_consensus::LongestChain<FullBackend, Block>;
 type FullGrandpaBlockImport = sc_finality_grandpa::GrandpaBlockImport<FullBackend, Block, FullClient, FullSelectChain>;
+type FullTransactionPool = sc_transaction_pool::FullPool<Block, FullClient>;
+type FullBabeBlockImport = sc_consensus_babe::BabeBlockImport<Block, FullClient, FullGrandpaBlockImport>;
+type FullBabeLink = sc_consensus_babe::BabeLink<Block>;
+type FullGrandpaLink = sc_finality_grandpa::LinkHalf<Block, FullClient, FullSelectChain>;
+
+/// A set of APIs that polkadot-like runtimes must implement.
+///
+/// This is the copy of `polkadot_service::RuntimeApiCollection` with some APIs removed
+/// (right now - MMR and BEEFY).
+pub trait RequiredApiCollection:
+	sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block>
+	+ sp_api::ApiExt<Block>
+	+ sp_consensus_babe::BabeApi<Block>
+	+ sp_finality_grandpa::GrandpaApi<Block>
+	+ polkadot_primitives::v1::ParachainHost<Block>
+	+ sp_block_builder::BlockBuilder<Block>
+	+ frame_system_rpc_runtime_api::AccountNonceApi<Block, bp_rialto::AccountId, rialto_runtime::Index>
+	+ pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<Block, bp_rialto::Balance>
+	+ sp_api::Metadata<Block>
+	+ sp_offchain::OffchainWorkerApi<Block>
+	+ sp_session::SessionKeys<Block>
+	+ sp_authority_discovery::AuthorityDiscoveryApi<Block>
+where
+	<Self as sp_api::ApiExt<Block>>::StateBackend: sp_api::StateBackend<BlakeTwo256>,
+{
+}
+
+impl<Api> RequiredApiCollection for Api
+where
+	Api: sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block>
+		+ sp_api::ApiExt<Block>
+		+ sp_consensus_babe::BabeApi<Block>
+		+ sp_finality_grandpa::GrandpaApi<Block>
+		+ polkadot_primitives::v1::ParachainHost<Block>
+		+ sp_block_builder::BlockBuilder<Block>
+		+ frame_system_rpc_runtime_api::AccountNonceApi<Block, bp_rialto::AccountId, rialto_runtime::Index>
+		+ pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<Block, bp_rialto::Balance>
+		+ sp_api::Metadata<Block>
+		+ sp_offchain::OffchainWorkerApi<Block>
+		+ sp_session::SessionKeys<Block>
+		+ sp_authority_discovery::AuthorityDiscoveryApi<Block>,
+	<Self as sp_api::ApiExt<Block>>::StateBackend: sp_api::StateBackend<BlakeTwo256>,
+{
+}
+
+// If we're using prometheus, use a registry with a prefix of `polkadot`.
+fn set_prometheus_registry(config: &mut Configuration) -> Result<(), Error> {
+	if let Some(PrometheusConfig { registry, .. }) = config.prometheus_config.as_mut() {
+		*registry = Registry::new_custom(Some("polkadot".into()), None)?;
+	}
+
+	Ok(())
+}
 
-#[allow(clippy::type_complexity)]
 pub fn new_partial(
-	config: &Configuration,
+	config: &mut Configuration,
 ) -> Result<
 	sc_service::PartialComponents<
 		FullClient,
 		FullBackend,
 		FullSelectChain,
 		sp_consensus::DefaultImportQueue<Block, FullClient>,
-		sc_transaction_pool::FullPool<Block, FullClient>,
+		FullTransactionPool,
 		(
-			FullGrandpaBlockImport,
-			sc_finality_grandpa::LinkHalf<Block, FullClient, FullSelectChain>,
-			sc_consensus_babe::BabeBlockImport<Block, FullClient, FullGrandpaBlockImport>,
-			sc_consensus_babe::BabeLink<Block>,
+			impl Fn(
+				sc_rpc::DenyUnsafe,
+				sc_rpc::SubscriptionTaskExecutor,
+			) -> jsonrpc_core::IoHandler<sc_service::RpcMetadata>,
+			(FullBabeBlockImport, FullGrandpaLink, FullBabeLink),
+			sc_finality_grandpa::SharedVoterState,
+			std::time::Duration,
 			Option<Telemetry>,
 		),
 	>,
-	ServiceError,
-> {
-	if config.keystore_remote.is_some() {
-		return Err(ServiceError::Other("Remote Keystores are not supported.".to_string()));
-	}
+	Error,
+>
+where
+	RuntimeApi: ConstructRuntimeApi<Block, FullClient> + Send + Sync + 'static,
+	<RuntimeApi as ConstructRuntimeApi<Block, FullClient>>::RuntimeApi:
+		RequiredApiCollection<StateBackend = sc_client_api::StateBackendFor<FullBackend, Block>>,
+	Executor: NativeExecutionDispatch + 'static,
+{
+	set_prometheus_registry(config)?;
 
 	let telemetry = config
 		.telemetry_endpoints
@@ -110,24 +208,23 @@ pub fn new_partial(
 		client.clone(),
 	);
 
-	let (grandpa_block_import, grandpa_link) = sc_finality_grandpa::block_import(
+	let (grandpa_block_import, grandpa_link) = sc_finality_grandpa::block_import_with_authority_set_hard_forks(
 		client.clone(),
 		&(client.clone() as Arc<_>),
 		select_chain.clone(),
+		Vec::new(),
 		telemetry.as_ref().map(|x| x.handle()),
 	)?;
 	let justification_import = grandpa_block_import.clone();
 
-	let (babe_block_import, babe_link) = sc_consensus_babe::block_import(
-		sc_consensus_babe::Config::get_or_compute(&*client)?,
-		grandpa_block_import.clone(),
-		client.clone(),
-	)?;
+	let babe_config = sc_consensus_babe::Config::get_or_compute(&*client)?;
+	let (block_import, babe_link) =
+		sc_consensus_babe::block_import(babe_config.clone(), grandpa_block_import, client.clone())?;
 
 	let slot_duration = babe_link.config().slot_duration();
 	let import_queue = sc_consensus_babe::import_queue(
 		babe_link.clone(),
-		babe_block_import.clone(),
+		block_import.clone(),
 		Some(Box::new(justification_import)),
 		client.clone(),
 		select_chain.clone(),
@@ -147,61 +244,203 @@ pub fn new_partial(
 		telemetry.as_ref().map(|x| x.handle()),
 	)?;
 
+	let justification_stream = grandpa_link.justification_stream();
+	let shared_authority_set = grandpa_link.shared_authority_set().clone();
+	let shared_voter_state = sc_finality_grandpa::SharedVoterState::empty();
+
+	let import_setup = (block_import, grandpa_link, babe_link);
+	let rpc_setup = shared_voter_state.clone();
+
+	let slot_duration = babe_config.slot_duration();
+
+	let rpc_extensions_builder = {
+		let client = client.clone();
+		let transaction_pool = transaction_pool.clone();
+		let backend = backend.clone();
+
+		move |deny_unsafe,
+		      subscription_executor: sc_rpc::SubscriptionTaskExecutor|
+		      -> jsonrpc_core::IoHandler<sc_service::RpcMetadata> {
+			use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApi};
+			use sc_finality_grandpa_rpc::{GrandpaApi, GrandpaRpcHandler};
+			use substrate_frame_rpc_system::{FullSystem, SystemApi};
+
+			let backend = backend.clone();
+			let client = client.clone();
+			let pool = transaction_pool.clone();
+
+			let shared_voter_state = shared_voter_state.clone();
+
+			let finality_proof_provider =
+				GrandpaFinalityProofProvider::new_for_service(backend, Some(shared_authority_set.clone()));
+
+			let mut io = jsonrpc_core::IoHandler::default();
+			io.extend_with(SystemApi::to_delegate(FullSystem::new(
+				client.clone(),
+				pool,
+				deny_unsafe,
+			)));
+			io.extend_with(TransactionPaymentApi::to_delegate(TransactionPayment::new(client)));
+			io.extend_with(GrandpaApi::to_delegate(GrandpaRpcHandler::new(
+				shared_authority_set.clone(),
+				shared_voter_state,
+				justification_stream.clone(),
+				subscription_executor,
+				finality_proof_provider,
+			)));
+
+			io
+		}
+	};
+
 	Ok(sc_service::PartialComponents {
 		client,
 		backend,
 		task_manager,
-		import_queue,
 		keystore_container,
 		select_chain,
+		import_queue,
 		transaction_pool,
 		other: (
-			grandpa_block_import,
-			grandpa_link,
-			babe_block_import,
-			babe_link,
+			rpc_extensions_builder,
+			import_setup,
+			rpc_setup,
+			slot_duration,
 			telemetry,
 		),
 	})
 }
 
-fn remote_keystore(_url: &str) -> 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.")
+pub struct NewFull<C> {
+	pub task_manager: TaskManager,
+	pub client: C,
+	pub overseer_handler: Option<OverseerHandler>,
+	pub network: Arc<sc_network::NetworkService<Block, <Block as BlockT>::Hash>>,
+	pub rpc_handlers: sc_service::RpcHandlers,
+	pub backend: Arc<FullBackend>,
 }
 
-/// Builds a new service for a full client.
-pub fn new_full(mut config: Configuration) -> Result<TaskManager, ServiceError> {
+/// The maximum number of active leaves we forward to the [`Overseer`] on startup.
+const MAX_ACTIVE_LEAVES: usize = 4;
+
+/// Returns the active leaves the overseer should start with.
+async fn active_leaves(
+	select_chain: &sc_consensus::LongestChain<FullBackend, Block>,
+	client: &FullClient,
+) -> Result<Vec<BlockInfo>, Error>
+where
+	RuntimeApi: ConstructRuntimeApi<Block, FullClient> + Send + Sync + 'static,
+	<RuntimeApi as ConstructRuntimeApi<Block, FullClient>>::RuntimeApi:
+		RequiredApiCollection<StateBackend = sc_client_api::StateBackendFor<FullBackend, Block>>,
+	Executor: NativeExecutionDispatch + 'static,
+{
+	let best_block = select_chain.best_chain().await?;
+
+	let mut leaves = select_chain
+		.leaves()
+		.await
+		.unwrap_or_default()
+		.into_iter()
+		.filter_map(|hash| {
+			let number = client.number(hash).ok()??;
+
+			// Only consider leaves that are in maximum an uncle of the best block.
+			if number < best_block.number().saturating_sub(1) || hash == best_block.hash() {
+				return None;
+			}
+
+			let parent_hash = client.header(&BlockId::Hash(hash)).ok()??.parent_hash;
+
+			Some(BlockInfo {
+				hash,
+				parent_hash,
+				number,
+			})
+		})
+		.collect::<Vec<_>>();
+
+	// Sort by block number and get the maximum number of leaves
+	leaves.sort_by_key(|b| b.number);
+
+	leaves.push(BlockInfo {
+		hash: best_block.hash(),
+		parent_hash: *best_block.parent_hash(),
+		number: *best_block.number(),
+	});
+
+	Ok(leaves.into_iter().rev().take(MAX_ACTIVE_LEAVES).collect())
+}
+
+// Create a new full node.
+pub fn new_full(
+	mut config: Configuration,
+	program_path: Option<std::path::PathBuf>,
+	overseer_gen: impl OverseerGen,
+) -> Result<NewFull<Arc<FullClient>>, Error>
+where
+	RuntimeApi: ConstructRuntimeApi<Block, FullClient> + Send + Sync + 'static,
+	<RuntimeApi as ConstructRuntimeApi<Block, FullClient>>::RuntimeApi:
+		RequiredApiCollection<StateBackend = sc_client_api::StateBackendFor<FullBackend, Block>>,
+	Executor: NativeExecutionDispatch + 'static,
+{
+	let is_collator = false;
+
+	let role = config.role.clone();
+	let force_authoring = config.force_authoring;
+	let backoff_authoring_blocks = Some(sc_consensus_slots::BackoffAuthoringOnFinalizedHeadLagging::default());
+
+	let disable_grandpa = config.disable_grandpa;
+	let name = config.network.node_name.clone();
+
 	let sc_service::PartialComponents {
 		client,
 		backend,
 		mut task_manager,
-		import_queue,
-		mut keystore_container,
+		keystore_container,
 		select_chain,
+		import_queue,
 		transaction_pool,
-		other: (_grandpa_block_import, grandpa_link, babe_block_import, babe_link, mut telemetry),
-	} = new_partial(&config)?;
-
-	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
-				)))
-			}
-		};
-	}
+		other: (rpc_extensions_builder, import_setup, rpc_setup, slot_duration, mut telemetry),
+	} = new_partial(&mut config)?;
+
+	let prometheus_registry = config.prometheus_registry().cloned();
 
+	let shared_voter_state = rpc_setup;
+	let auth_disc_publish_non_global_ips = config.network.allow_non_globals_in_dht;
+
+	// Note: GrandPa is pushed before the Polkadot-specific protocols. This doesn't change
+	// anything in terms of behaviour, but makes the logs more consistent with the other
+	// Substrate nodes.
 	config
 		.network
 		.extra_sets
 		.push(sc_finality_grandpa::grandpa_peers_set_config());
 
+	{
+		use polkadot_network_bridge::{peer_sets_info, IsAuthority};
+		let is_authority = if role.is_authority() {
+			IsAuthority::Yes
+		} else {
+			IsAuthority::No
+		};
+		config.network.extra_sets.extend(peer_sets_info(is_authority));
+	}
+
+	config
+		.network
+		.request_response_protocols
+		.push(sc_finality_grandpa_warp_sync::request_response_config_for_chain(
+			&config,
+			task_manager.spawn_handle(),
+			backend.clone(),
+			import_setup.1.shared_authority_set().clone(),
+		));
+	let request_multiplexer = {
+		let (multiplexer, configs) = RequestMultiplexer::new();
+		config.network.request_response_protocols.extend(configs);
+		multiplexer
+	};
+
 	let (network, system_rpc_tx, network_starter) = sc_service::build_network(sc_service::BuildNetworkParams {
 		config: &config,
 		client: client.clone(),
@@ -213,75 +452,146 @@ pub fn new_full(mut config: Configuration) -> Result<TaskManager, ServiceError>
 	})?;
 
 	if config.offchain_worker.enabled {
-		sc_service::build_offchain_workers(&config, task_manager.spawn_handle(), client.clone(), network.clone());
+		let _ =
+			sc_service::build_offchain_workers(&config, task_manager.spawn_handle(), client.clone(), network.clone());
 	}
 
-	let role = config.role.clone();
-	let force_authoring = config.force_authoring;
-	let backoff_authoring_blocks: Option<()> = None;
-	let name = config.network.node_name.clone();
-	let enable_grandpa = !config.disable_grandpa;
-	let prometheus_registry = config.prometheus_registry().cloned();
-
-	let shared_voter_state = sc_finality_grandpa::SharedVoterState::empty();
-
-	let rpc_extensions_builder = {
-		use sc_finality_grandpa::FinalityProofProvider as GrandpaFinalityProofProvider;
-
-		use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApi};
-		use sc_finality_grandpa_rpc::{GrandpaApi, GrandpaRpcHandler};
-		use sc_rpc::DenyUnsafe;
-		use substrate_frame_rpc_system::{FullSystem, SystemApi};
-
-		let backend = backend.clone();
-		let client = client.clone();
-		let pool = transaction_pool.clone();
-
-		let justification_stream = grandpa_link.justification_stream();
-		let shared_authority_set = grandpa_link.shared_authority_set().clone();
-		let shared_voter_state = shared_voter_state.clone();
+	let parachains_db = crate::parachains_db::open_creating(
+		config.database.path().ok_or(Error::DatabasePathRequired)?.into(),
+		crate::parachains_db::CacheSizes::default(),
+	)?;
 
-		let finality_proof_provider =
-			GrandpaFinalityProofProvider::new_for_service(backend, Some(shared_authority_set.clone()));
+	let availability_config = AvailabilityConfig {
+		col_data: crate::parachains_db::REAL_COLUMNS.col_availability_data,
+		col_meta: crate::parachains_db::REAL_COLUMNS.col_availability_meta,
+	};
 
-		Box::new(move |_, subscription_executor| {
-			let mut io = jsonrpc_core::IoHandler::default();
-			io.extend_with(SystemApi::to_delegate(FullSystem::new(
-				client.clone(),
-				pool.clone(),
-				DenyUnsafe::No,
-			)));
-			io.extend_with(TransactionPaymentApi::to_delegate(TransactionPayment::new(
-				client.clone(),
-			)));
-			io.extend_with(GrandpaApi::to_delegate(GrandpaRpcHandler::new(
-				shared_authority_set.clone(),
-				shared_voter_state.clone(),
-				justification_stream.clone(),
-				subscription_executor,
-				finality_proof_provider.clone(),
-			)));
+	let approval_voting_config = ApprovalVotingConfig {
+		col_data: crate::parachains_db::REAL_COLUMNS.col_approval_data,
+		slot_duration_millis: slot_duration.as_millis() as u64,
+	};
 
-			io
-		})
+	let candidate_validation_config = CandidateValidationConfig {
+		artifacts_cache_path: config
+			.database
+			.path()
+			.ok_or(Error::DatabasePathRequired)?
+			.join("pvf-artifacts"),
+		program_path: match program_path {
+			None => std::env::current_exe()?,
+			Some(p) => p,
+		},
 	};
 
-	let _rpc_handlers = sc_service::spawn_tasks(sc_service::SpawnTasksParams {
-		network: network.clone(),
+	let rpc_handlers = sc_service::spawn_tasks(sc_service::SpawnTasksParams {
+		config,
+		backend: backend.clone(),
 		client: client.clone(),
 		keystore: keystore_container.sync_keystore(),
-		task_manager: &mut task_manager,
+		network: network.clone(),
+		rpc_extensions_builder: Box::new(rpc_extensions_builder),
 		transaction_pool: transaction_pool.clone(),
-		rpc_extensions_builder,
+		task_manager: &mut task_manager,
 		on_demand: None,
 		remote_blockchain: None,
-		backend,
 		system_rpc_tx,
-		config,
 		telemetry: telemetry.as_mut(),
 	})?;
 
+	let (block_import, link_half, babe_link) = import_setup;
+
+	let overseer_client = client.clone();
+	let spawner = task_manager.spawn_handle();
+	let active_leaves = futures::executor::block_on(active_leaves(&select_chain, &*client))?;
+
+	let authority_discovery_service = if role.is_authority() || is_collator {
+		use futures::StreamExt;
+		use sc_network::Event;
+
+		let authority_discovery_role = if role.is_authority() {
+			sc_authority_discovery::Role::PublishAndDiscover(keystore_container.keystore())
+		} else {
+			// don't publish our addresses when we're only a collator
+			sc_authority_discovery::Role::Discover
+		};
+		let dht_event_stream = network.event_stream("authority-discovery").filter_map(|e| async move {
+			match e {
+				Event::Dht(e) => Some(e),
+				_ => None,
+			}
+		});
+		let (worker, service) = sc_authority_discovery::new_worker_and_service_with_config(
+			sc_authority_discovery::WorkerConfig {
+				publish_non_global_ips: auth_disc_publish_non_global_ips,
+				..Default::default()
+			},
+			client.clone(),
+			network.clone(),
+			Box::pin(dht_event_stream),
+			authority_discovery_role,
+			prometheus_registry.clone(),
+		);
+
+		task_manager
+			.spawn_handle()
+			.spawn("authority-discovery-worker", worker.run());
+		Some(service)
+	} else {
+		None
+	};
+
+	// we'd say let overseer_handler = authority_discovery_service.map(|authority_discovery_service|, ...),
+	// but in that case we couldn't use ? to propagate errors
+	let local_keystore = keystore_container.local_keystore();
+	let maybe_params = local_keystore.and_then(move |k| authority_discovery_service.map(|a| (a, k)));
+
+	let overseer_handler = if let Some((authority_discovery_service, keystore)) = maybe_params {
+		let (overseer, overseer_handler) =
+			overseer_gen.generate::<sc_service::SpawnTaskHandle, FullClient>(OverseerGenArgs {
+				leaves: active_leaves,
+				keystore,
+				runtime_client: overseer_client.clone(),
+				parachains_db,
+				availability_config,
+				approval_voting_config,
+				network_service: network.clone(),
+				authority_discovery_service,
+				request_multiplexer,
+				registry: prometheus_registry.as_ref(),
+				spawner,
+				candidate_validation_config,
+			})?;
+		let overseer_handler_clone = overseer_handler.clone();
+
+		task_manager.spawn_essential_handle().spawn_blocking(
+			"overseer",
+			Box::pin(async move {
+				use futures::{pin_mut, select, FutureExt};
+
+				let forward = polkadot_overseer::forward_events(overseer_client, overseer_handler_clone);
+
+				let forward = forward.fuse();
+				let overseer_fut = overseer.run().fuse();
+
+				pin_mut!(overseer_fut);
+				pin_mut!(forward);
+
+				select! {
+					_ = forward => (),
+					_ = overseer_fut => (),
+					complete => (),
+				}
+			}),
+		);
+
+		Some(overseer_handler)
+	} else {
+		None
+	};
+
 	if role.is_authority() {
+		let can_author_with = sp_consensus::CanAuthorWithNativeVersion::new(client.executor().clone());
+
 		let proposer = sc_basic_authorship::ProposerFactory::new(
 			task_manager.spawn_handle(),
 			client.clone(),
@@ -290,85 +600,118 @@ pub fn new_full(mut config: Configuration) -> Result<TaskManager, ServiceError>
 			telemetry.as_ref().map(|x| x.handle()),
 		);
 
-		let can_author_with = sp_consensus::CanAuthorWithNativeVersion::new(client.executor().clone());
-
+		let client_clone = client.clone();
+		let overseer_handler = overseer_handler
+			.as_ref()
+			.ok_or(Error::AuthoritiesRequireRealOverseer)?
+			.clone();
 		let slot_duration = babe_link.config().slot_duration();
 		let babe_config = sc_consensus_babe::BabeParams {
 			keystore: keystore_container.sync_keystore(),
-			client,
+			client: client.clone(),
 			select_chain,
+			block_import,
 			env: proposer,
-			block_import: babe_block_import,
 			sync_oracle: network.clone(),
 			justification_sync_link: network.clone(),
-			create_inherent_data_providers: move |_parent, ()| async move {
-				let timestamp = sp_timestamp::InherentDataProvider::from_system_time();
-
-				let slot = sp_consensus_babe::inherents::InherentDataProvider::from_timestamp_and_duration(
-					*timestamp,
-					slot_duration,
-				);
-
-				Ok((timestamp, slot))
+			create_inherent_data_providers: move |parent, ()| {
+				let client_clone = client_clone.clone();
+				let overseer_handler = overseer_handler.clone();
+				async move {
+					let parachain = polkadot_node_core_parachains_inherent::ParachainsInherentDataProvider::create(
+						&*client_clone,
+						overseer_handler,
+						parent,
+					)
+					.await
+					.map_err(Box::new)?;
+
+					let uncles = sc_consensus_uncles::create_uncles_inherent_data_provider(&*client_clone, parent)?;
+
+					let timestamp = sp_timestamp::InherentDataProvider::from_system_time();
+
+					let slot = sp_consensus_babe::inherents::InherentDataProvider::from_timestamp_and_duration(
+						*timestamp,
+						slot_duration,
+					);
+
+					Ok((timestamp, slot, uncles, parachain))
+				}
 			},
 			force_authoring,
 			backoff_authoring_blocks,
 			babe_link,
 			can_author_with,
-			block_proposal_slot_portion: SlotProportion::new(0.5),
+			block_proposal_slot_portion: sc_consensus_babe::SlotProportion::new(2f32 / 3f32),
 			max_block_proposal_slot_portion: None,
 			telemetry: telemetry.as_ref().map(|x| x.handle()),
 		};
 
 		let babe = sc_consensus_babe::start_babe(babe_config)?;
-		task_manager
-			.spawn_essential_handle()
-			.spawn_blocking("babe-proposer", babe);
+		task_manager.spawn_essential_handle().spawn_blocking("babe", babe);
 	}
 
 	// 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() {
+	let keystore_opt = 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),
+	let config = sc_finality_grandpa::Config {
+		// FIXME substrate#1578 make this available through chainspec
+		gossip_duration: Duration::from_millis(1000),
 		justification_period: 512,
 		name: Some(name),
 		observer_enabled: false,
-		keystore,
+		keystore: keystore_opt,
 		local_role: role,
 		telemetry: telemetry.as_ref().map(|x| x.handle()),
 	};
 
+	let enable_grandpa = !disable_grandpa;
 	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.
+		// NOTE: unlike in substrate we are currently running the full
+		// GRANDPA voter protocol for all full nodes (regardless of whether
+		// they're validators or not). at this point the full voter should
+		// provide better guarantees of block and vote data availability than
+		// the observer.
+
+		// add a custom voting rule to temporarily stop voting for new blocks
+		// after the given pause block is finalized and restarting after the
+		// given delay.
+		let builder = sc_finality_grandpa::VotingRulesBuilder::default();
+
+		let voting_rule = builder.build();
 		let grandpa_config = sc_finality_grandpa::GrandpaParams {
-			config: grandpa_config,
-			link: grandpa_link,
-			network,
-			voting_rule: sc_finality_grandpa::VotingRulesBuilder::default().build(),
+			config,
+			link: link_half,
+			network: network.clone(),
+			voting_rule,
 			prometheus_registry,
 			shared_voter_state,
 			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)?);
 	}
 
 	network_starter.start_network();
-	Ok(task_manager)
+
+	Ok(NewFull {
+		task_manager,
+		client,
+		overseer_handler,
+		network,
+		rpc_handlers,
+		backend,
+	})
+}
+
+pub fn build_full(config: Configuration, overseer_gen: impl OverseerGen) -> Result<NewFull<Arc<FullClient>>, Error> {
+	new_full(config, None, overseer_gen)
 }
diff --git a/bridges/bin/rialto/runtime/Cargo.toml b/bridges/bin/rialto/runtime/Cargo.toml
index b6e971eec00..4c0e51ad3c9 100644
--- a/bridges/bin/rialto/runtime/Cargo.toml
+++ b/bridges/bin/rialto/runtime/Cargo.toml
@@ -39,6 +39,7 @@ frame-executive = { git = "https://github.com/paritytech/substrate", branch = "m
 frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
 frame-system = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
 frame-system-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
+pallet-authority-discovery = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
 pallet-babe = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
 pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
 pallet-grandpa = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
@@ -49,6 +50,7 @@ pallet-timestamp = { git = "https://github.com/paritytech/substrate", branch = "
 pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
 pallet-transaction-payment-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
 sp-api = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
+sp-authority-discovery = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
 sp-block-builder = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
 sp-consensus-babe = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
 sp-core = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
@@ -63,6 +65,11 @@ sp-transaction-pool = { git = "https://github.com/paritytech/substrate", branch
 sp-trie = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
 sp-version = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
 
+# Polkadot (parachain) Dependencies
+
+polkadot-primitives = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false }
+polkadot-runtime-common = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false }
+polkadot-runtime-parachains = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false }
 
 [dev-dependencies]
 libsecp256k1 = { version = "0.3.4", features = ["hmac"] }
@@ -89,6 +96,7 @@ std = [
 	"frame-system-rpc-runtime-api/std",
 	"frame-system/std",
 	"log/std",
+	"pallet-authority-discovery/std",
 	"pallet-babe/std",
 	"pallet-balances/std",
 	"pallet-bridge-currency-exchange/std",
@@ -103,8 +111,12 @@ std = [
 	"pallet-timestamp/std",
 	"pallet-transaction-payment-rpc-runtime-api/std",
 	"pallet-transaction-payment/std",
+	"polkadot-primitives/std",
+	"polkadot-runtime-common/std",
+	"polkadot-runtime-parachains/std",
 	"serde",
 	"sp-api/std",
+	"sp-authority-discovery/std",
 	"sp-block-builder/std",
 	"sp-consensus-babe/std",
 	"sp-core/std",
diff --git a/bridges/bin/rialto/runtime/src/lib.rs b/bridges/bin/rialto/runtime/src/lib.rs
index 8b46020a1bd..fd3b5c94245 100644
--- a/bridges/bin/rialto/runtime/src/lib.rs
+++ b/bridges/bin/rialto/runtime/src/lib.rs
@@ -36,6 +36,7 @@ pub mod exchange;
 pub mod benches;
 pub mod kovan;
 pub mod millau_messages;
+pub mod parachains;
 pub mod rialto_poa;
 
 use crate::millau_messages::{ToMillauMessagePayload, WithMillauMessageBridge};
@@ -44,14 +45,15 @@ use bridge_runtime_common::messages::{source::estimate_message_dispatch_and_deli
 use pallet_grandpa::{fg_primitives, AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList};
 use pallet_transaction_payment::{FeeDetails, Multiplier, RuntimeDispatchInfo};
 use sp_api::impl_runtime_apis;
+use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId;
 use sp_core::{crypto::KeyTypeId, OpaqueMetadata};
-use sp_runtime::traits::{Block as BlockT, IdentityLookup, NumberFor, OpaqueKeys};
+use sp_runtime::traits::{AccountIdLookup, Block as BlockT, NumberFor, OpaqueKeys};
 use sp_runtime::{
 	create_runtime_str, generic, impl_opaque_keys,
 	transaction_validity::{TransactionSource, TransactionValidity},
 	ApplyExtrinsicResult, FixedPointNumber, MultiSignature, MultiSigner, Perquintill,
 };
-use sp_std::prelude::*;
+use sp_std::{collections::btree_map::BTreeMap, prelude::*};
 #[cfg(feature = "std")]
 use sp_version::NativeVersion;
 use sp_version::RuntimeVersion;
@@ -127,6 +129,9 @@ impl_opaque_keys! {
 	pub struct SessionKeys {
 		pub babe: Babe,
 		pub grandpa: Grandpa,
+		pub para_validator: Initializer,
+		pub para_assignment: SessionInfo,
+		pub authority_discovery: AuthorityDiscovery,
 	}
 }
 
@@ -168,7 +173,7 @@ impl frame_system::Config for Runtime {
 	/// The aggregated dispatch type that is available for extrinsics.
 	type Call = Call;
 	/// The lookup mechanism to get account ID from whatever is passed in dispatchers.
-	type Lookup = IdentityLookup<AccountId>;
+	type Lookup = AccountIdLookup<AccountId, ()>;
 	/// The index type for storing how many extrinsics an account has signed.
 	type Index = Index;
 	/// The index type for blocks.
@@ -220,7 +225,7 @@ pub const BABE_GENESIS_EPOCH_CONFIG: sp_consensus_babe::BabeEpochConfiguration =
 	};
 
 parameter_types! {
-	pub const EpochDuration: u64 = bp_rialto::time_units::EPOCH_DURATION_IN_SLOTS as u64;
+	pub const EpochDuration: u64 = bp_rialto::EPOCH_DURATION_IN_SLOTS as u64;
 	pub const ExpectedBlockTime: bp_rialto::Moment = bp_rialto::time_units::MILLISECS_PER_BLOCK;
 }
 
@@ -442,6 +447,8 @@ impl pallet_session::Config for Runtime {
 	type WeightInfo = ();
 }
 
+impl pallet_authority_discovery::Config for Runtime {}
+
 parameter_types! {
 	/// This is a pretty unscientific cap.
 	///
@@ -545,6 +552,7 @@ construct_runtime!(
 		TransactionPayment: pallet_transaction_payment::{Pallet, Storage},
 
 		// Consensus support.
+		AuthorityDiscovery: pallet_authority_discovery::{Pallet, Config},
 		Session: pallet_session::{Pallet, Call, Storage, Event, Config<T>},
 		Grandpa: pallet_grandpa::{Pallet, Call, Storage, Config, Event},
 		ShiftSessionManager: pallet_shift_session_manager::{Pallet},
@@ -560,11 +568,30 @@ construct_runtime!(
 		BridgeMillauGrandpa: pallet_bridge_grandpa::{Pallet, Call, Storage},
 		BridgeDispatch: pallet_bridge_dispatch::{Pallet, Event<T>},
 		BridgeMillauMessages: pallet_bridge_messages::{Pallet, Call, Storage, Event<T>, Config<T>},
+
+		// Parachain modules.
+		ParachainsOrigin: polkadot_runtime_parachains::origin::{Pallet, Origin},
+		ParachainsConfiguration: polkadot_runtime_parachains::configuration::{Pallet, Call, Storage, Config<T>},
+		Shared: polkadot_runtime_parachains::shared::{Pallet, Call, Storage},
+		Inclusion: polkadot_runtime_parachains::inclusion::{Pallet, Call, Storage, Event<T>},
+		ParasInherent: polkadot_runtime_parachains::paras_inherent::{Pallet, Call, Storage, Inherent},
+		Scheduler: polkadot_runtime_parachains::scheduler::{Pallet, Call, Storage},
+		Paras: polkadot_runtime_parachains::paras::{Pallet, Call, Storage, Event, Config},
+		Initializer: polkadot_runtime_parachains::initializer::{Pallet, Call, Storage},
+		Dmp: polkadot_runtime_parachains::dmp::{Pallet, Call, Storage},
+		Ump: polkadot_runtime_parachains::ump::{Pallet, Call, Storage, Event},
+		Hrmp: polkadot_runtime_parachains::hrmp::{Pallet, Call, Storage, Event, Config},
+		SessionInfo: polkadot_runtime_parachains::session_info::{Pallet, Call, Storage},
+
+		// Parachain Onboarding Pallets
+		Registrar: polkadot_runtime_common::paras_registrar::{Pallet, Call, Storage, Event<T>},
+		Slots: polkadot_runtime_common::slots::{Pallet, Call, Storage, Event<T>},
+		ParasSudoWrapper: polkadot_runtime_common::paras_sudo_wrapper::{Pallet, Call},
 	}
 );
 
 /// The address format for describing accounts.
-pub type Address = AccountId;
+pub type Address = sp_runtime::MultiAddress<AccountId, ()>;
 /// Block header type as expected by this runtime.
 pub type Header = generic::Header<BlockNumber, Hashing>;
 /// Block type as expected by this runtime.
@@ -769,6 +796,95 @@ impl_runtime_apis! {
 		}
 	}
 
+	impl polkadot_primitives::v1::ParachainHost<Block, Hash, BlockNumber> for Runtime {
+		fn validators() -> Vec<polkadot_primitives::v1::ValidatorId> {
+			polkadot_runtime_parachains::runtime_api_impl::v1::validators::<Runtime>()
+		}
+
+		fn validator_groups() -> (
+			Vec<Vec<polkadot_primitives::v1::ValidatorIndex>>,
+			polkadot_primitives::v1::GroupRotationInfo<BlockNumber>,
+		) {
+			polkadot_runtime_parachains::runtime_api_impl::v1::validator_groups::<Runtime>()
+		}
+
+		fn availability_cores() -> Vec<polkadot_primitives::v1::CoreState<Hash, BlockNumber>> {
+			polkadot_runtime_parachains::runtime_api_impl::v1::availability_cores::<Runtime>()
+		}
+
+		fn persisted_validation_data(
+			para_id: polkadot_primitives::v1::Id,
+			assumption: polkadot_primitives::v1::OccupiedCoreAssumption,
+		)
+			-> Option<polkadot_primitives::v1::PersistedValidationData<Hash, BlockNumber>> {
+			polkadot_runtime_parachains::runtime_api_impl::v1::persisted_validation_data::<Runtime>(para_id, assumption)
+		}
+
+		fn check_validation_outputs(
+			para_id: polkadot_primitives::v1::Id,
+			outputs: polkadot_primitives::v1::CandidateCommitments,
+		) -> bool {
+			polkadot_runtime_parachains::runtime_api_impl::v1::check_validation_outputs::<Runtime>(para_id, outputs)
+		}
+
+		fn session_index_for_child() -> polkadot_primitives::v1::SessionIndex {
+			polkadot_runtime_parachains::runtime_api_impl::v1::session_index_for_child::<Runtime>()
+		}
+
+		fn validation_code(
+			para_id: polkadot_primitives::v1::Id,
+			assumption: polkadot_primitives::v1::OccupiedCoreAssumption,
+		)
+			-> Option<polkadot_primitives::v1::ValidationCode> {
+			polkadot_runtime_parachains::runtime_api_impl::v1::validation_code::<Runtime>(para_id, assumption)
+		}
+
+		fn candidate_pending_availability(
+			para_id: polkadot_primitives::v1::Id,
+		) -> Option<polkadot_primitives::v1::CommittedCandidateReceipt<Hash>> {
+			polkadot_runtime_parachains::runtime_api_impl::v1::candidate_pending_availability::<Runtime>(para_id)
+		}
+
+		fn candidate_events() -> Vec<polkadot_primitives::v1::CandidateEvent<Hash>> {
+			polkadot_runtime_parachains::runtime_api_impl::v1::candidate_events::<Runtime, _>(|ev| {
+				match ev {
+					Event::Inclusion(ev) => {
+						Some(ev)
+					}
+					_ => None,
+				}
+			})
+		}
+
+		fn session_info(index: polkadot_primitives::v1::SessionIndex) -> Option<polkadot_primitives::v1::SessionInfo> {
+			polkadot_runtime_parachains::runtime_api_impl::v1::session_info::<Runtime>(index)
+		}
+
+		fn dmq_contents(
+			recipient: polkadot_primitives::v1::Id,
+		) -> Vec<polkadot_primitives::v1::InboundDownwardMessage<BlockNumber>> {
+			polkadot_runtime_parachains::runtime_api_impl::v1::dmq_contents::<Runtime>(recipient)
+		}
+
+		fn inbound_hrmp_channels_contents(
+			recipient: polkadot_primitives::v1::Id
+		) -> BTreeMap<polkadot_primitives::v1::Id, Vec<polkadot_primitives::v1::InboundHrmpMessage<BlockNumber>>> {
+			polkadot_runtime_parachains::runtime_api_impl::v1::inbound_hrmp_channels_contents::<Runtime>(recipient)
+		}
+
+		fn validation_code_by_hash(
+			hash: polkadot_primitives::v1::ValidationCodeHash,
+		) -> Option<polkadot_primitives::v1::ValidationCode> {
+			polkadot_runtime_parachains::runtime_api_impl::v1::validation_code_by_hash::<Runtime>(hash)
+		}
+	}
+
+	impl sp_authority_discovery::AuthorityDiscoveryApi<Block> for Runtime {
+		fn authorities() -> Vec<AuthorityDiscoveryId> {
+			polkadot_runtime_parachains::runtime_api_impl::v1::relevant_authority_ids::<Runtime>()
+		}
+	}
+
 	impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<
 		Block,
 		Balance,
diff --git a/bridges/bin/rialto/runtime/src/parachains.rs b/bridges/bin/rialto/runtime/src/parachains.rs
new file mode 100644
index 00000000000..47fc6722a19
--- /dev/null
+++ b/bridges/bin/rialto/runtime/src/parachains.rs
@@ -0,0 +1,158 @@
+// Copyright 2019-2021 Parity Technologies (UK) Ltd.
+// This file is part of Parity Bridges Common.
+
+// Parity Bridges Common is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Parity Bridges Common is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Parity Bridges Common.  If not, see <http://www.gnu.org/licenses/>.
+
+//! Parachains support in Rialto runtime.
+
+use crate::{
+	AccountId, Balance, Balances, BlockNumber, Event, Origin, RandomnessCollectiveFlip, Registrar, Runtime, Slots,
+};
+
+use frame_support::{parameter_types, weights::Weight};
+use frame_system::EnsureRoot;
+use polkadot_primitives::v1::ValidatorIndex;
+use polkadot_runtime_common::{paras_registrar, paras_sudo_wrapper, slots};
+use polkadot_runtime_parachains::configuration as parachains_configuration;
+use polkadot_runtime_parachains::dmp as parachains_dmp;
+use polkadot_runtime_parachains::hrmp as parachains_hrmp;
+use polkadot_runtime_parachains::inclusion as parachains_inclusion;
+use polkadot_runtime_parachains::initializer as parachains_initializer;
+use polkadot_runtime_parachains::origin as parachains_origin;
+use polkadot_runtime_parachains::paras as parachains_paras;
+use polkadot_runtime_parachains::paras_inherent as parachains_paras_inherent;
+use polkadot_runtime_parachains::scheduler as parachains_scheduler;
+use polkadot_runtime_parachains::session_info as parachains_session_info;
+use polkadot_runtime_parachains::shared as parachains_shared;
+use polkadot_runtime_parachains::ump as parachains_ump;
+
+/// Special `RewardValidators` that does nothing ;)
+pub struct RewardValidators;
+impl polkadot_runtime_parachains::inclusion::RewardValidators for RewardValidators {
+	fn reward_backing(_: impl IntoIterator<Item = ValidatorIndex>) {}
+	fn reward_bitfields(_: impl IntoIterator<Item = ValidatorIndex>) {}
+}
+
+// all required parachain modules from `polkadot-runtime-parachains` crate
+
+impl parachains_configuration::Config for Runtime {}
+
+impl parachains_dmp::Config for Runtime {}
+
+impl parachains_hrmp::Config for Runtime {
+	type Event = Event;
+	type Origin = Origin;
+	type Currency = Balances;
+}
+
+impl parachains_inclusion::Config for Runtime {
+	type Event = Event;
+	type RewardValidators = RewardValidators;
+}
+
+impl parachains_initializer::Config for Runtime {
+	type Randomness = RandomnessCollectiveFlip;
+	type ForceOrigin = EnsureRoot<AccountId>;
+}
+
+impl parachains_origin::Config for Runtime {}
+
+impl parachains_paras::Config for Runtime {
+	type Origin = Origin;
+	type Event = Event;
+}
+
+impl parachains_paras_inherent::Config for Runtime {}
+
+impl parachains_scheduler::Config for Runtime {}
+
+impl parachains_session_info::Config for Runtime {}
+
+impl parachains_shared::Config for Runtime {}
+
+parameter_types! {
+	pub const FirstMessageFactorPercent: u64 = 100;
+}
+
+impl parachains_ump::Config for Runtime {
+	type Event = Event;
+	type UmpSink = ();
+	type FirstMessageFactorPercent = FirstMessageFactorPercent;
+}
+
+// required onboarding pallets. We're not going to use auctions or crowdloans, so they're missing
+
+parameter_types! {
+	pub const ParaDeposit: Balance = 0;
+	pub const DataDepositPerByte: Balance = 0;
+}
+
+impl paras_registrar::Config for Runtime {
+	type Event = Event;
+	type Origin = Origin;
+	type Currency = Balances;
+	type OnSwap = Slots;
+	type ParaDeposit = ParaDeposit;
+	type DataDepositPerByte = DataDepositPerByte;
+	type WeightInfo = paras_registrar::TestWeightInfo;
+}
+
+parameter_types! {
+	pub const LeasePeriod: BlockNumber = 10 * bp_rialto::MINUTES;
+}
+
+impl slots::Config for Runtime {
+	type Event = Event;
+	type Currency = Balances;
+	type Registrar = Registrar;
+	type LeasePeriod = LeasePeriod;
+	type WeightInfo = slots::TestWeightInfo;
+}
+
+impl paras_sudo_wrapper::Config for Runtime {}
+
+pub struct ZeroWeights;
+
+impl polkadot_runtime_common::paras_registrar::WeightInfo for ZeroWeights {
+	fn reserve() -> Weight {
+		0
+	}
+	fn register() -> Weight {
+		0
+	}
+	fn force_register() -> Weight {
+		0
+	}
+	fn deregister() -> Weight {
+		0
+	}
+	fn swap() -> Weight {
+		0
+	}
+}
+
+impl polkadot_runtime_common::slots::WeightInfo for ZeroWeights {
+	fn force_lease() -> Weight {
+		0
+	}
+	fn manage_lease_period_start(_c: u32, _t: u32) -> Weight {
+		0
+	}
+	fn clear_all_leases() -> Weight {
+		0
+	}
+	fn trigger_onboard() -> Weight {
+		0
+	}
+}
diff --git a/bridges/primitives/chain-rialto/src/lib.rs b/bridges/primitives/chain-rialto/src/lib.rs
index b7b382f52bc..6ab3431e459 100644
--- a/bridges/primitives/chain-rialto/src/lib.rs
+++ b/bridges/primitives/chain-rialto/src/lib.rs
@@ -42,7 +42,7 @@ pub const EXTRA_STORAGE_PROOF_SIZE: u32 = 1024;
 /// Number of bytes, included in the signed Rialto transaction apart from the encoded call itself.
 ///
 /// Can be computed by subtracting encoded call size from raw transaction size.
-pub const TX_EXTRA_BYTES: u32 = 103;
+pub const TX_EXTRA_BYTES: u32 = 104;
 
 /// Maximal size (in bytes) of encoded (using `Encode::encode()`) account id.
 pub const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = 32;
diff --git a/bridges/relays/bin-substrate/src/chains/rialto.rs b/bridges/relays/bin-substrate/src/chains/rialto.rs
index 995ae7ae0d6..2e27342baa3 100644
--- a/bridges/relays/bin-substrate/src/chains/rialto.rs
+++ b/bridges/relays/bin-substrate/src/chains/rialto.rs
@@ -40,9 +40,9 @@ impl CliEncodeCall for Rialto {
 			Call::Remark { remark_payload, .. } => rialto_runtime::Call::System(rialto_runtime::SystemCall::remark(
 				remark_payload.as_ref().map(|x| x.0.clone()).unwrap_or_default(),
 			)),
-			Call::Transfer { recipient, amount } => {
-				rialto_runtime::Call::Balances(rialto_runtime::BalancesCall::transfer(recipient.raw_id(), amount.0))
-			}
+			Call::Transfer { recipient, amount } => rialto_runtime::Call::Balances(
+				rialto_runtime::BalancesCall::transfer(recipient.raw_id().into(), amount.0),
+			),
 			Call::BridgeSendMessage {
 				lane,
 				payload,
diff --git a/bridges/relays/bin-substrate/src/cli/encode_call.rs b/bridges/relays/bin-substrate/src/cli/encode_call.rs
index 343b44c3786..d7a9f840b16 100644
--- a/bridges/relays/bin-substrate/src/cli/encode_call.rs
+++ b/bridges/relays/bin-substrate/src/cli/encode_call.rs
@@ -209,7 +209,7 @@ mod tests {
 		// then
 		assert_eq!(
 			format!("{:?}", hex),
-			"0x0400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27de5c0"
+			"0x040000d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27de5c0"
 		);
 	}
 
diff --git a/bridges/relays/client-rialto/src/lib.rs b/bridges/relays/client-rialto/src/lib.rs
index ed0cec314a7..f7ba2ca65cb 100644
--- a/bridges/relays/client-rialto/src/lib.rs
+++ b/bridges/relays/client-rialto/src/lib.rs
@@ -100,7 +100,7 @@ impl TransactionSignScheme for Rialto {
 		let signer: sp_runtime::MultiSigner = signer.public().into();
 		let (call, extra, _) = raw_payload.deconstruct();
 
-		rialto_runtime::UncheckedExtrinsic::new_signed(call, signer.into_account(), signature.into(), extra)
+		rialto_runtime::UncheckedExtrinsic::new_signed(call, signer.into_account().into(), signature.into(), extra)
 	}
 
 	fn is_signed(tx: &Self::SignedTransaction) -> bool {
@@ -110,7 +110,7 @@ impl TransactionSignScheme for Rialto {
 	fn is_signed_by(signer: &Self::AccountKeyPair, tx: &Self::SignedTransaction) -> bool {
 		tx.signature
 			.as_ref()
-			.map(|(address, _, _)| *address == rialto_runtime::Address::from(*signer.public().as_array_ref()))
+			.map(|(address, _, _)| *address == rialto_runtime::Address::Id(signer.public().into()))
 			.unwrap_or(false)
 	}
 
-- 
GitLab