diff --git a/bridges/bin/rialto-parachain/runtime/Cargo.toml b/bridges/bin/rialto-parachain/runtime/Cargo.toml index 09916f508b7bf..d12e4326711d9 100644 --- a/bridges/bin/rialto-parachain/runtime/Cargo.toml +++ b/bridges/bin/rialto-parachain/runtime/Cargo.toml @@ -15,6 +15,10 @@ codec = { package = 'parity-scale-codec', version = '2.0.0', default-features = log = { version = "0.4.14", default-features = false } serde = { version = '1.0', optional = true, features = ['derive'] } +# Bridge depedencies + +bp-rialto-parachain = { path = "../../../primitives/chain-rialto-parachain", default-features = false } + # Substrate Dependencies ## Substrate Primitive Dependencies sp-api = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } @@ -77,6 +81,7 @@ runtime-benchmarks = [ 'pallet-timestamp/runtime-benchmarks', ] std = [ + "bp-rialto-parachain/std", "codec/std", "serde", "log/std", diff --git a/bridges/bin/rialto-parachain/runtime/src/lib.rs b/bridges/bin/rialto-parachain/runtime/src/lib.rs index 15911d6fc4134..bf55f08eb4b96 100644 --- a/bridges/bin/rialto-parachain/runtime/src/lib.rs +++ b/bridges/bin/rialto-parachain/runtime/src/lib.rs @@ -30,9 +30,9 @@ use sp_api::impl_runtime_apis; use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; use sp_runtime::{ create_runtime_str, generic, impl_opaque_keys, - traits::{AccountIdLookup, BlakeTwo256, Block as BlockT, IdentifyAccount, Verify}, + traits::{AccountIdLookup, Block as BlockT}, transaction_validity::{TransactionSource, TransactionValidity}, - ApplyExtrinsicResult, MultiSignature, + ApplyExtrinsicResult, }; use sp_std::prelude::*; @@ -50,7 +50,7 @@ pub use frame_support::{ }, StorageValue, }; -use frame_system::limits::{BlockLength, BlockWeights}; +pub use frame_system::Call as SystemCall; pub use pallet_balances::Call as BalancesCall; pub use pallet_timestamp::Call as TimestampCall; pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; @@ -58,6 +58,11 @@ pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; pub use sp_runtime::BuildStorage; pub use sp_runtime::{MultiAddress, Perbill, Permill}; +pub use bp_rialto_parachain::{ + AccountId, Balance, BlockLength, BlockNumber, BlockWeights, Hash, Hasher as Hashing, Header, + Index, Signature, MAXIMUM_BLOCK_WEIGHT, +}; + // Polkadot & XCM imports use pallet_xcm::XcmPassthrough; use polkadot_parachain::primitives::Sibling; @@ -71,26 +76,8 @@ use xcm_builder::{ }; use xcm_executor::{Config, XcmExecutor}; -// /// Import the template pallet. -// pub use template; - -/// Alias to 512-bit hash when used in the context of a transaction signature on the chain. -pub type Signature = MultiSignature; -/// Some way of identifying an account on the chain. We intentionally make it equivalent -/// to the public key of our transaction signing scheme. -pub type AccountId = <::Signer as IdentifyAccount>::AccountId; -/// Balance of an account. -pub type Balance = u128; -/// Index of a transaction in the chain. -pub type Index = u32; -/// A hash of some data used by the chain. -pub type Hash = sp_core::H256; -/// An index to a block. -pub type BlockNumber = u32; /// The address format for describing accounts. pub type Address = MultiAddress; -/// Block header type as expected by this runtime. -pub type Header = generic::Header; /// Block type as expected by this runtime. pub type Block = generic::Block; /// A Block signed with a Justification @@ -168,38 +155,9 @@ pub fn native_version() -> NativeVersion { NativeVersion { runtime_version: VERSION, can_author_with: Default::default() } } -/// We assume that approximately 10 percent of the block weight is consumed by `on_initalize` -/// handlers. This is used to limit the maximal weight of a single extrinsic. -const AVERAGE_ON_INITIALIZE_RATIO: Perbill = Perbill::from_percent(10); -/// We allow `Normal` extrinsics to fill up the block up to 75 percent, the rest can be used -/// by Operational extrinsics. -const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); -/// We allow for 2 seconds of compute with a 12 second average block time. -const MAXIMUM_BLOCK_WEIGHT: Weight = WEIGHT_PER_SECOND * 2; - parameter_types! { pub const BlockHashCount: BlockNumber = 250; pub const Version: RuntimeVersion = VERSION; - pub RuntimeBlockLength: BlockLength = - BlockLength::max_with_normal_ratio(5 * 1024 * 1024, NORMAL_DISPATCH_RATIO); - pub RuntimeBlockWeights: BlockWeights = BlockWeights::builder() - .base_block(BlockExecutionWeight::get()) - .for_class(DispatchClass::all(), |weights| { - weights.base_extrinsic = ExtrinsicBaseWeight::get(); - }) - .for_class(DispatchClass::Normal, |weights| { - weights.max_total = Some(NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT); - }) - .for_class(DispatchClass::Operational, |weights| { - weights.max_total = Some(MAXIMUM_BLOCK_WEIGHT); - // Operational transactions have some extra reserved space, so that they - // are included even if block reached `MAXIMUM_BLOCK_WEIGHT`. - weights.reserved = Some( - MAXIMUM_BLOCK_WEIGHT - NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT - ); - }) - .avg_block_initialization(AVERAGE_ON_INITIALIZE_RATIO) - .build_or_panic(); pub const SS58Prefix: u8 = 48; } @@ -219,9 +177,9 @@ impl frame_system::Config for Runtime { /// The type for hashing blocks and tries. type Hash = Hash; /// The hashing algorithm used. - type Hashing = BlakeTwo256; + type Hashing = Hashing; /// The header type. - type Header = generic::Header; + type Header = generic::Header; /// The ubiquitous event type. type Event = Event; /// The ubiquitous origin type. @@ -244,9 +202,9 @@ impl frame_system::Config for Runtime { /// Weight information for the extrinsics of this pallet. type SystemWeightInfo = (); /// Block & extrinsics weights: base values and limits. - type BlockWeights = RuntimeBlockWeights; + type BlockWeights = BlockWeights; /// The maximum length of a block (in bytes). - type BlockLength = RuntimeBlockLength; + type BlockLength = BlockLength; /// This is used as an identifier of the chain. 42 is the generic substrate prefix. type SS58Prefix = SS58Prefix; /// The action to take on a Runtime Upgrade diff --git a/bridges/primitives/chain-rialto-parachain/Cargo.toml b/bridges/primitives/chain-rialto-parachain/Cargo.toml new file mode 100644 index 0000000000000..034188631b8cd --- /dev/null +++ b/bridges/primitives/chain-rialto-parachain/Cargo.toml @@ -0,0 +1,36 @@ +[package] +name = "bp-rialto-parachain" +description = "Primitives of Rialto parachain runtime." +version = "0.1.0" +authors = ["Parity Technologies "] +edition = "2018" +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" + +[dependencies] + +# Bridge Dependencies + +bp-messages = { path = "../messages", default-features = false } +bp-runtime = { path = "../runtime", default-features = false } + +# Substrate Based Dependencies + +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 } +sp-api = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-core = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } + +[features] +default = ["std"] +std = [ + "bp-messages/std", + "bp-runtime/std", + "frame-support/std", + "frame-system/std", + "sp-api/std", + "sp-core/std", + "sp-runtime/std", + "sp-std/std", +] diff --git a/bridges/primitives/chain-rialto-parachain/src/lib.rs b/bridges/primitives/chain-rialto-parachain/src/lib.rs new file mode 100644 index 0000000000000..826f6d39bd7f7 --- /dev/null +++ b/bridges/primitives/chain-rialto-parachain/src/lib.rs @@ -0,0 +1,128 @@ +// 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 . + +#![cfg_attr(not(feature = "std"), no_std)] +// RuntimeApi generated functions +#![allow(clippy::too_many_arguments)] +// Runtime-generated DecodeLimit::decode_all_With_depth_limit +#![allow(clippy::unnecessary_mut_passed)] + +use bp_runtime::Chain; +use frame_support::{ + weights::{constants::WEIGHT_PER_SECOND, DispatchClass, IdentityFee, Weight}, + RuntimeDebug, +}; +use frame_system::limits; +use sp_core::Hasher as HasherT; +use sp_runtime::{ + traits::{BlakeTwo256, IdentifyAccount, Verify}, + MultiSignature, MultiSigner, Perbill, +}; + +/// Maximal weight of single Rialto parachain block. +/// +/// This represents two seconds of compute assuming a target block time of six seconds. +pub const MAXIMUM_BLOCK_WEIGHT: Weight = 2 * WEIGHT_PER_SECOND; + +/// Represents the average portion of a block's weight that will be used by an +/// `on_initialize()` runtime call. +pub const AVERAGE_ON_INITIALIZE_RATIO: Perbill = Perbill::from_percent(10); + +/// Represents the portion of a block that will be used by Normal extrinsics. +pub const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); + +/// Block number type used in Rialto. +pub type BlockNumber = u32; + +/// Hash type used in Rialto. +pub type Hash = ::Out; + +/// The type of object that can produce hashes on Rialto. +pub type Hasher = BlakeTwo256; + +/// The header type used by Rialto. +pub type Header = sp_runtime::generic::Header; + +/// Alias to 512-bit hash when used in the context of a transaction signature on the chain. +pub type Signature = MultiSignature; + +/// Some way of identifying an account on the chain. We intentionally make it equivalent +/// to the public key of our transaction signing scheme. +pub type AccountId = <::Signer as IdentifyAccount>::AccountId; + +/// Public key of the chain account that may be used to verify signatures. +pub type AccountSigner = MultiSigner; + +/// Balance of an account. +pub type Balance = u128; + +/// An instant or duration in time. +pub type Moment = u64; + +/// Index of a transaction in the parachain. +pub type Index = u32; + +/// Weight-to-Fee type used by Rialto parachain. +pub type WeightToFee = IdentityFee; + +/// Rialto parachain. +#[derive(RuntimeDebug)] +pub struct RialtoParachain; + +impl Chain for RialtoParachain { + type BlockNumber = BlockNumber; + type Hash = Hash; + type Hasher = Hasher; + type Header = Header; + + type AccountId = AccountId; + type Balance = Balance; + type Index = Index; + type Signature = Signature; +} + +frame_support::parameter_types! { + pub BlockLength: limits::BlockLength = + limits::BlockLength::max_with_normal_ratio(5 * 1024 * 1024, NORMAL_DISPATCH_RATIO); + pub BlockWeights: limits::BlockWeights = limits::BlockWeights::builder() + // Allowance for Normal class + .for_class(DispatchClass::Normal, |weights| { + weights.max_total = Some(NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT); + }) + // Allowance for Operational class + .for_class(DispatchClass::Operational, |weights| { + weights.max_total = Some(MAXIMUM_BLOCK_WEIGHT); + // Extra reserved space for Operational class + weights.reserved = Some(MAXIMUM_BLOCK_WEIGHT - NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT); + }) + // By default Mandatory class is not limited at all. + // This parameter is used to derive maximal size of a single extrinsic. + .avg_block_initialization(AVERAGE_ON_INITIALIZE_RATIO) + .build_or_panic(); +} + +/// Get the maximum weight (compute time) that a Normal extrinsic on the Millau chain can use. +pub fn max_extrinsic_weight() -> Weight { + BlockWeights::get() + .get(DispatchClass::Normal) + .max_extrinsic + .unwrap_or(Weight::MAX) +} + +/// Get the maximum length in bytes that a Normal extrinsic on the Millau chain requires. +pub fn max_extrinsic_size() -> u32 { + *BlockLength::get().max.get(DispatchClass::Normal) +} diff --git a/bridges/primitives/chain-rialto/src/lib.rs b/bridges/primitives/chain-rialto/src/lib.rs index 1ded7651cceca..6c4e48301e3bb 100644 --- a/bridges/primitives/chain-rialto/src/lib.rs +++ b/bridges/primitives/chain-rialto/src/lib.rs @@ -231,6 +231,12 @@ pub fn max_extrinsic_size() -> u32 { /// Name of the With-Millau messages pallet instance in the Rialto runtime. pub const WITH_MILLAU_MESSAGES_PALLET_NAME: &str = "BridgeMillauMessages"; +/// Name of the parachain registrar pallet in the Rialto runtime. +pub const PARAS_REGISTRAR_PALLET_NAME: &str = "Registrar"; + +/// Name of the parachains pallet in the Rialto runtime. +pub const PARAS_PALLET_NAME: &str = "Paras"; + /// Name of the `RialtoFinalityApi::best_finalized` runtime method. pub const BEST_FINALIZED_RIALTO_HEADER_METHOD: &str = "RialtoFinalityApi_best_finalized"; diff --git a/bridges/primitives/runtime/src/lib.rs b/bridges/primitives/runtime/src/lib.rs index 9a3470a2570c3..9ee15df1a9839 100644 --- a/bridges/primitives/runtime/src/lib.rs +++ b/bridges/primitives/runtime/src/lib.rs @@ -28,6 +28,7 @@ pub use chain::{ AccountIdOf, AccountPublicOf, BalanceOf, BlockNumberOf, Chain, HashOf, HasherOf, HeaderOf, IndexOf, SignatureOf, TransactionEraOf, }; +pub use frame_support::storage::storage_prefix as storage_value_final_key; pub use storage_proof::{Error as StorageProofError, StorageProofChecker}; #[cfg(feature = "std")] @@ -216,6 +217,15 @@ pub fn storage_map_final_key_blake2_128concat( ) } +/// +pub fn storage_map_final_key_twox64_concat( + pallet_prefix: &str, + map_name: &str, + key: &[u8], +) -> StorageKey { + storage_map_final_key_identity(pallet_prefix, map_name, &frame_support::Twox64Concat::hash(key)) +} + /// This is a copy of the /// `frame_support::storage::generator::StorageMap::storage_map_final_key` for `Identity` maps. /// diff --git a/bridges/relays/bin-substrate/Cargo.toml b/bridges/relays/bin-substrate/Cargo.toml index 6153fee1e569c..0f9e2792139fa 100644 --- a/bridges/relays/bin-substrate/Cargo.toml +++ b/bridges/relays/bin-substrate/Cargo.toml @@ -28,6 +28,7 @@ bp-message-dispatch = { path = "../../primitives/message-dispatch" } bp-millau = { path = "../../primitives/chain-millau" } bp-polkadot = { path = "../../primitives/chain-polkadot" } bp-rialto = { path = "../../primitives/chain-rialto" } +bp-rialto-parachain = { path = "../../primitives/chain-rialto-parachain" } bp-rococo = { path = "../../primitives/chain-rococo" } bp-token-swap = { path = "../../primitives/token-swap" } bp-wococo = { path = "../../primitives/chain-wococo" } @@ -44,11 +45,13 @@ relay-kusama-client = { path = "../client-kusama" } relay-millau-client = { path = "../client-millau" } relay-polkadot-client = { path = "../client-polkadot" } relay-rialto-client = { path = "../client-rialto" } +relay-rialto-parachain-client = { path = "../client-rialto-parachain" } relay-rococo-client = { path = "../client-rococo" } relay-wococo-client = { path = "../client-wococo" } relay-substrate-client = { path = "../client-substrate" } relay-utils = { path = "../utils" } relay-westend-client = { path = "../client-westend" } +rialto-parachain-runtime = { path = "../../bin/rialto-parachain/runtime" } rialto-runtime = { path = "../../bin/rialto/runtime" } substrate-relay-helper = { path = "../lib-substrate-relay" } @@ -61,6 +64,13 @@ sp-io = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-version = { git = "https://github.com/paritytech/substrate", branch = "master" } +# Polkadot Dependencies + +polkadot-parachain = { git = "https://github.com/paritytech/polkadot", branch = "master" } +polkadot-primitives = { git = "https://github.com/paritytech/polkadot", branch = "master" } +polkadot-runtime-common = { git = "https://github.com/paritytech/polkadot", branch = "master" } +polkadot-runtime-parachains = { git = "https://github.com/paritytech/polkadot", branch = "master" } + [dev-dependencies] hex-literal = "0.3" pallet-bridge-grandpa = { path = "../../modules/grandpa" } diff --git a/bridges/relays/bin-substrate/src/chains/mod.rs b/bridges/relays/bin-substrate/src/chains/mod.rs index ea7c9754ec72a..1e5e549d519a9 100644 --- a/bridges/relays/bin-substrate/src/chains/mod.rs +++ b/bridges/relays/bin-substrate/src/chains/mod.rs @@ -34,6 +34,7 @@ mod kusama; mod millau; mod polkadot; mod rialto; +mod rialto_parachain; mod rococo; mod westend; mod wococo; diff --git a/bridges/relays/bin-substrate/src/chains/rialto_parachain.rs b/bridges/relays/bin-substrate/src/chains/rialto_parachain.rs new file mode 100644 index 0000000000000..f81bc61b859a8 --- /dev/null +++ b/bridges/relays/bin-substrate/src/chains/rialto_parachain.rs @@ -0,0 +1,82 @@ +// 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 . + +//! Rialto parachain specification for CLI. + +use crate::cli::{ + encode_call::{Call, CliEncodeCall}, + encode_message, CliChain, +}; +use bp_message_dispatch::MessagePayload; +use codec::Decode; +use frame_support::weights::{DispatchInfo, GetDispatchInfo, Weight}; +use relay_rialto_parachain_client::RialtoParachain; +use sp_version::RuntimeVersion; + +impl CliEncodeCall for RialtoParachain { + fn max_extrinsic_size() -> u32 { + bp_rialto_parachain::max_extrinsic_size() + } + + fn encode_call(call: &Call) -> anyhow::Result { + Ok(match call { + Call::Raw { data } => Decode::decode(&mut &*data.0)?, + Call::Remark { remark_payload, .. } => rialto_parachain_runtime::Call::System( + rialto_parachain_runtime::SystemCall::remark( + remark_payload.as_ref().map(|x| x.0.clone()).unwrap_or_default(), + ), + ), + Call::Transfer { recipient, amount } => rialto_parachain_runtime::Call::Balances( + rialto_parachain_runtime::BalancesCall::transfer( + recipient.raw_id().into(), + amount.0, + ), + ), + Call::BridgeSendMessage { .. } => + anyhow::bail!("Bridge messages are not (yet) supported here",), + }) + } + + fn get_dispatch_info(call: &rialto_parachain_runtime::Call) -> anyhow::Result { + Ok(call.get_dispatch_info()) + } +} + +impl CliChain for RialtoParachain { + const RUNTIME_VERSION: RuntimeVersion = rialto_parachain_runtime::VERSION; + + type KeyPair = sp_core::sr25519::Pair; + type MessagePayload = MessagePayload< + bp_rialto_parachain::AccountId, + bp_millau::AccountSigner, + bp_millau::Signature, + Vec, + >; + + fn ss58_format() -> u16 { + rialto_parachain_runtime::SS58Prefix::get() as u16 + } + + fn max_extrinsic_weight() -> Weight { + bp_rialto_parachain::max_extrinsic_weight() + } + + fn encode_message( + _message: encode_message::MessagePayload, + ) -> Result { + Err("Not supported".into()) + } +} diff --git a/bridges/relays/bin-substrate/src/cli/mod.rs b/bridges/relays/bin-substrate/src/cli/mod.rs index 97998a33d35bf..b50fd20ea94fd 100644 --- a/bridges/relays/bin-substrate/src/cli/mod.rs +++ b/bridges/relays/bin-substrate/src/cli/mod.rs @@ -32,6 +32,7 @@ pub(crate) mod send_message; mod derive_account; mod init_bridge; +mod register_parachain; mod relay_headers; mod relay_headers_and_messages; mod relay_messages; @@ -93,6 +94,8 @@ pub enum Command { ResubmitTransactions(resubmit_transactions::ResubmitTransactions), /// Swap tokens using token-swap bridge. SwapTokens(swap_tokens::SwapTokens), + /// Register parachain. + RegisterParachain(register_parachain::RegisterParachain), } impl Command { @@ -128,6 +131,7 @@ impl Command { Self::DeriveAccount(arg) => arg.run().await?, Self::ResubmitTransactions(arg) => arg.run().await?, Self::SwapTokens(arg) => arg.run().await?, + Self::RegisterParachain(arg) => arg.run().await?, } Ok(()) } @@ -438,6 +442,7 @@ macro_rules! declare_chain_options { } /// Parse signing params into chain-specific KeyPair. + #[allow(dead_code)] pub fn to_keypair(&self) -> anyhow::Result { let suri = match (self.[<$chain_prefix _signer>].as_ref(), self.[<$chain_prefix _signer_file>].as_ref()) { (Some(suri), _) => suri.to_owned(), @@ -515,6 +520,8 @@ macro_rules! declare_chain_options { declare_chain_options!(Source, source); declare_chain_options!(Target, target); +declare_chain_options!(Relaychain, relaychain); +declare_chain_options!(Parachain, parachain); #[cfg(test)] mod tests { diff --git a/bridges/relays/bin-substrate/src/cli/register_parachain.rs b/bridges/relays/bin-substrate/src/cli/register_parachain.rs new file mode 100644 index 0000000000000..00e98e419e5b7 --- /dev/null +++ b/bridges/relays/bin-substrate/src/cli/register_parachain.rs @@ -0,0 +1,343 @@ +// 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 . + +use crate::cli::{ + swap_tokens::wait_until_transaction_is_finalized, Balance, ParachainConnectionParams, + RelaychainConnectionParams, RelaychainSigningParams, +}; + +use codec::Encode; +use num_traits::Zero; +use polkadot_parachain::primitives::{ + HeadData as ParaHeadData, Id as ParaId, ValidationCode as ParaValidationCode, +}; +use polkadot_runtime_common::{ + paras_registrar::Call as ParaRegistrarCall, slots::Call as ParaSlotsCall, +}; +use polkadot_runtime_parachains::paras::ParaLifecycle; +use relay_substrate_client::{ + AccountIdOf, CallOf, Chain, Client, TransactionSignScheme, UnsignedTransaction, +}; +use rialto_runtime::SudoCall; +use sp_core::{ + storage::{well_known_keys::CODE, StorageKey}, + Bytes, Pair, +}; +use structopt::StructOpt; +use strum::{EnumString, EnumVariantNames, VariantNames}; + +/// Name of the `NextFreeParaId` value in the `polkadot_runtime_common::paras_registrar` pallet. +const NEXT_FREE_PARA_ID_STORAGE_NAME: &str = "NextFreeParaId"; +/// Name of the `ParaLifecycles` map in the `polkadot_runtime_parachains::paras` pallet. +const PARAS_LIFECYCLES_STORAGE_NAME: &str = "ParaLifecycles"; + +/// Register parachain. +#[derive(StructOpt, Debug, PartialEq)] +pub struct RegisterParachain { + /// A parachain to register. + #[structopt(possible_values = Parachain::VARIANTS, case_insensitive = true)] + parachain: Parachain, + /// Parachain deposit. + #[structopt(long, default_value = "0")] + deposit: Balance, + /// Lease begin. + #[structopt(long, default_value = "0")] + lease_begin: u32, + /// Lease end. + #[structopt(long, default_value = "256")] + lease_end: u32, + #[structopt(flatten)] + relay_connection: RelaychainConnectionParams, + #[structopt(flatten)] + relay_sign: RelaychainSigningParams, + #[structopt(flatten)] + para_connection: ParachainConnectionParams, +} + +/// Parachain to register. +#[derive(Debug, EnumString, EnumVariantNames, PartialEq)] +#[strum(serialize_all = "kebab_case")] +pub enum Parachain { + RialtoParachain, +} + +macro_rules! select_bridge { + ($bridge: expr, $generic: tt) => { + match $bridge { + Parachain::RialtoParachain => { + type Relaychain = relay_rialto_client::Rialto; + type Parachain = relay_rialto_parachain_client::RialtoParachain; + + use bp_rialto::{PARAS_PALLET_NAME, PARAS_REGISTRAR_PALLET_NAME}; + + $generic + }, + } + }; +} + +impl RegisterParachain { + /// Run the command. + pub async fn run(self) -> anyhow::Result<()> { + select_bridge!(self.parachain, { + let relay_client = self.relay_connection.to_client::().await?; + let relay_sign = self.relay_sign.to_keypair::()?; + let para_client = self.para_connection.to_client::().await?; + + // hopefully we're the only actor that is registering parachain right now + // => read next parachain id + let para_id_key = bp_runtime::storage_value_final_key( + PARAS_REGISTRAR_PALLET_NAME.as_bytes(), + NEXT_FREE_PARA_ID_STORAGE_NAME.as_bytes(), + ); + let para_id: ParaId = relay_client + .storage_value(StorageKey(para_id_key.to_vec()), None) + .await? + .unwrap_or(polkadot_primitives::v1::LOWEST_PUBLIC_ID) + .max(polkadot_primitives::v1::LOWEST_PUBLIC_ID); + log::info!(target: "bridge", "Going to reserve parachain id: {:?}", para_id); + + // step 1: reserve a parachain id + let relay_genesis_hash = *relay_client.genesis_hash(); + let relay_sudo_account: AccountIdOf = relay_sign.public().clone().into(); + let reserve_parachain_id_call: CallOf = ParaRegistrarCall::reserve().into(); + let reserve_parachain_signer = relay_sign.clone(); + wait_until_transaction_is_finalized::( + relay_client + .submit_and_watch_signed_extrinsic( + relay_sudo_account.clone(), + move |_, transaction_nonce| { + Bytes( + Relaychain::sign_transaction( + relay_genesis_hash, + &reserve_parachain_signer, + relay_substrate_client::TransactionEra::immortal(), + UnsignedTransaction::new( + reserve_parachain_id_call, + transaction_nonce, + ), + ) + .encode(), + ) + }, + ) + .await?, + ) + .await?; + log::info!(target: "bridge", "Reserved parachain id: {:?}", para_id); + + // step 2: register parathread + let para_genesis_header = para_client.header_by_number(Zero::zero()).await?; + let para_code = para_client + .raw_storage_value(StorageKey(CODE.to_vec()), Some(para_genesis_header.hash())) + .await? + .ok_or_else(|| { + anyhow::format_err!("Cannot fetch validation code of {}", Parachain::NAME) + })? + .0; + log::info!( + target: "bridge", + "Going to register parachain {:?}: genesis len = {} code len = {}", + para_id, + para_genesis_header.encode().len(), + para_code.len(), + ); + let register_parathread_call: CallOf = ParaRegistrarCall::register( + para_id, + ParaHeadData(para_genesis_header.encode()), + ParaValidationCode(para_code), + ) + .into(); + let register_parathread_signer = relay_sign.clone(); + wait_until_transaction_is_finalized::( + relay_client + .submit_and_watch_signed_extrinsic( + relay_sudo_account.clone(), + move |_, transaction_nonce| { + Bytes( + Relaychain::sign_transaction( + relay_genesis_hash, + ®ister_parathread_signer, + relay_substrate_client::TransactionEra::immortal(), + UnsignedTransaction::new( + register_parathread_call, + transaction_nonce, + ), + ) + .encode(), + ) + }, + ) + .await?, + ) + .await?; + log::info!(target: "bridge", "Registered parachain: {:?}. Waiting for onboarding", para_id); + + // wait until parathread is onboarded + let para_state_key = bp_runtime::storage_map_final_key_twox64_concat( + PARAS_PALLET_NAME, + PARAS_LIFECYCLES_STORAGE_NAME, + ¶_id.encode(), + ); + wait_para_state( + &relay_client, + ¶_state_key.0, + &[ParaLifecycle::Onboarding, ParaLifecycle::Parathread], + ParaLifecycle::Parathread, + ) + .await?; + + // step 3: force parachain leases + let lease_begin = self.lease_begin; + let lease_end = self.lease_end; + let para_deposit = self.deposit.cast().into(); + log::info!( + target: "bridge", + "Going to force leases of parachain {:?}: [{}; {}]", + para_id, + lease_begin, + lease_end, + ); + let force_lease_call: CallOf = SudoCall::sudo(Box::new( + ParaSlotsCall::force_lease( + para_id, + relay_sudo_account.clone(), + para_deposit, + lease_begin, + lease_end, + ) + .into(), + )) + .into(); + let force_lease_signer = relay_sign.clone(); + relay_client + .submit_signed_extrinsic(relay_sudo_account.clone(), move |_, transaction_nonce| { + Bytes( + Relaychain::sign_transaction( + relay_genesis_hash, + &force_lease_signer, + relay_substrate_client::TransactionEra::immortal(), + UnsignedTransaction::new(force_lease_call, transaction_nonce), + ) + .encode(), + ) + }) + .await?; + log::info!(target: "bridge", "Registered parachain leases: {:?}. Waiting for onboarding", para_id); + + // wait until parachain is onboarded + wait_para_state( + &relay_client, + ¶_state_key.0, + &[ + ParaLifecycle::Onboarding, + ParaLifecycle::UpgradingParathread, + ParaLifecycle::Parathread, + ], + ParaLifecycle::Parachain, + ) + .await?; + + Ok(()) + }) + } +} + +/// Wait until parachain state is changed. +async fn wait_para_state( + relay_client: &Client, + para_state_key: &[u8], + from_states: &[ParaLifecycle], + to_state: ParaLifecycle, +) -> anyhow::Result<()> { + loop { + let para_state: ParaLifecycle = relay_client + .storage_value(StorageKey(para_state_key.to_vec()), None) + .await? + .ok_or_else(|| { + anyhow::format_err!( + "Cannot fetch next free parachain lifecycle from the runtime storage of {}", + Relaychain::NAME, + ) + })?; + if !from_states.contains(¶_state) { + return Err(anyhow::format_err!("Invalid parachain lifecycle: {:?}", para_state)) + } + if para_state == to_state { + log::info!(target: "bridge", "Parachain state is now: {:?}", to_state); + return Ok(()) + } + + log::info!(target: "bridge", "Parachain state: {:?}. Waiting for {:?}", para_state, to_state); + async_std::task::sleep(Relaychain::AVERAGE_BLOCK_INTERVAL).await; + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn register_rialto_parachain() { + let register_parachain = RegisterParachain::from_iter(vec![ + "register-parachain", + "rialto-parachain", + "--parachain-host", + "127.0.0.1", + "--parachain-port", + "11949", + "--relaychain-host", + "127.0.0.1", + "--relaychain-port", + "9944", + "--relaychain-signer", + "//Alice", + "--deposit", + "42", + "--lease-begin", + "100", + "--lease-end", + "200", + ]); + + assert_eq!( + register_parachain, + RegisterParachain { + parachain: Parachain::RialtoParachain, + deposit: Balance(42), + lease_begin: 100, + lease_end: 200, + relay_connection: RelaychainConnectionParams { + relaychain_host: "127.0.0.1".into(), + relaychain_port: 9944, + relaychain_secure: false, + }, + relay_sign: RelaychainSigningParams { + relaychain_signer: Some("//Alice".into()), + relaychain_signer_password: None, + relaychain_signer_file: None, + relaychain_signer_password_file: None, + relaychain_transactions_mortality: None, + }, + para_connection: ParachainConnectionParams { + parachain_host: "127.0.0.1".into(), + parachain_port: 11949, + parachain_secure: false, + }, + } + ); + } +} diff --git a/bridges/relays/bin-substrate/src/cli/swap_tokens.rs b/bridges/relays/bin-substrate/src/cli/swap_tokens.rs index 7d7d7ce56e64b..01eb3fbb4f528 100644 --- a/bridges/relays/bin-substrate/src/cli/swap_tokens.rs +++ b/bridges/relays/bin-substrate/src/cli/swap_tokens.rs @@ -570,7 +570,7 @@ async fn read_account_balance( /// Wait until transaction is included into finalized block. /// /// Returns the hash of the finalized block with transaction. -async fn wait_until_transaction_is_finalized( +pub(crate) async fn wait_until_transaction_is_finalized( subscription: Subscription>, ) -> anyhow::Result> { loop { diff --git a/bridges/relays/client-rialto-parachain/Cargo.toml b/bridges/relays/client-rialto-parachain/Cargo.toml new file mode 100644 index 0000000000000..e4518c6877652 --- /dev/null +++ b/bridges/relays/client-rialto-parachain/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "relay-rialto-parachain-client" +version = "0.1.0" +authors = ["Parity Technologies "] +edition = "2018" +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" + +[dependencies] +relay-substrate-client = { path = "../client-substrate" } +relay-utils = { path = "../utils" } + +# Bridge dependencies + +bp-rialto = { path = "../../primitives/chain-rialto" } +rialto-parachain-runtime = { path = "../../bin/rialto-parachain/runtime" } + +# Substrate Dependencies + +frame-system = { git = "https://github.com/paritytech/substrate", branch = "master" } +frame-support = { git = "https://github.com/paritytech/substrate", branch = "master" } +pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", branch = "master" } diff --git a/bridges/relays/client-rialto-parachain/src/lib.rs b/bridges/relays/client-rialto-parachain/src/lib.rs new file mode 100644 index 0000000000000..ca299a0eeb78b --- /dev/null +++ b/bridges/relays/client-rialto-parachain/src/lib.rs @@ -0,0 +1,51 @@ +// 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 . + +//! Types used to connect to the Rialto-Substrate chain. + +use relay_substrate_client::{Chain, ChainBase}; +use std::time::Duration; + +/// Rialto header id. +pub type HeaderId = + relay_utils::HeaderId; + +/// Rialto parachain definition +#[derive(Debug, Clone, Copy)] +pub struct RialtoParachain; + +impl ChainBase for RialtoParachain { + type BlockNumber = rialto_parachain_runtime::BlockNumber; + type Hash = rialto_parachain_runtime::Hash; + type Hasher = rialto_parachain_runtime::Hashing; + type Header = rialto_parachain_runtime::Header; + + type AccountId = rialto_parachain_runtime::AccountId; + type Balance = rialto_parachain_runtime::Balance; + type Index = rialto_parachain_runtime::Index; + type Signature = rialto_parachain_runtime::Signature; +} + +impl Chain for RialtoParachain { + const NAME: &'static str = "RialtoParachain"; + const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(5); + const STORAGE_PROOF_OVERHEAD: u32 = bp_rialto::EXTRA_STORAGE_PROOF_SIZE; + const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = bp_rialto::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE; + + type SignedBlock = rialto_parachain_runtime::SignedBlock; + type Call = rialto_parachain_runtime::Call; + type WeightToFee = bp_rialto::WeightToFee; +} diff --git a/bridges/relays/client-substrate/src/client.rs b/bridges/relays/client-substrate/src/client.rs index fd69dd255e6da..1902875c93810 100644 --- a/bridges/relays/client-substrate/src/client.rs +++ b/bridges/relays/client-substrate/src/client.rs @@ -38,7 +38,10 @@ use num_traits::{Bounded, Zero}; use pallet_balances::AccountData; use pallet_transaction_payment::InclusionFee; use relay_utils::{relay_loop::RECONNECT_DELAY, HeaderId}; -use sp_core::{storage::StorageKey, Bytes, Hasher}; +use sp_core::{ + storage::{StorageData, StorageKey}, + Bytes, Hasher, +}; use sp_runtime::{ traits::Header as HeaderT, transaction_validity::{TransactionSource, TransactionValidity}, @@ -269,13 +272,22 @@ impl Client { storage_key: StorageKey, block_hash: Option, ) -> Result> { + self.raw_storage_value(storage_key, block_hash) + .await? + .map(|encoded_value| { + T::decode(&mut &encoded_value.0[..]).map_err(Error::ResponseParseFailed) + }) + .transpose() + } + + /// Read raw value from runtime storage. + pub async fn raw_storage_value( + &self, + storage_key: StorageKey, + block_hash: Option, + ) -> Result> { self.jsonrpsee_execute(move |client| async move { - Substrate::::state_get_storage(&*client, storage_key, block_hash) - .await? - .map(|encoded_value| { - T::decode(&mut &encoded_value.0[..]).map_err(Error::ResponseParseFailed) - }) - .transpose() + Ok(Substrate::::state_get_storage(&*client, storage_key, block_hash).await?) }) .await }