diff --git a/Cargo.lock b/Cargo.lock index 2b5ada7eb2627..7032592f21fd8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6685,7 +6685,7 @@ checksum = "8c321610643004cf908ec0f5f2aa0d8f1f8e14b540562a2887a1111ff1ecbf7b" dependencies = [ "crunchy", "fixed-hash", - "impl-codec 0.7.1", + "impl-codec 0.7.0", "impl-rlp 0.4.0", "impl-serde 0.5.0", "scale-info", @@ -6716,7 +6716,7 @@ checksum = "1ab15ed80916029f878e0267c3a9f92b67df55e79af370bf66199059ae2b4ee3" dependencies = [ "ethbloom 0.14.1", "fixed-hash", - "impl-codec 0.7.1", + "impl-codec 0.7.0", "impl-rlp 0.4.0", "impl-serde 0.5.0", "primitive-types 0.13.1", @@ -8944,9 +8944,9 @@ dependencies = [ [[package]] name = "impl-codec" -version = "0.7.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d40b9d5e17727407e55028eafc22b2dc68781786e6d7eb8a21103f5058e3a14" +checksum = "b67aa010c1e3da95bf151bd8b4c059b2ed7e75387cdb969b4f8f2723a43f9941" dependencies = [ "parity-scale-codec", ] @@ -15511,6 +15511,42 @@ dependencies = [ "sp-staking 36.0.0", ] +[[package]] +name = "pallet-staking-ah-client" +version = "0.1.0" +dependencies = [ + "frame-support 28.0.0", + "frame-system 28.0.0", + "log", + "pallet-authorship 28.0.0", + "pallet-session 28.0.0", + "pallet-staking 28.0.0", + "pallet-staking-rc-client", + "parity-scale-codec", + "polkadot-primitives 7.0.0", + "polkadot-runtime-parachains 7.0.0", + "scale-info", + "sp-core 28.0.0", + "sp-runtime 31.0.1", + "sp-staking 26.0.0", + "staging-xcm 7.0.0", +] + +[[package]] +name = "pallet-staking-rc-client" +version = "0.1.0" +dependencies = [ + "frame-support 28.0.0", + "frame-system 28.0.0", + "log", + "parity-scale-codec", + "scale-info", + "sp-core 28.0.0", + "sp-runtime 31.0.1", + "sp-staking 26.0.0", + "staging-xcm 7.0.0", +] + [[package]] name = "pallet-staking-reward-curve" version = "11.0.0" @@ -18835,6 +18871,8 @@ dependencies = [ "pallet-skip-feeless-payment 3.0.0", "pallet-society 28.0.0", "pallet-staking 28.0.0", + "pallet-staking-ah-client", + "pallet-staking-rc-client", "pallet-staking-reward-curve", "pallet-staking-reward-fn 19.0.0", "pallet-staking-runtime-api 14.0.0", @@ -20461,7 +20499,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d15600a7d856470b7d278b3fe0e311fe28c2526348549f8ef2ff7db3299c87f5" dependencies = [ "fixed-hash", - "impl-codec 0.7.1", + "impl-codec 0.7.0", "impl-num-traits 0.2.0", "impl-rlp 0.4.0", "impl-serde 0.5.0", @@ -26425,53 +26463,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "sp-core" -version = "35.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4532774405a712a366a98080cbb4daa28c38ddff0ec595902ad6ee6a78a809f8" -dependencies = [ - "array-bytes", - "bitflags 1.3.2", - "blake2 0.10.6", - "bounded-collections", - "bs58", - "dyn-clonable", - "ed25519-zebra 4.0.3", - "futures", - "hash-db", - "hash256-std-hasher", - "impl-serde 0.5.0", - "itertools 0.11.0", - "k256", - "libsecp256k1", - "log", - "merlin", - "parity-bip39", - "parity-scale-codec", - "parking_lot 0.12.3", - "paste", - "primitive-types 0.13.1", - "rand", - "scale-info", - "schnorrkel 0.11.4", - "secp256k1 0.28.2", - "secrecy 0.8.0", - "serde", - "sp-crypto-hashing 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sp-debug-derive 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sp-externalities 0.30.0", - "sp-runtime-interface 29.0.0", - "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sp-storage 22.0.0", - "ss58-registry", - "substrate-bip39 0.6.0", - "thiserror", - "tracing", - "w3f-bls", - "zeroize", -] - [[package]] name = "sp-core-fuzz" version = "0.0.0" @@ -26693,17 +26684,6 @@ dependencies = [ "sp-storage 21.0.0", ] -[[package]] -name = "sp-externalities" -version = "0.30.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30cbf059dce180a8bf8b6c8b08b6290fa3d1c7f069a60f1df038ab5dd5fc0ba6" -dependencies = [ - "environmental", - "parity-scale-codec", - "sp-storage 22.0.0", -] - [[package]] name = "sp-genesis-builder" version = "0.8.0" @@ -27306,26 +27286,6 @@ dependencies = [ "static_assertions", ] -[[package]] -name = "sp-runtime-interface" -version = "29.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51e83d940449837a8b2a01b4d877dd22d896fd14d3d3ade875787982da994a33" -dependencies = [ - "bytes", - "impl-trait-for-tuples", - "parity-scale-codec", - "polkavm-derive 0.9.1", - "primitive-types 0.13.1", - "sp-externalities 0.30.0", - "sp-runtime-interface-proc-macro 18.0.0", - "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sp-storage 22.0.0", - "sp-tracing 17.0.1", - "sp-wasm-interface 21.0.1", - "static_assertions", -] - [[package]] name = "sp-runtime-interface-proc-macro" version = "11.0.0" @@ -27656,19 +27616,6 @@ dependencies = [ "sp-debug-derive 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "sp-storage" -version = "22.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee3b70ca340e41cde9d2e069d354508a6e37a6573d66f7cc38f11549002f64ec" -dependencies = [ - "impl-serde 0.5.0", - "parity-scale-codec", - "ref-cast", - "serde", - "sp-debug-derive 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "sp-test-primitives" version = "2.0.0" @@ -32338,9 +32285,9 @@ dependencies = [ [[package]] name = "zombienet-configuration" -version = "0.2.24" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03caa9f916aedb12e8443521c87604fe54fbde163a58018780108d86761310dc" +checksum = "5ced2fca1322821431f03d06dcf2ea74d3a7369760b6c587b372de6eada3ce43" dependencies = [ "anyhow", "lazy_static", @@ -32352,16 +32299,15 @@ dependencies = [ "thiserror", "tokio", "toml 0.8.19", - "tracing", "url", "zombienet-support", ] [[package]] name = "zombienet-orchestrator" -version = "0.2.24" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8330f46e4584a306ed567702307a697b8a2771681233548263f5bc3f639fcdec" +checksum = "86ecd17133c3129547b6472591b5e58d4aee1fc63c965a3418fd56d33a8a4e82" dependencies = [ "anyhow", "async-trait", @@ -32377,7 +32323,7 @@ dependencies = [ "serde", "serde_json", "sha2 0.10.8", - "sp-core 35.0.0", + "sp-core 34.0.0", "subxt", "subxt-signer", "thiserror", @@ -32392,9 +32338,9 @@ dependencies = [ [[package]] name = "zombienet-prom-metrics-parser" -version = "0.2.24" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a52a796a1521cf6420cc6384eac9ef25a146d453b568969774af643f3ecdc97" +checksum = "23702db0819a050c8a0130a769b105695137020a64207b4597aa021f06924552" dependencies = [ "pest", "pest_derive", @@ -32403,9 +32349,9 @@ dependencies = [ [[package]] name = "zombienet-provider" -version = "0.2.24" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7121ed12016baf318afdcaa96e59d134a3299f40ad5cb67fa6e8ae561db97d26" +checksum = "83e903843c62cd811e7730ccc618dcd14444d20e8aadfcd7d7561c7b47d8f984" dependencies = [ "anyhow", "async-trait", @@ -32434,9 +32380,9 @@ dependencies = [ [[package]] name = "zombienet-sdk" -version = "0.2.24" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "732a89935216d4cde1e538075af2f9e0e974e49895004694ab113c7040725ae5" +checksum = "e457b12c8fdc7003c12dd56855da09812ac11dd232e4ec01acccb2899fe05e44" dependencies = [ "async-trait", "futures", @@ -32452,9 +32398,9 @@ dependencies = [ [[package]] name = "zombienet-support" -version = "0.2.24" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f0c215aa994335125b75f9ad7c227a4ae6c281c074a6e6a42800f2fdfa59c8b" +checksum = "43547d65b19a92cf0ee44380239d82ef345e7d26f7b04b9e0ecf48496af6346b" dependencies = [ "anyhow", "async-trait", diff --git a/Cargo.toml b/Cargo.toml index ba8af51c3a567..5fd0384f8e311 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -419,6 +419,8 @@ members = [ "substrate/frame/session/benchmarking", "substrate/frame/society", "substrate/frame/staking", + "substrate/frame/staking/ah-client", + "substrate/frame/staking/rc-client", "substrate/frame/staking/reward-curve", "substrate/frame/staking/reward-fn", "substrate/frame/staking/runtime-api", @@ -996,6 +998,8 @@ pallet-session-benchmarking = { path = "substrate/frame/session/benchmarking", d pallet-skip-feeless-payment = { path = "substrate/frame/transaction-payment/skip-feeless-payment", default-features = false } pallet-society = { path = "substrate/frame/society", default-features = false } pallet-staking = { path = "substrate/frame/staking", default-features = false } +pallet-staking-ah-client = { path = "substrate/frame/staking/ah-client", default-features = false } +pallet-staking-rc-client = { path = "substrate/frame/staking/rc-client", default-features = false } pallet-staking-reward-curve = { path = "substrate/frame/staking/reward-curve", default-features = false } pallet-staking-reward-fn = { path = "substrate/frame/staking/reward-fn", default-features = false } pallet-staking-runtime-api = { path = "substrate/frame/staking/runtime-api", default-features = false } diff --git a/prdoc/pr_7357.prdoc b/prdoc/pr_7357.prdoc new file mode 100644 index 0000000000000..26e594c4373f2 --- /dev/null +++ b/prdoc/pr_7357.prdoc @@ -0,0 +1,17 @@ +title: Implementation of `ah-client` and `rc-client` staking pallets +doc: +- audience: Runtime Dev + description: |- + This PR introduces the initial structure for `pallet-ah-client` and `pallet-rc-client`. These + pallets will reside on the relay chain and AssetHub, respectively, and will manage the interaction + between `pallet-session` on the relay chain and `pallet-staking` on AssetHub. + Both pallets are experimental and not intended for production use. +crates: +- name: pallet-staking-ah-client + bump: major +- name: pallet-staking-rc-client + bump: major +- name: pallet-election-provider-multi-block + bump: minor +- name: pallet-staking + bump: major diff --git a/substrate/frame/election-provider-multi-block/src/lib.rs b/substrate/frame/election-provider-multi-block/src/lib.rs index 355f117bc4573..ea30fb239aee3 100644 --- a/substrate/frame/election-provider-multi-block/src/lib.rs +++ b/substrate/frame/election-provider-multi-block/src/lib.rs @@ -66,7 +66,7 @@ //! //! ## Pagination //! -//! Most of the external APIs of this pallet are paginated. All pagination follow a patter where if +//! Most of the external APIs of this pallet are paginated. All pagination follow a pattern where if //! `N` pages exist, the first paginated call is `function(N-1)` and the last one is `function(0)`. //! For example, with 3 pages, the `elect` of [`ElectionProvider`] is expected to be called as //! `elect(2) -> elect(1) -> elect(0)`. In essence, calling a paginated function with index 0 is diff --git a/substrate/frame/staking/ah-client/Cargo.toml b/substrate/frame/staking/ah-client/Cargo.toml new file mode 100644 index 0000000000000..480f589f317f2 --- /dev/null +++ b/substrate/frame/staking/ah-client/Cargo.toml @@ -0,0 +1,67 @@ +[package] +name = "pallet-staking-ah-client" +description = "Pallet handling the communication with staking-rc-client. It's role is to glue the staking pallet (on AssetHub chain) and session pallet (on Relay Chain) in a transparent way." +license = "Apache-2.0" +version = "0.1.0" +edition.workspace = true +authors.workspace = true +repository.workspace = true +publish = false + +[dependencies] +codec = { workspace = true, features = ["derive"] } +frame-support = { workspace = true } +frame-system = { workspace = true } +log = { workspace = true } +pallet-authorship = { workspace = true } +pallet-session = { features = ["historical"], workspace = true } +pallet-staking = { workspace = true } +pallet-staking-rc-client = { workspace = true } +polkadot-primitives = { workspace = true } +polkadot-runtime-parachains = { workspace = true } +scale-info = { workspace = true, features = ["derive"] } +sp-core = { workspace = true } +sp-runtime = { workspace = true } +sp-staking = { workspace = true } +xcm = { workspace = true } + +[features] +default = ["std"] +std = [ + "codec/std", + "frame-support/std", + "frame-system/std", + "log/std", + "pallet-authorship/std", + "pallet-session/std", + "pallet-staking-rc-client/std", + "pallet-staking/std", + "polkadot-primitives/std", + "polkadot-runtime-parachains/std", + "scale-info/std", + "sp-core/std", + "sp-runtime/std", + "sp-staking/std", + "xcm/std", +] +runtime-benchmarks = [ + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "pallet-staking-rc-client/runtime-benchmarks", + "pallet-staking/runtime-benchmarks", + "polkadot-primitives/runtime-benchmarks", + "polkadot-runtime-parachains/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", + "sp-staking/runtime-benchmarks", + "xcm/runtime-benchmarks", +] +try-runtime = [ + "frame-support/try-runtime", + "frame-system/try-runtime", + "pallet-authorship/try-runtime", + "pallet-session/try-runtime", + "pallet-staking-rc-client/try-runtime", + "pallet-staking/try-runtime", + "polkadot-runtime-parachains/try-runtime", + "sp-runtime/try-runtime", +] diff --git a/substrate/frame/staking/ah-client/src/lib.rs b/substrate/frame/staking/ah-client/src/lib.rs new file mode 100644 index 0000000000000..85fe8f88170a7 --- /dev/null +++ b/substrate/frame/staking/ah-client/src/lib.rs @@ -0,0 +1,326 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! This pallet is intended to be used on a relay chain and to communicate with its counterpart on +//! AssetHub (or a similar network) named `pallet-staking-rc-client`. +//! +//! This pallet serves as an interface between the staking pallet on AssetHub and the session pallet +//! on the relay chain. From the relay chain to AssetHub, its responsibilities are to send +//! information about session changes (start and end) and to report offenses. From AssetHub to the +//! relay chain, it receives information about the potentially new validator set for the session. +//! +//! All the communication between the two pallets is performed with XCM messages. + +#![cfg_attr(not(feature = "std"), no_std)] + +extern crate alloc; + +use alloc::vec::Vec; +use frame_support::pallet_prelude::*; +use pallet_staking_rc_client::Offence; +use sp_core::crypto::AccountId32; +use sp_runtime::traits::Convert; +use sp_staking::{offence::OffenceDetails, Exposure, SessionIndex}; +use xcm::prelude::*; + +const LOG_TARGET: &str = "runtime::staking::ah-client"; + +/// `pallet-staking-rc-client` pallet index on AssetHub. Used to construct remote calls. +/// +/// The codec index must correspond to the index of `pallet-staking-rc-client` in the +/// `construct_runtime` of AssetHub. +#[derive(Encode, Decode)] +enum AssetHubRuntimePallets { + #[codec(index = 50)] + RcClient(StakingCalls), +} + +/// Call encoding for the calls needed from the Broker pallet. +#[derive(Encode, Decode)] +enum StakingCalls { + /// A session with the given index has started. + #[codec(index = 0)] + RelayChainSessionStart(SessionIndex), + // A session with the given index has ended. The block authors with their corresponding + // session points are provided. + #[codec(index = 1)] + RelayChainSessionEnd(SessionIndex, Vec<(AccountId32, u32)>), + /// Report one or more offences. + #[codec(index = 2)] + NewRelayChainOffences(SessionIndex, Vec), +} + +#[frame_support::pallet(dev_mode)] +pub mod pallet { + use crate::*; + use alloc::vec; + use core::result; + use frame_system::pallet_prelude::*; + use pallet_session::historical; + use pallet_staking::ExposureOf; + use polkadot_primitives::Id as ParaId; + use polkadot_runtime_parachains::origin::{ensure_parachain, Origin}; + use sp_runtime::Perbill; + use sp_staking::{offence::OnOffenceHandler, SessionIndex}; + + const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); + + /// The balance type of this pallet. + pub type BalanceOf = ::CurrencyBalance; + + // `Exposure>` will be removed. This type alias exists only to + // suppress clippy warnings. + type ElectedValidatorSet = Vec<( + ::AccountId, + Exposure<::AccountId, BalanceOf>, + )>; + + #[pallet::pallet] + #[pallet::storage_version(STORAGE_VERSION)] + pub struct Pallet(_); + + // TODO: should contain some initial state, otherwise starting from genesis won't work + #[pallet::storage] + pub type ValidatorSet = StorageValue< + _, + Option>)>>, + ValueQuery, + >; + + /// Keeps track of the session points for each block author in the current session. + #[pallet::storage] + pub type BlockAuthors = StorageMap<_, Twox64Concat, AccountId32, u32, ValueQuery>; + + #[pallet::config] + pub trait Config: frame_system::Config { + type RuntimeOrigin: From<::RuntimeOrigin> + + Into::RuntimeOrigin>>; + /// Just the `Currency::Balance` type; we have this item to allow us to constrain it to + /// `From`. + type CurrencyBalance: sp_runtime::traits::AtLeast32BitUnsigned + + codec::FullCodec + + Copy + + MaybeSerializeDeserialize + + core::fmt::Debug + + Default + + From + + TypeInfo + + Send + + Sync + + MaxEncodedLen; + /// The ParaId of the AssetHub. + #[pallet::constant] + type AssetHubId: Get; + /// The XCM sender. + type SendXcm: SendXcm; + } + + #[pallet::error] + pub enum Error { + /// The ParaId making the call is not AssetHub. + NotAssetHub, + } + + #[pallet::call] + impl Pallet { + #[pallet::call_index(0)] + // #[pallet::weight(T::WeightInfo::new_validators())] // TODO + pub fn new_validator_set( + origin: OriginFor, + new_validator_set: ElectedValidatorSet, + ) -> DispatchResult { + // Ignore requests not coming from the AssetHub or root. + Self::ensure_root_or_para(origin, ::AssetHubId::get().into())?; + + // Save the validator set. We don't care if there is a validator set which was not used. + ValidatorSet::::put(Some(new_validator_set)); + + Ok(()) + } + } + + impl historical::SessionManager>> + for Pallet + { + fn new_session(_: sp_staking::SessionIndex) -> Option> { + // If there is a new validator set - return it. Otherwise return `None`. + ValidatorSet::::take() + } + + fn new_session_genesis( + _: SessionIndex, + ) -> Option>)>> { + ValidatorSet::::take() + } + + fn start_session(start_index: SessionIndex) { + >::start_session(start_index) + } + + fn end_session(end_index: SessionIndex) { + >::end_session(end_index) + } + } + + impl pallet_session::SessionManager for Pallet { + fn new_session(_: u32) -> Option::AccountId>> { + // Doesn't do anything because all the logic is handled in `historical::SessionManager` + // implementation + defensive!("new_session should not be called"); + None + } + + fn end_session(session_index: u32) { + let authors = BlockAuthors::::iter().collect::>(); + // The maximum number of block authors is `num_cores * max_validators_per_core` (both + // are parameters from [`SchedulerParams`]). + let _ = BlockAuthors::::clear(u32::MAX, None); + + let message = Xcm(vec![ + Instruction::UnpaidExecution { + weight_limit: WeightLimit::Unlimited, + check_origin: None, + }, + mk_asset_hub_call(StakingCalls::RelayChainSessionEnd(session_index, authors)), + ]); + + if let Err(err) = send_xcm::( + Location::new(0, [Junction::Parachain(T::AssetHubId::get())]), + message, + ) { + log::error!(target: LOG_TARGET, "Sending `RelayChainSessionEnd` to AssetHub failed: {:?}", err); + } + } + + fn start_session(session_index: u32) { + let message = Xcm(vec![ + Instruction::UnpaidExecution { + weight_limit: WeightLimit::Unlimited, + check_origin: None, + }, + mk_asset_hub_call(StakingCalls::RelayChainSessionStart(session_index)), + ]); + if let Err(err) = send_xcm::( + Location::new(0, [Junction::Parachain(T::AssetHubId::get())]), + message, + ) { + log::error!(target: LOG_TARGET, "Sending `RelayChainSessionStart` to AssetHub failed: {:?}", err); + } + } + } + + impl pallet_authorship::EventHandler> for Pallet + where + T: Config + pallet_authorship::Config + pallet_session::Config + Config, + T::AccountId: Into, + { + // Notes the authored block in `BlockAuthors`. + fn note_author(author: T::AccountId) { + BlockAuthors::::mutate(author.into(), |block_count| { + *block_count += 1; + }); + } + } + + impl + OnOffenceHandler, Weight> + for Pallet + where + T: pallet_session::Config::AccountId>, + T: pallet_session::historical::Config< + FullIdentification = Exposure<::AccountId, BalanceOf>, + FullIdentificationOf = ExposureOf, + >, + T::SessionHandler: pallet_session::SessionHandler<::AccountId>, + T::SessionManager: pallet_session::SessionManager<::AccountId>, + T::ValidatorIdOf: Convert< + ::AccountId, + Option<::AccountId>, + >, + T::AccountId: Into, + { + fn on_offence( + offenders: &[OffenceDetails< + T::AccountId, + pallet_session::historical::IdentificationTuple, + >], + slash_fraction: &[Perbill], + slash_session: SessionIndex, + ) -> Weight { + let offenders_and_slashes = offenders + .iter() + .cloned() + .zip(slash_fraction) + .map(|(offence, fraction)| { + Offence::new( + offence.offender.0.into(), + offence.reporters.into_iter().map(|r| r.into()).collect(), + *fraction, + ) + }) + .collect::>(); + + // send the offender immediately over xcm + let message = Xcm(vec![ + Instruction::UnpaidExecution { + weight_limit: WeightLimit::Unlimited, + check_origin: None, + }, + mk_asset_hub_call(StakingCalls::NewRelayChainOffences( + slash_session, + offenders_and_slashes, + )), + ]); + if let Err(err) = send_xcm::( + Location::new(0, [Junction::Parachain(T::AssetHubId::get())]), + message, + ) { + log::error!(target: LOG_TARGET, "Sending `NewRelayChainOffences` to AssetHub failed: {:?}", + err); + } + + Weight::zero() + } + } + + impl Pallet { + /// Ensure the origin is one of Root or the `para` itself. + fn ensure_root_or_para( + origin: ::RuntimeOrigin, + id: ParaId, + ) -> DispatchResult { + if let Ok(caller_id) = + ensure_parachain(::RuntimeOrigin::from(origin.clone())) + { + // Check if matching para id... + ensure!(caller_id == id, Error::::NotAssetHub); + } else { + // Check if root... + ensure_root(origin.clone())?; + } + Ok(()) + } + } + + fn mk_asset_hub_call(call: StakingCalls) -> Instruction<()> { + Instruction::Transact { + origin_kind: OriginKind::Superuser, + fallback_max_weight: None, + call: AssetHubRuntimePallets::RcClient(call).encode().into(), + } + } +} diff --git a/substrate/frame/staking/rc-client/Cargo.toml b/substrate/frame/staking/rc-client/Cargo.toml new file mode 100644 index 0000000000000..0380cb864250b --- /dev/null +++ b/substrate/frame/staking/rc-client/Cargo.toml @@ -0,0 +1,46 @@ +[package] +name = "pallet-staking-rc-client" +description = "Pallet handling the communication with staking-ah-client. It's role is to glue the staking pallet (on AssetHub chain) and session pallet (on Relay Chain) in a transparent way." +license = "Apache-2.0" +version = "0.1.0" +edition.workspace = true +authors.workspace = true +repository.workspace = true +publish = false + +[dependencies] +codec = { workspace = true, features = ["derive"] } +frame-support = { workspace = true } +frame-system = { workspace = true } +log = { workspace = true } +scale-info = { workspace = true, features = ["derive"] } +sp-core = { workspace = true } +sp-runtime = { features = ["serde"], workspace = true } +sp-staking = { features = ["serde"], workspace = true } +xcm = { workspace = true } + +[features] +default = ["std"] +std = [ + "codec/std", + "frame-support/std", + "frame-system/std", + "log/std", + "scale-info/std", + "sp-core/std", + "sp-runtime/std", + "sp-staking/std", + "xcm/std", +] +runtime-benchmarks = [ + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", + "sp-staking/runtime-benchmarks", + "xcm/runtime-benchmarks", +] +try-runtime = [ + "frame-support/try-runtime", + "frame-system/try-runtime", + "sp-runtime/try-runtime", +] diff --git a/substrate/frame/staking/rc-client/src/lib.rs b/substrate/frame/staking/rc-client/src/lib.rs new file mode 100644 index 0000000000000..dc6c0b7e5c6fc --- /dev/null +++ b/substrate/frame/staking/rc-client/src/lib.rs @@ -0,0 +1,181 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! This pallet is intended to be used on AssetHub. It provides extrinsics used by +//! `pallet-staking-ah-client` and serves as an interface between the relay chain and the staking +//! pallet on AssetHub. + +#![cfg_attr(not(feature = "std"), no_std)] + +extern crate alloc; + +use alloc::vec::Vec; +use frame_support::pallet_prelude::*; +use sp_core::crypto::AccountId32; +use sp_runtime::Perbill; +use sp_staking::SessionIndex; +use xcm::prelude::*; + +const LOG_TARGET: &str = "runtime::staking::rc-client"; + +// Provides to the pallet a validator set produced by an election or other similar mechanism. +pub trait ElectionResultHandler { + fn handle_election_result(result: Vec); +} + +// API provided by the staking pallet. +pub trait StakingApi { + /// New session with index `start_index` has started on the relay chain. + fn on_relay_chain_session_start(start_index: SessionIndex); + /// A session with index `end_index` has ended on the relay chain. The block authors and their + /// corresponding session points are reported. + fn on_relay_chain_session_end(end_index: SessionIndex, block_authors: Vec<(AccountId32, u32)>); + /// Report one or more offences on the relay chain. + fn on_new_offences(offences: Vec); +} + +/// `pallet-staking-ah-client` pallet index on Relay chain. Used to construct remote calls. +/// +/// The codec index must correspond to the index of `pallet-staking-ah-client` in the +/// `construct_runtime` of the Relay chain. +#[derive(Encode, Decode)] +enum RelayChainRuntimePallets { + #[codec(index = 50)] + AhClient(SessionCalls), +} + +/// Call encoding for the calls needed from the pallet. +#[derive(Encode, Decode)] +enum SessionCalls { + #[codec(index = 0)] + NewValidatorSet(Vec), +} + +// An offence on the relay chain. Based on [`sp_staking::offence::OffenceDetails`]. +#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo)] +pub struct Offence { + offender: AccountId32, + reporters: Vec, + slash_fraction: Perbill, +} + +impl Offence { + pub fn new( + offender: AccountId32, + reporters: Vec, + slash_fraction: Perbill, + ) -> Self { + Self { offender, reporters, slash_fraction } + } +} + +#[frame_support::pallet(dev_mode)] +pub mod pallet { + use super::*; + use alloc::vec; + use frame_system::pallet_prelude::*; + + /// The in-code storage version. + const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); + + #[pallet::pallet] + #[pallet::storage_version(STORAGE_VERSION)] + pub struct Pallet(_); + + #[pallet::config] + pub trait Config: frame_system::Config { + type AdminOrigin: EnsureOrigin; + /// A stable ID for a validator. + type ValidatorId: Member + + Parameter + + MaybeSerializeDeserialize + + MaxEncodedLen + + TryFrom; + + /// Handler for staking calls + type StakingApi: StakingApi; + /// The XCM sender. + type SendXcm: SendXcm; + } + + impl> ElectionResultHandler for Pallet { + fn handle_election_result(result: Vec) { + let new_validator_set = result.into_iter().map(Into::into).collect::>(); + + let message = Xcm(vec![ + Instruction::UnpaidExecution { + weight_limit: WeightLimit::Unlimited, + check_origin: None, + }, + mk_relay_chain_call(SessionCalls::NewValidatorSet(new_validator_set)), + ]); + + if let Err(err) = send_xcm::(Location::new(1, Here), message) { + log::error!(target: LOG_TARGET, "Sending `NewValidators` to relay chain failed: {:?}", err); + } + } + } + + #[pallet::call] + impl Pallet { + /// Called to indicate the start of a new session on the relay chain. + #[pallet::call_index(0)] + // #[pallet::weight(T::WeightInfo::end_session())] // TODO + pub fn relay_chain_session_start( + origin: OriginFor, + start_index: SessionIndex, + ) -> DispatchResult { + T::AdminOrigin::ensure_origin_or_root(origin)?; + T::StakingApi::on_relay_chain_session_start(start_index); + Ok(()) + } + + /// Called to indicate the end of a session on the relay chain. Accepts the session id and + /// the block authors with their corresponding session points for the finished session. + #[pallet::call_index(1)] + // #[pallet::weight(T::WeightInfo::end_session())] // TODO + pub fn relay_chain_session_end( + origin: OriginFor, + end_index: SessionIndex, + block_authors: Vec<(AccountId32, u32)>, + ) -> DispatchResult { + T::AdminOrigin::ensure_origin_or_root(origin)?; + T::StakingApi::on_relay_chain_session_end(end_index, block_authors); + Ok(()) + } + + /// Called to report one or more new offenses on the relay chain. + #[pallet::call_index(2)] + // #[pallet::weight(T::WeightInfo::end_session())] // TODO + pub fn new_relay_chain_offence( + origin: OriginFor, + offences: Vec, + ) -> DispatchResult { + T::AdminOrigin::ensure_origin_or_root(origin)?; + T::StakingApi::on_new_offences(offences); + Ok(()) + } + } + + fn mk_relay_chain_call(call: SessionCalls) -> Instruction<()> { + Instruction::Transact { + origin_kind: OriginKind::Superuser, + fallback_max_weight: None, + call: RelayChainRuntimePallets::AhClient(call).encode().into(), + } + } +} diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 8ca018c7d8b41..00b6942d19d71 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -518,6 +518,12 @@ impl Pallet { frame_support::print("Warning: A session appears to have been skipped."); Self::start_era(start_session); } + + // trigger election in the last session of the era + if start_session + 1 == next_active_era_start_session_index { + // Self::trigger_election(); + todo!() + } } // disable all offending validators that have been disabled for the whole era diff --git a/umbrella/Cargo.toml b/umbrella/Cargo.toml index 80b72febfb598..25645bd058850 100644 --- a/umbrella/Cargo.toml +++ b/umbrella/Cargo.toml @@ -135,6 +135,8 @@ std = [ "pallet-session?/std", "pallet-skip-feeless-payment?/std", "pallet-society?/std", + "pallet-staking-ah-client?/std", + "pallet-staking-rc-client?/std", "pallet-staking-reward-fn?/std", "pallet-staking-runtime-api?/std", "pallet-staking?/std", @@ -322,6 +324,8 @@ runtime-benchmarks = [ "pallet-session-benchmarking?/runtime-benchmarks", "pallet-skip-feeless-payment?/runtime-benchmarks", "pallet-society?/runtime-benchmarks", + "pallet-staking-ah-client?/runtime-benchmarks", + "pallet-staking-rc-client?/runtime-benchmarks", "pallet-staking?/runtime-benchmarks", "pallet-state-trie-migration?/runtime-benchmarks", "pallet-sudo?/runtime-benchmarks", @@ -461,6 +465,8 @@ try-runtime = [ "pallet-session?/try-runtime", "pallet-skip-feeless-payment?/try-runtime", "pallet-society?/try-runtime", + "pallet-staking-ah-client?/try-runtime", + "pallet-staking-rc-client?/try-runtime", "pallet-staking?/try-runtime", "pallet-state-trie-migration?/try-runtime", "pallet-statement?/try-runtime", @@ -549,7 +555,7 @@ with-tracing = [ "sp-tracing?/with-tracing", "sp-tracing?/with-tracing", ] -runtime-full = ["assets-common", "binary-merkle-tree", "bp-header-chain", "bp-messages", "bp-parachains", "bp-polkadot", "bp-polkadot-core", "bp-relayers", "bp-runtime", "bp-test-utils", "bp-xcm-bridge-hub", "bp-xcm-bridge-hub-router", "bridge-hub-common", "bridge-runtime-common", "cumulus-pallet-aura-ext", "cumulus-pallet-dmp-queue", "cumulus-pallet-parachain-system", "cumulus-pallet-parachain-system-proc-macro", "cumulus-pallet-session-benchmarking", "cumulus-pallet-solo-to-para", "cumulus-pallet-weight-reclaim", "cumulus-pallet-xcm", "cumulus-pallet-xcmp-queue", "cumulus-ping", "cumulus-primitives-aura", "cumulus-primitives-core", "cumulus-primitives-parachain-inherent", "cumulus-primitives-proof-size-hostfunction", "cumulus-primitives-storage-weight-reclaim", "cumulus-primitives-timestamp", "cumulus-primitives-utility", "frame-benchmarking", "frame-benchmarking-pallet-pov", "frame-election-provider-solution-type", "frame-election-provider-support", "frame-executive", "frame-metadata-hash-extension", "frame-support", "frame-support-procedural", "frame-support-procedural-tools-derive", "frame-system", "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", "pallet-alliance", "pallet-asset-conversion", "pallet-asset-conversion-ops", "pallet-asset-conversion-tx-payment", "pallet-asset-rate", "pallet-asset-rewards", "pallet-asset-tx-payment", "pallet-assets", "pallet-assets-freezer", "pallet-atomic-swap", "pallet-aura", "pallet-authority-discovery", "pallet-authorship", "pallet-babe", "pallet-bags-list", "pallet-balances", "pallet-beefy", "pallet-beefy-mmr", "pallet-bounties", "pallet-bridge-grandpa", "pallet-bridge-messages", "pallet-bridge-parachains", "pallet-bridge-relayers", "pallet-broker", "pallet-child-bounties", "pallet-collator-selection", "pallet-collective", "pallet-collective-content", "pallet-contracts", "pallet-contracts-proc-macro", "pallet-contracts-uapi", "pallet-conviction-voting", "pallet-core-fellowship", "pallet-delegated-staking", "pallet-democracy", "pallet-dev-mode", "pallet-election-provider-multi-block", "pallet-election-provider-multi-phase", "pallet-election-provider-support-benchmarking", "pallet-elections-phragmen", "pallet-fast-unstake", "pallet-glutton", "pallet-grandpa", "pallet-identity", "pallet-im-online", "pallet-indices", "pallet-insecure-randomness-collective-flip", "pallet-lottery", "pallet-membership", "pallet-message-queue", "pallet-migrations", "pallet-mixnet", "pallet-mmr", "pallet-multisig", "pallet-nft-fractionalization", "pallet-nfts", "pallet-nfts-runtime-api", "pallet-nis", "pallet-node-authorization", "pallet-nomination-pools", "pallet-nomination-pools-benchmarking", "pallet-nomination-pools-runtime-api", "pallet-offences", "pallet-offences-benchmarking", "pallet-paged-list", "pallet-parameters", "pallet-preimage", "pallet-proxy", "pallet-ranked-collective", "pallet-recovery", "pallet-referenda", "pallet-remark", "pallet-revive", "pallet-revive-proc-macro", "pallet-revive-uapi", "pallet-root-offences", "pallet-root-testing", "pallet-safe-mode", "pallet-salary", "pallet-scheduler", "pallet-scored-pool", "pallet-session", "pallet-session-benchmarking", "pallet-skip-feeless-payment", "pallet-society", "pallet-staking", "pallet-staking-reward-curve", "pallet-staking-reward-fn", "pallet-staking-runtime-api", "pallet-state-trie-migration", "pallet-statement", "pallet-sudo", "pallet-timestamp", "pallet-tips", "pallet-transaction-payment", "pallet-transaction-payment-rpc-runtime-api", "pallet-transaction-storage", "pallet-treasury", "pallet-tx-pause", "pallet-uniques", "pallet-utility", "pallet-verify-signature", "pallet-vesting", "pallet-whitelist", "pallet-xcm", "pallet-xcm-benchmarks", "pallet-xcm-bridge-hub", "pallet-xcm-bridge-hub-router", "parachains-common", "polkadot-core-primitives", "polkadot-parachain-primitives", "polkadot-primitives", "polkadot-runtime-common", "polkadot-runtime-metrics", "polkadot-runtime-parachains", "polkadot-sdk-frame", "sc-chain-spec-derive", "sc-tracing-proc-macro", "slot-range-helper", "snowbridge-beacon-primitives", "snowbridge-core", "snowbridge-ethereum", "snowbridge-outbound-queue-merkle-tree", "snowbridge-outbound-queue-runtime-api", "snowbridge-pallet-ethereum-client", "snowbridge-pallet-ethereum-client-fixtures", "snowbridge-pallet-inbound-queue", "snowbridge-pallet-inbound-queue-fixtures", "snowbridge-pallet-outbound-queue", "snowbridge-pallet-system", "snowbridge-router-primitives", "snowbridge-runtime-common", "snowbridge-system-runtime-api", "sp-api", "sp-api-proc-macro", "sp-application-crypto", "sp-arithmetic", "sp-authority-discovery", "sp-block-builder", "sp-consensus-aura", "sp-consensus-babe", "sp-consensus-beefy", "sp-consensus-grandpa", "sp-consensus-pow", "sp-consensus-slots", "sp-core", "sp-crypto-ec-utils", "sp-crypto-hashing", "sp-crypto-hashing-proc-macro", "sp-debug-derive", "sp-externalities", "sp-genesis-builder", "sp-inherents", "sp-io", "sp-keyring", "sp-keystore", "sp-metadata-ir", "sp-mixnet", "sp-mmr-primitives", "sp-npos-elections", "sp-offchain", "sp-runtime", "sp-runtime-interface", "sp-runtime-interface-proc-macro", "sp-session", "sp-staking", "sp-state-machine", "sp-statement-store", "sp-std", "sp-storage", "sp-timestamp", "sp-tracing", "sp-transaction-pool", "sp-transaction-storage-proof", "sp-trie", "sp-version", "sp-version-proc-macro", "sp-wasm-interface", "sp-weights", "staging-parachain-info", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", "substrate-bip39", "testnet-parachains-constants", "tracing-gum-proc-macro", "xcm-procedural", "xcm-runtime-apis"] +runtime-full = ["assets-common", "binary-merkle-tree", "bp-header-chain", "bp-messages", "bp-parachains", "bp-polkadot", "bp-polkadot-core", "bp-relayers", "bp-runtime", "bp-test-utils", "bp-xcm-bridge-hub", "bp-xcm-bridge-hub-router", "bridge-hub-common", "bridge-runtime-common", "cumulus-pallet-aura-ext", "cumulus-pallet-dmp-queue", "cumulus-pallet-parachain-system", "cumulus-pallet-parachain-system-proc-macro", "cumulus-pallet-session-benchmarking", "cumulus-pallet-solo-to-para", "cumulus-pallet-weight-reclaim", "cumulus-pallet-xcm", "cumulus-pallet-xcmp-queue", "cumulus-ping", "cumulus-primitives-aura", "cumulus-primitives-core", "cumulus-primitives-parachain-inherent", "cumulus-primitives-proof-size-hostfunction", "cumulus-primitives-storage-weight-reclaim", "cumulus-primitives-timestamp", "cumulus-primitives-utility", "frame-benchmarking", "frame-benchmarking-pallet-pov", "frame-election-provider-solution-type", "frame-election-provider-support", "frame-executive", "frame-metadata-hash-extension", "frame-support", "frame-support-procedural", "frame-support-procedural-tools-derive", "frame-system", "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", "pallet-alliance", "pallet-asset-conversion", "pallet-asset-conversion-ops", "pallet-asset-conversion-tx-payment", "pallet-asset-rate", "pallet-asset-rewards", "pallet-asset-tx-payment", "pallet-assets", "pallet-assets-freezer", "pallet-atomic-swap", "pallet-aura", "pallet-authority-discovery", "pallet-authorship", "pallet-babe", "pallet-bags-list", "pallet-balances", "pallet-beefy", "pallet-beefy-mmr", "pallet-bounties", "pallet-bridge-grandpa", "pallet-bridge-messages", "pallet-bridge-parachains", "pallet-bridge-relayers", "pallet-broker", "pallet-child-bounties", "pallet-collator-selection", "pallet-collective", "pallet-collective-content", "pallet-contracts", "pallet-contracts-proc-macro", "pallet-contracts-uapi", "pallet-conviction-voting", "pallet-core-fellowship", "pallet-delegated-staking", "pallet-democracy", "pallet-dev-mode", "pallet-election-provider-multi-block", "pallet-election-provider-multi-phase", "pallet-election-provider-support-benchmarking", "pallet-elections-phragmen", "pallet-fast-unstake", "pallet-glutton", "pallet-grandpa", "pallet-identity", "pallet-im-online", "pallet-indices", "pallet-insecure-randomness-collective-flip", "pallet-lottery", "pallet-membership", "pallet-message-queue", "pallet-migrations", "pallet-mixnet", "pallet-mmr", "pallet-multisig", "pallet-nft-fractionalization", "pallet-nfts", "pallet-nfts-runtime-api", "pallet-nis", "pallet-node-authorization", "pallet-nomination-pools", "pallet-nomination-pools-benchmarking", "pallet-nomination-pools-runtime-api", "pallet-offences", "pallet-offences-benchmarking", "pallet-paged-list", "pallet-parameters", "pallet-preimage", "pallet-proxy", "pallet-ranked-collective", "pallet-recovery", "pallet-referenda", "pallet-remark", "pallet-revive", "pallet-revive-proc-macro", "pallet-revive-uapi", "pallet-root-offences", "pallet-root-testing", "pallet-safe-mode", "pallet-salary", "pallet-scheduler", "pallet-scored-pool", "pallet-session", "pallet-session-benchmarking", "pallet-skip-feeless-payment", "pallet-society", "pallet-staking", "pallet-staking-ah-client", "pallet-staking-rc-client", "pallet-staking-reward-curve", "pallet-staking-reward-fn", "pallet-staking-runtime-api", "pallet-state-trie-migration", "pallet-statement", "pallet-sudo", "pallet-timestamp", "pallet-tips", "pallet-transaction-payment", "pallet-transaction-payment-rpc-runtime-api", "pallet-transaction-storage", "pallet-treasury", "pallet-tx-pause", "pallet-uniques", "pallet-utility", "pallet-verify-signature", "pallet-vesting", "pallet-whitelist", "pallet-xcm", "pallet-xcm-benchmarks", "pallet-xcm-bridge-hub", "pallet-xcm-bridge-hub-router", "parachains-common", "polkadot-core-primitives", "polkadot-parachain-primitives", "polkadot-primitives", "polkadot-runtime-common", "polkadot-runtime-metrics", "polkadot-runtime-parachains", "polkadot-sdk-frame", "sc-chain-spec-derive", "sc-tracing-proc-macro", "slot-range-helper", "snowbridge-beacon-primitives", "snowbridge-core", "snowbridge-ethereum", "snowbridge-outbound-queue-merkle-tree", "snowbridge-outbound-queue-runtime-api", "snowbridge-pallet-ethereum-client", "snowbridge-pallet-ethereum-client-fixtures", "snowbridge-pallet-inbound-queue", "snowbridge-pallet-inbound-queue-fixtures", "snowbridge-pallet-outbound-queue", "snowbridge-pallet-system", "snowbridge-router-primitives", "snowbridge-runtime-common", "snowbridge-system-runtime-api", "sp-api", "sp-api-proc-macro", "sp-application-crypto", "sp-arithmetic", "sp-authority-discovery", "sp-block-builder", "sp-consensus-aura", "sp-consensus-babe", "sp-consensus-beefy", "sp-consensus-grandpa", "sp-consensus-pow", "sp-consensus-slots", "sp-core", "sp-crypto-ec-utils", "sp-crypto-hashing", "sp-crypto-hashing-proc-macro", "sp-debug-derive", "sp-externalities", "sp-genesis-builder", "sp-inherents", "sp-io", "sp-keyring", "sp-keystore", "sp-metadata-ir", "sp-mixnet", "sp-mmr-primitives", "sp-npos-elections", "sp-offchain", "sp-runtime", "sp-runtime-interface", "sp-runtime-interface-proc-macro", "sp-session", "sp-staking", "sp-state-machine", "sp-statement-store", "sp-std", "sp-storage", "sp-timestamp", "sp-tracing", "sp-transaction-pool", "sp-transaction-storage-proof", "sp-trie", "sp-version", "sp-version-proc-macro", "sp-wasm-interface", "sp-weights", "staging-parachain-info", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", "substrate-bip39", "testnet-parachains-constants", "tracing-gum-proc-macro", "xcm-procedural", "xcm-runtime-apis"] runtime = [ "frame-benchmarking", "frame-benchmarking-pallet-pov", @@ -1281,6 +1287,16 @@ default-features = false optional = true path = "../substrate/frame/staking" +[dependencies.pallet-staking-ah-client] +default-features = false +optional = true +path = "../substrate/frame/staking/ah-client" + +[dependencies.pallet-staking-rc-client] +default-features = false +optional = true +path = "../substrate/frame/staking/rc-client" + [dependencies.pallet-staking-reward-curve] default-features = false optional = true diff --git a/umbrella/src/lib.rs b/umbrella/src/lib.rs index 79a4ed9960e45..2e2630da48a33 100644 --- a/umbrella/src/lib.rs +++ b/umbrella/src/lib.rs @@ -653,6 +653,16 @@ pub use pallet_society; #[cfg(feature = "pallet-staking")] pub use pallet_staking; +/// Pallet handling the communication with staking-rc-client. It's role is to glue the staking +/// pallet (on AssetHub chain) and session pallet (on Relay Chain) in a transparent way. +#[cfg(feature = "pallet-staking-ah-client")] +pub use pallet_staking_ah_client; + +/// Pallet handling the communication with staking-ah-client. It's role is to glue the staking +/// pallet (on AssetHub chain) and session pallet (on Relay Chain) in a transparent way. +#[cfg(feature = "pallet-staking-rc-client")] +pub use pallet_staking_rc_client; + /// Reward Curve for FRAME staking pallet. #[cfg(feature = "pallet-staking-reward-curve")] pub use pallet_staking_reward_curve;