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