Skip to content
This repository has been archived by the owner on May 21, 2024. It is now read-only.

[Backport] #163 Lockdown-pallet to v0.9.40 #191

Merged
merged 4 commits into from
May 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions node/service/src/chain_spec/trappist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,7 @@ fn testnet_genesis(
phantom: Default::default(),
},
treasury: Default::default(),
lockdown_mode: Default::default(),
}
}

Expand Down Expand Up @@ -349,5 +350,6 @@ fn trappist_live_genesis(
phantom: Default::default(),
},
treasury: Default::default(),
lockdown_mode: Default::default(),
}
}
77 changes: 77 additions & 0 deletions pallets/lockdown-mode/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
[package]
name = "pallet-lockdown-mode"
version = "0.1.0"
description = "Trappist pallet for setting lockdown mode."
edition = "2021"
license = "Apache-2.0"
repository = "https://github.com/paritytech/trappist"

[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

[dependencies]
codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive",] }
scale-info = { version = "2.3.1", default-features = false, features = ["derive"] }
sp-runtime = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.40" }
sp-std = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.40" }
frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" }
frame-support = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" }
frame-system = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" }
cumulus-primitives-core = { git = "https://github.com/paritytech/cumulus", branch = "polkadot-v0.9.40", default-features = false }
pallet-assets = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" }
pallet-balances = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" }
log = "0.4.17"
xcm = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "release-v0.9.40" }

xcm-primitives = { path = "../../primitives/xcm", default-features = false }

[dev-dependencies]
sp-core = { version = "7.0.0", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" }
sp-io = { version = "7.0.0", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" }
sp-runtime = { version = "7.0.0", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" }
pallet-remark = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.40" }


xcm = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "release-v0.9.40" }
xcm-simulator = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "release-v0.9.40" }
xcm-executor = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "release-v0.9.40" }
xcm-builder = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "release-v0.9.40" }
pallet-xcm = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "release-v0.9.40" }
polkadot-core-primitives = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "release-v0.9.40" }
polkadot-runtime-parachains = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "release-v0.9.40" }
polkadot-parachain = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "release-v0.9.40" }

parachain-info = { git = "https://github.com/paritytech/cumulus", branch = "polkadot-v0.9.40", default-features = false }
parachains-common = { git = "https://github.com/paritytech/cumulus", branch = "polkadot-v0.9.40", default-features = false }
cumulus-pallet-dmp-queue = { git = "https://github.com/paritytech/cumulus", branch = "polkadot-v0.9.40", default-features = false }
cumulus-pallet-xcmp-queue = { git = "https://github.com/paritytech/cumulus", branch = "polkadot-v0.9.40", default-features = false }
cumulus-primitives-core = { git = "https://github.com/paritytech/cumulus", branch = "polkadot-v0.9.40", default-features = false }

[features]
default = ["std"]
std = [
"codec/std",
"sp-runtime/std",
"sp-std/std",
"pallet-assets/std",
"pallet-balances/std",
"frame-benchmarking/std",
"frame-support/std",
"frame-system/std",
"scale-info/std",
"xcm-primitives/std",
"xcm/std",
"xcm-executor/std",
"xcm-builder/std",
"pallet-xcm/std",
"polkadot-core-primitives/std",
"polkadot-runtime-parachains/std",
"polkadot-parachain/std",
"parachain-info/std",
"parachains-common/std",
"cumulus-pallet-dmp-queue/std",
"cumulus-pallet-xcmp-queue/std",
"cumulus-primitives-core/std",
]
runtime-benchmarks = ["frame-benchmarking/runtime-benchmarks"]
try-runtime = ["frame-support/try-runtime"]
41 changes: 41 additions & 0 deletions pallets/lockdown-mode/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Lockdown Mode Pallet

The Lockdown Mode Pallet is a Substrate module that provides functionality to lock down the runtime execution in a Substrate-based blockchain system. When the lockdown mode is activated, it filters out incoming calls and messages to ensure that only authorized actions are allowed.

## Overview

This pallet the governance of the chain to activate or deactivate a lockdown mode. When the lockdown mode is activated, incoming runtime calls and downward messages are filtered based on a preconfigured filter. Additionally, it suspends the execution of XCM (Cross-Consensus Message) messages in the `on_idle` hook.

The lockdown mode status is stored in the `LockdownModeStatus` storage item. When the lockdown mode is deactivated, the system resumes normal operations, including the execution of XCM messages in the `on_idle` hook.

## Configuration

This pallet supports configurable traits that allow customization according to specific needs.

### Types

- `RuntimeEvent`: Specifies the runtime event type.
- `LockdownModeOrigin`: Specifies the origin that is allowed to activate and deactivate the lockdown mode.
- `BlackListedCalls`: Specifies the filter used to filter incoming runtime calls in lockdown mode.
- `LockdownDmpHandler`: Specifies the handler for downward messages in lockdown mode.
- `XcmExecutorManager`: Interface to control the execution of XCMP Queue messages.


## Extrinsics

The pallet provides the following extrinsics:

- `activate_lockdown_mode`: Activates the lockdown mode. Only the specified `LockdownModeOrigin` can call this extrinsic. It updates the `LockdownModeStatus` storage item to `ACTIVATED` (true) and attempts to suspend the execution of XCM messages in the `on_idle` hook.
- `deactivate_lockdown_mode`: Deactivates the lockdown mode. Only the specified `LockdownModeOrigin` can call this extrinsic. It updates the `LockdownModeStatus` storage item to `DEACTIVATED` (false) and attempts to resume the execution of XCM messages in the `on_idle` hook.


#### Errors

Possible errors returned by the dispatchable calls are:

- `LockdownModeAlreadyActivated`: The lockdown mode is already activated.
- `LockdownModeAlreadyDeactivated`: The lockdown mode is already deactivated.

Please note that any failure to suspend or resume XCM execution in the `on_idle` hook is not treated as a fatal error that stops the function execution. Instead, it is recorded as an event `FailedToSuspendIdleXcmExecution` or `FailedToResumeIdleXcmExecution`, respectively, and the function continues its execution.

The lockdown mode can serve as a crucial tool in system maintenance or in case of emergency, when it's necessary to restrict system operation and ensure the system's security and stability.
25 changes: 25 additions & 0 deletions pallets/lockdown-mode/src/benchmarking.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
use super::*;

#[allow(unused)]
use crate::Pallet as LockdownMode;
use crate::{ACTIVATED, DEACTIVATED};
use frame_benchmarking::benchmarks;
use frame_system::RawOrigin;

benchmarks! {
activate_lockdown_mode {
LockdownModeStatus::<T>::put(DEACTIVATED);
}: activate_lockdown_mode(RawOrigin::Root)
verify {
assert_eq!(LockdownModeStatus::<T>::get(), ACTIVATED);
}

deactivate_lockdown_mode {
LockdownModeStatus::<T>::put(ACTIVATED);
}: deactivate_lockdown_mode(RawOrigin::Root)
verify {
assert_eq!(LockdownModeStatus::<T>::get(), DEACTIVATED);
}

impl_benchmark_test_suite!(LockdownMode, crate::mock::new_test_ext(true), crate::mock::Test);
}
155 changes: 155 additions & 0 deletions pallets/lockdown-mode/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
#![cfg_attr(not(feature = "std"), no_std)]

/// Edit this file to define custom logic or remove it if it is not needed.
/// Learn more about FRAME and the core library of Substrate FRAME pallets:
/// <https://docs.substrate.io/reference/frame-pallets/>
pub use pallet::*;

#[cfg(test)]
mod mock;
#[cfg(test)]
mod tests;

#[cfg(feature = "runtime-benchmarks")]
mod benchmarking;
pub mod weights;
pub use weights::*;

pub const ACTIVATED: bool = true;
pub const DEACTIVATED: bool = false;

#[frame_support::pallet]
pub mod pallet {
use super::*;
use cumulus_primitives_core::{
relay_chain::BlockNumber as RelayBlockNumber, DmpMessageHandler,
};
use frame_support::{
pallet_prelude::{ValueQuery, *},
traits::Contains,
};
use frame_system::pallet_prelude::*;
use sp_std::vec::Vec;
use xcm_primitives::PauseXcmExecution;
#[pallet::pallet]
pub struct Pallet<T>(_);

#[pallet::genesis_config]
pub struct GenesisConfig {
pub initial_status: bool,
}

#[cfg(feature = "std")]
impl Default for GenesisConfig {
fn default() -> Self {
Self { initial_status: ACTIVATED }
}
}

#[pallet::genesis_build]
impl<T: Config> GenesisBuild<T> for GenesisConfig {
fn build(&self) {
LockdownModeStatus::<T>::put(&self.initial_status);
}
}

#[pallet::config]
pub trait Config: frame_system::Config {
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
type LockdownModeOrigin: EnsureOrigin<Self::RuntimeOrigin>;
type BlackListedCalls: Contains<Self::RuntimeCall>;
type LockdownDmpHandler: DmpMessageHandler;
type XcmExecutorManager: PauseXcmExecution;
type WeightInfo: WeightInfo;
}

#[pallet::storage]
pub type LockdownModeStatus<T: Config> = StorageValue<_, bool, ValueQuery>;

#[pallet::event]
#[pallet::generate_deposit(pub(super) fn deposit_event)]
pub enum Event<T: Config> {
LockdownModeActivated,
LockdownModeDeactivated,
/// The call to suspend on_idle XCM execution failed with inner error
FailedToSuspendIdleXcmExecution {
error: DispatchError,
},
/// The call to resume on_idle XCM execution failed with inner error
FailedToResumeIdleXcmExecution {
error: DispatchError,
},
}

#[pallet::error]
pub enum Error<T> {
/// Lockdown mode was already activated
LockdownModeAlreadyActivated,
/// Lockdown mode was already deactivated
LockdownModeAlreadyDeactivated,
}

#[pallet::call]
impl<T: Config> Pallet<T> {
#[pallet::call_index(0)]
#[pallet::weight(<T as pallet::Config>::WeightInfo::activate_lockdown_mode())]
pub fn activate_lockdown_mode(origin: OriginFor<T>) -> DispatchResult {
T::LockdownModeOrigin::ensure_origin(origin)?;

ensure!(!LockdownModeStatus::<T>::get(), Error::<T>::LockdownModeAlreadyActivated);

LockdownModeStatus::<T>::put(ACTIVATED);

if let Err(error) = T::XcmExecutorManager::suspend_xcm_execution() {
log::error!("Failed to suspend idle XCM execution {:?}", error);
Self::deposit_event(Event::FailedToSuspendIdleXcmExecution { error });
}

Self::deposit_event(Event::LockdownModeActivated);

Ok(())
}

#[pallet::call_index(1)]
#[pallet::weight(<T as pallet::Config>::WeightInfo::deactivate_lockdown_mode())]
pub fn deactivate_lockdown_mode(origin: OriginFor<T>) -> DispatchResult {
T::LockdownModeOrigin::ensure_origin(origin)?;
ensure!(LockdownModeStatus::<T>::get(), Error::<T>::LockdownModeAlreadyDeactivated);

LockdownModeStatus::<T>::put(DEACTIVATED);

if let Err(error) = T::XcmExecutorManager::resume_xcm_execution() {
log::error!("Failed to resume idle XCM execution {:?}", error);
Self::deposit_event(Event::FailedToResumeIdleXcmExecution { error });
}

Self::deposit_event(Event::LockdownModeDeactivated);

Ok(())
}
}

impl<T: Config> Contains<T::RuntimeCall> for Pallet<T> {
fn contains(call: &T::RuntimeCall) -> bool {
if LockdownModeStatus::<T>::get() {
T::BlackListedCalls::contains(call)
} else {
return true
}
}
}

impl<T: Config> DmpMessageHandler for Pallet<T> {
fn handle_dmp_messages(
iter: impl Iterator<Item = (RelayBlockNumber, Vec<u8>)>,
limit: Weight,
) -> Weight {
if LockdownModeStatus::<T>::get() {
T::LockdownDmpHandler::handle_dmp_messages(iter, Weight::zero())
} else {
// Normal path, everything should pass through
T::LockdownDmpHandler::handle_dmp_messages(iter, limit)
}
}
}
}
Loading