mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-22 08:01:06 +00:00
[FRAME Core] New pallets: safe-mode and tx-pause (#12092)
* Add safe-mode Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Update pallet Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Add to kitchensink-runtime Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Spelling Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Rename to tx-pause Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Add SafeMode pallet Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * fmt Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Automatically disable safe-mode in on_init… Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Add permissionless enable+extend Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Add repay+slash stake methods Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Add docs Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Fix stakes storage Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Genesis config for safe-mode pallet Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Genesis config for safe-mode pallet Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Rename ExtrinsicName to FunctionName Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Origin variable duration Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Rename FunctionName -> CallName Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Rename and docs Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Pallet safe mode tests (#12148) * Add safe-mode mock runtime * Add safe-mode tests * Add ForceEnable- and ForceExtendOrigin * Start dummy benchmarks Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Tests for `pallet-tx-pause` (#12259) * mock added * tests added * dummy benchmarks started * rename to active/inactive tests broken, in progress * Runtime types, fix tests * WIP safe mode and tx pause {continued} (#12371) * test coverage on safe mode and tx pause * benchmarks & tests * tests passing, use FullNameOf to check tx-pause unfilterables * naming updates Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Set block number Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * dummy weights generated, safe mode * add repay_reservation call with RepaymentDelay per #10033 feature requirements * make call name optional to allow pausing pallets, handle `Contains` correctly for this throughout, doc comments started * move to full_name notation for all interfaces, last commit introduced 1 more storage read. * refactor is_paused * safe math on safe mode * Make stuff compile Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Compile Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Cleanup & renames Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Cleanup TxPause pallet Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Fix benches Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * fmt Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Refactor to fungibles::* and rename stuf Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Make compile Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Fix node config Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Typos Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Remove CausalHoldReason Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Refactor benchmarks and runtime configs Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Add traits Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Remove old code Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Cleanup safe-mode benches Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Update frame/safe-mode/Cargo.toml Co-authored-by: Liam Aharon <liam.aharon@hotmail.com> * Update frame/safe-mode/Cargo.toml Co-authored-by: Liam Aharon <liam.aharon@hotmail.com> * Docs Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Remove getters Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Update Cargo.lock Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Remove phantom Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Fix test Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Remove phantom Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Apply suggestions from code review Co-authored-by: Liam Aharon <liam.aharon@hotmail.com> * Use new as Origin benchmarking syntax Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Docs Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Fix node Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Fix tx-pause benches Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Renames * Remove duplicate test * Add docs * docs * Apply suggestions from code review Co-authored-by: Liam Aharon <liam.aharon@hotmail.com> Co-authored-by: Muharem Ismailov <ismailov.m.h@gmail.com> Co-authored-by: Gonçalo Pestana <g6pestana@gmail.com> * Cleanup tests * docs * Cleanup GenesisConfigs * Doc traits * Remove PauseTooLongNames * docs * Use V2 benchmarking Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Use RuntimeHoldReason * Fix kitchensink runtime * Fix CI Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Fix CI Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Review Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Rename Stake to Deposit Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Add docs Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Add Notify and test it Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Fix kitchensink Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Update frame/safe-mode/src/tests.rs Co-authored-by: Liam Aharon <liam.aharon@hotmail.com> * Update frame/safe-mode/src/tests.rs Co-authored-by: Liam Aharon <liam.aharon@hotmail.com> * Update frame/support/src/traits/safe_mode.rs Co-authored-by: Liam Aharon <liam.aharon@hotmail.com> * Update frame/support/src/traits/safe_mode.rs Co-authored-by: Liam Aharon <liam.aharon@hotmail.com> * Update frame/support/src/traits/safe_mode.rs Co-authored-by: Liam Aharon <liam.aharon@hotmail.com> * Update frame/support/src/traits/tx_pause.rs Co-authored-by: Liam Aharon <liam.aharon@hotmail.com> * Update frame/tx-pause/src/lib.rs Co-authored-by: Liam Aharon <liam.aharon@hotmail.com> * Update frame/tx-pause/src/lib.rs Co-authored-by: Liam Aharon <liam.aharon@hotmail.com> * Update frame/tx-pause/src/mock.rs Co-authored-by: Liam Aharon <liam.aharon@hotmail.com> * Update frame/support/src/traits/safe_mode.rs Co-authored-by: Liam Aharon <liam.aharon@hotmail.com> * Simplify code * Update frame/support/src/traits/safe_mode.rs Co-authored-by: Liam Aharon <liam.aharon@hotmail.com> * Update frame/support/src/traits/safe_mode.rs Co-authored-by: Liam Aharon <liam.aharon@hotmail.com> * Update frame/support/src/traits/safe_mode.rs Co-authored-by: Liam Aharon <liam.aharon@hotmail.com> * Fixup merge Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Make stuff compile Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Make tx-pause compile again Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Fix features Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Fix more features Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * ".git/.scripts/commands/bench/bench.sh" --subcommand=pallet --runtime=dev --target_dir=substrate --pallet=pallet_safe_mode * Update weights Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> --------- Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> Co-authored-by: Dan Shields <35669742+NukeManDan@users.noreply.github.com> Co-authored-by: Dan Shields <nukemandan@protonmail.com> Co-authored-by: Liam Aharon <liam.aharon@hotmail.com> Co-authored-by: Muharem Ismailov <ismailov.m.h@gmail.com> Co-authored-by: Gonçalo Pestana <g6pestana@gmail.com> Co-authored-by: command-bot <>
This commit is contained in:
committed by
GitHub
parent
46bd466e48
commit
3710edfedc
@@ -0,0 +1,277 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) 2022 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.
|
||||
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
#![deny(rustdoc::broken_intra_doc_links)]
|
||||
|
||||
mod benchmarking;
|
||||
pub mod mock;
|
||||
mod tests;
|
||||
pub mod weights;
|
||||
|
||||
use frame_support::{
|
||||
dispatch::GetDispatchInfo,
|
||||
pallet_prelude::*,
|
||||
traits::{CallMetadata, Contains, GetCallMetadata, IsSubType, IsType},
|
||||
DefaultNoBound,
|
||||
};
|
||||
use frame_system::pallet_prelude::*;
|
||||
use sp_runtime::{traits::Dispatchable, DispatchResult};
|
||||
use sp_std::{convert::TryInto, prelude::*};
|
||||
|
||||
pub use pallet::*;
|
||||
pub use weights::*;
|
||||
|
||||
/// The stringy name of a pallet from [`GetCallMetadata`] for [`Config::RuntimeCall`] variants.
|
||||
pub type PalletNameOf<T> = BoundedVec<u8, <T as Config>::MaxNameLen>;
|
||||
|
||||
/// The stringy name of a call (within a pallet) from [`GetCallMetadata`] for
|
||||
/// [`Config::RuntimeCall`] variants.
|
||||
pub type PalletCallNameOf<T> = BoundedVec<u8, <T as Config>::MaxNameLen>;
|
||||
|
||||
/// A fully specified pallet ([`PalletNameOf`]) and optional call ([`PalletCallNameOf`])
|
||||
/// to partially or fully specify an item a variant of a [`Config::RuntimeCall`].
|
||||
pub type RuntimeCallNameOf<T> = (PalletNameOf<T>, PalletCallNameOf<T>);
|
||||
|
||||
#[frame_support::pallet]
|
||||
pub mod pallet {
|
||||
use super::*;
|
||||
|
||||
#[pallet::pallet]
|
||||
pub struct Pallet<T>(PhantomData<T>);
|
||||
|
||||
#[pallet::config]
|
||||
pub trait Config: frame_system::Config {
|
||||
/// The overarching event type.
|
||||
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
|
||||
|
||||
/// The overarching call type.
|
||||
type RuntimeCall: Parameter
|
||||
+ Dispatchable<RuntimeOrigin = Self::RuntimeOrigin>
|
||||
+ GetDispatchInfo
|
||||
+ GetCallMetadata
|
||||
+ From<frame_system::Call<Self>>
|
||||
+ IsSubType<Call<Self>>
|
||||
+ IsType<<Self as frame_system::Config>::RuntimeCall>;
|
||||
|
||||
/// The only origin that can pause calls.
|
||||
type PauseOrigin: EnsureOrigin<Self::RuntimeOrigin>;
|
||||
|
||||
/// The only origin that can un-pause calls.
|
||||
type UnpauseOrigin: EnsureOrigin<Self::RuntimeOrigin>;
|
||||
|
||||
/// Contains all calls that cannot be paused.
|
||||
///
|
||||
/// The `TxMode` pallet cannot pause its own calls, and does not need to be explicitly
|
||||
/// added here.
|
||||
type WhitelistedCalls: Contains<RuntimeCallNameOf<Self>>;
|
||||
|
||||
/// Maximum length for pallet name and call name SCALE encoded string names.
|
||||
///
|
||||
/// TOO LONG NAMES WILL BE TREATED AS PAUSED.
|
||||
#[pallet::constant]
|
||||
type MaxNameLen: Get<u32>;
|
||||
|
||||
// Weight information for extrinsics in this pallet.
|
||||
type WeightInfo: WeightInfo;
|
||||
}
|
||||
|
||||
/// The set of calls that are explicitly paused.
|
||||
#[pallet::storage]
|
||||
pub type PausedCalls<T: Config> =
|
||||
StorageMap<_, Blake2_128Concat, RuntimeCallNameOf<T>, (), OptionQuery>;
|
||||
|
||||
#[pallet::error]
|
||||
pub enum Error<T> {
|
||||
/// The call is paused.
|
||||
IsPaused,
|
||||
|
||||
/// The call is unpaused.
|
||||
IsUnpaused,
|
||||
|
||||
/// The call is whitelisted and cannot be paused.
|
||||
Unpausable,
|
||||
|
||||
// The pallet or call does not exist in the runtime.
|
||||
NotFound,
|
||||
}
|
||||
|
||||
#[pallet::event]
|
||||
#[pallet::generate_deposit(pub(super) fn deposit_event)]
|
||||
pub enum Event<T: Config> {
|
||||
/// This pallet, or a specific call is now paused.
|
||||
CallPaused { full_name: RuntimeCallNameOf<T> },
|
||||
/// This pallet, or a specific call is now unpaused.
|
||||
CallUnpaused { full_name: RuntimeCallNameOf<T> },
|
||||
}
|
||||
|
||||
/// Configure the initial state of this pallet in the genesis block.
|
||||
#[pallet::genesis_config]
|
||||
#[derive(DefaultNoBound)]
|
||||
pub struct GenesisConfig<T: Config> {
|
||||
/// Initially paused calls.
|
||||
pub paused: Vec<RuntimeCallNameOf<T>>,
|
||||
}
|
||||
|
||||
#[pallet::genesis_build]
|
||||
impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
|
||||
fn build(&self) {
|
||||
for call in &self.paused {
|
||||
Pallet::<T>::ensure_can_pause(&call).expect("Genesis data is known good; qed");
|
||||
PausedCalls::<T>::insert(&call, ());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[pallet::call]
|
||||
impl<T: Config> Pallet<T> {
|
||||
/// Pause a call.
|
||||
///
|
||||
/// Can only be called by [`Config::PauseOrigin`].
|
||||
/// Emits an [`Event::CallPaused`] event on success.
|
||||
#[pallet::call_index(0)]
|
||||
#[pallet::weight(T::WeightInfo::pause())]
|
||||
pub fn pause(origin: OriginFor<T>, full_name: RuntimeCallNameOf<T>) -> DispatchResult {
|
||||
T::PauseOrigin::ensure_origin(origin)?;
|
||||
|
||||
Self::do_pause(full_name).map_err(Into::into)
|
||||
}
|
||||
|
||||
/// Un-pause a call.
|
||||
///
|
||||
/// Can only be called by [`Config::UnpauseOrigin`].
|
||||
/// Emits an [`Event::CallUnpaused`] event on success.
|
||||
#[pallet::call_index(1)]
|
||||
#[pallet::weight(T::WeightInfo::unpause())]
|
||||
pub fn unpause(origin: OriginFor<T>, ident: RuntimeCallNameOf<T>) -> DispatchResult {
|
||||
T::UnpauseOrigin::ensure_origin(origin)?;
|
||||
|
||||
Self::do_unpause(ident).map_err(Into::into)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Config> Pallet<T> {
|
||||
pub(crate) fn do_pause(ident: RuntimeCallNameOf<T>) -> Result<(), Error<T>> {
|
||||
Self::ensure_can_pause(&ident)?;
|
||||
PausedCalls::<T>::insert(&ident, ());
|
||||
Self::deposit_event(Event::CallPaused { full_name: ident });
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn do_unpause(ident: RuntimeCallNameOf<T>) -> Result<(), Error<T>> {
|
||||
Self::ensure_can_unpause(&ident)?;
|
||||
PausedCalls::<T>::remove(&ident);
|
||||
Self::deposit_event(Event::CallUnpaused { full_name: ident });
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Return whether this call is paused.
|
||||
pub fn is_paused(full_name: &RuntimeCallNameOf<T>) -> bool {
|
||||
if T::WhitelistedCalls::contains(full_name) {
|
||||
return false
|
||||
}
|
||||
|
||||
<PausedCalls<T>>::contains_key(full_name)
|
||||
}
|
||||
|
||||
/// Same as [`Self::is_paused`] but for inputs unbound by max-encoded-len.
|
||||
pub fn is_paused_unbound(pallet: Vec<u8>, call: Vec<u8>) -> bool {
|
||||
let pallet = PalletNameOf::<T>::try_from(pallet);
|
||||
let call = PalletCallNameOf::<T>::try_from(call);
|
||||
|
||||
match (pallet, call) {
|
||||
(Ok(pallet), Ok(call)) => Self::is_paused(&(pallet, call)),
|
||||
_ => true,
|
||||
}
|
||||
}
|
||||
|
||||
/// Ensure that this call can be paused.
|
||||
pub fn ensure_can_pause(full_name: &RuntimeCallNameOf<T>) -> Result<(), Error<T>> {
|
||||
// SAFETY: The `TxPause` pallet can never pause itself.
|
||||
if full_name.0.as_ref() == <Self as PalletInfoAccess>::name().as_bytes().to_vec() {
|
||||
return Err(Error::<T>::Unpausable)
|
||||
}
|
||||
|
||||
if T::WhitelistedCalls::contains(&full_name) {
|
||||
return Err(Error::<T>::Unpausable)
|
||||
}
|
||||
if Self::is_paused(&full_name) {
|
||||
return Err(Error::<T>::IsPaused)
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Ensure that this call can be un-paused.
|
||||
pub fn ensure_can_unpause(full_name: &RuntimeCallNameOf<T>) -> Result<(), Error<T>> {
|
||||
if Self::is_paused(&full_name) {
|
||||
// SAFETY: Everything that is paused, can be un-paused.
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::IsUnpaused)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: pallet::Config> Contains<<T as frame_system::Config>::RuntimeCall> for Pallet<T>
|
||||
where
|
||||
<T as frame_system::Config>::RuntimeCall: GetCallMetadata,
|
||||
{
|
||||
/// Return whether the call is allowed to be dispatched.
|
||||
fn contains(call: &<T as frame_system::Config>::RuntimeCall) -> bool {
|
||||
let CallMetadata { pallet_name, function_name } = call.get_call_metadata();
|
||||
!Pallet::<T>::is_paused_unbound(pallet_name.into(), function_name.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Config> frame_support::traits::TransactionPause for Pallet<T> {
|
||||
type CallIdentifier = RuntimeCallNameOf<T>;
|
||||
|
||||
fn is_paused(full_name: Self::CallIdentifier) -> bool {
|
||||
Self::is_paused(&full_name)
|
||||
}
|
||||
|
||||
fn can_pause(full_name: Self::CallIdentifier) -> bool {
|
||||
Self::ensure_can_pause(&full_name).is_ok()
|
||||
}
|
||||
|
||||
fn pause(
|
||||
full_name: Self::CallIdentifier,
|
||||
) -> Result<(), frame_support::traits::TransactionPauseError> {
|
||||
Self::do_pause(full_name).map_err(Into::into)
|
||||
}
|
||||
|
||||
fn unpause(
|
||||
full_name: Self::CallIdentifier,
|
||||
) -> Result<(), frame_support::traits::TransactionPauseError> {
|
||||
Self::do_unpause(full_name).map_err(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Config> From<Error<T>> for frame_support::traits::TransactionPauseError {
|
||||
fn from(err: Error<T>) -> Self {
|
||||
match err {
|
||||
Error::<T>::NotFound => Self::NotFound,
|
||||
Error::<T>::Unpausable => Self::Unpausable,
|
||||
Error::<T>::IsPaused => Self::AlreadyPaused,
|
||||
Error::<T>::IsUnpaused => Self::AlreadyUnpaused,
|
||||
_ => Self::Unknown,
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user