diff --git a/bridges/modules/grandpa/src/benchmarking.rs b/bridges/modules/grandpa/src/benchmarking.rs index f12894bb5cbd207e0c2a6ad242ab6863b6be8c1a..655cd6eae74e584e98f6f5a451b56bdc3d7da59e 100644 --- a/bridges/modules/grandpa/src/benchmarking.rs +++ b/bridges/modules/grandpa/src/benchmarking.rs @@ -41,6 +41,7 @@ use crate::*; +use bp_runtime::BasicOperatingMode; use bp_test_utils::{ accounts, make_justification_for_header, JustificationGeneratorParams, TEST_GRANDPA_ROUND, TEST_GRANDPA_SET_ID, @@ -84,7 +85,7 @@ fn prepare_benchmark_data<T: Config<I>, I: 'static>( header: Box::new(bp_test_utils::test_header(Zero::zero())), authority_list, set_id: TEST_GRANDPA_SET_ID, - is_halted: false, + operating_mode: BasicOperatingMode::Normal, }; bootstrap_bridge::<T, I>(init_data); diff --git a/bridges/modules/grandpa/src/lib.rs b/bridges/modules/grandpa/src/lib.rs index 726de9c507ed4a1cd716b282cb062e5474bffa26..056aee406d8c014ba03a69f58f39b89dc1873cca 100644 --- a/bridges/modules/grandpa/src/lib.rs +++ b/bridges/modules/grandpa/src/lib.rs @@ -71,6 +71,7 @@ pub type BridgedHeader<T, I> = HeaderOf<<T as Config<I>>::BridgedChain>; #[frame_support::pallet] pub mod pallet { use super::*; + use bp_runtime::BasicOperatingMode; use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; @@ -119,14 +120,9 @@ pub mod pallet { impl<T: Config<I>, I: 'static> OwnedBridgeModule<T> for Pallet<T, I> { const LOG_TARGET: &'static str = "runtime::bridge-grandpa"; - const OPERATING_MODE_KEY: &'static str = "IsHalted"; type OwnerStorage = PalletOwner<T, I>; - type OperatingMode = bool; - type OperatingModeStorage = IsHalted<T, I>; - - fn is_halted() -> bool { - Self::OperatingModeStorage::get() - } + type OperatingMode = BasicOperatingMode; + type OperatingModeStorage = PalletOperatingMode<T, I>; } #[pallet::call] @@ -237,8 +233,11 @@ pub mod pallet { /// /// May only be called either by root, or by `PalletOwner`. #[pallet::weight((T::DbWeight::get().reads_writes(1, 1), DispatchClass::Operational))] - pub fn set_operational(origin: OriginFor<T>, operational: bool) -> DispatchResult { - Self::set_operating_mode(origin, !operational) + pub fn set_operating_mode( + origin: OriginFor<T>, + operating_mode: BasicOperatingMode, + ) -> DispatchResult { + <Self as OwnedBridgeModule<_>>::set_operating_mode(origin, operating_mode) } } @@ -293,9 +292,12 @@ pub mod pallet { pub type PalletOwner<T: Config<I>, I: 'static = ()> = StorageValue<_, T::AccountId, OptionQuery>; - /// If true, all pallet transactions are failed immediately. + /// The current operating mode of the pallet. + /// + /// Depending on the mode either all, or no transactions will be allowed. #[pallet::storage] - pub type IsHalted<T: Config<I>, I: 'static = ()> = StorageValue<_, bool, ValueQuery>; + pub type PalletOperatingMode<T: Config<I>, I: 'static = ()> = + StorageValue<_, BasicOperatingMode, ValueQuery>; #[pallet::genesis_config] pub struct GenesisConfig<T: Config<I>, I: 'static = ()> { @@ -324,7 +326,7 @@ pub mod pallet { } else { // Since the bridge hasn't been initialized we shouldn't allow anyone to perform // transactions. - <IsHalted<T, I>>::put(true); + <PalletOperatingMode<T, I>>::put(BasicOperatingMode::Halted); } } } @@ -463,7 +465,8 @@ pub mod pallet { pub(crate) fn initialize_bridge<T: Config<I>, I: 'static>( init_params: super::InitializationData<BridgedHeader<T, I>>, ) { - let super::InitializationData { header, authority_list, set_id, is_halted } = init_params; + let super::InitializationData { header, authority_list, set_id, operating_mode } = + init_params; let initial_hash = header.hash(); <InitialHash<T, I>>::put(initial_hash); @@ -473,7 +476,7 @@ pub mod pallet { let authority_set = bp_header_chain::AuthoritySet::new(authority_list, set_id); <CurrentAuthoritySet<T, I>>::put(authority_set); - <IsHalted<T, I>>::put(is_halted); + <PalletOperatingMode<T, I>>::put(operating_mode); } #[cfg(feature = "runtime-benchmarks")] @@ -576,7 +579,7 @@ pub fn initialize_for_benchmarks<T: Config<I>, I: 'static>(header: BridgedHeader authority_list: sp_std::vec::Vec::new(), /* we don't verify any proofs in external * benchmarks */ set_id: 0, - is_halted: false, + operating_mode: bp_runtime::BasicOperatingMode::Normal, }); } @@ -584,6 +587,7 @@ pub fn initialize_for_benchmarks<T: Config<I>, I: 'static>(header: BridgedHeader mod tests { use super::*; use crate::mock::{run_test, test_header, Origin, TestHeader, TestNumber, TestRuntime}; + use bp_runtime::BasicOperatingMode; use bp_test_utils::{ authority_list, make_default_justification, make_justification_for_header, JustificationGeneratorParams, ALICE, BOB, @@ -611,7 +615,7 @@ mod tests { header: Box::new(genesis), authority_list: authority_list(), set_id: 1, - is_halted: false, + operating_mode: BasicOperatingMode::Normal, }; Pallet::<TestRuntime>::initialize(origin, init_data.clone()).map(|_| init_data) @@ -685,7 +689,7 @@ mod tests { CurrentAuthoritySet::<TestRuntime>::get().authorities, init_data.authority_list ); - assert!(!IsHalted::<TestRuntime>::get()); + assert_eq!(PalletOperatingMode::<TestRuntime>::get(), BasicOperatingMode::Normal); }) } @@ -707,29 +711,50 @@ mod tests { assert_ok!(Pallet::<TestRuntime>::set_owner(Origin::root(), Some(1))); assert_noop!( - Pallet::<TestRuntime>::set_operational(Origin::signed(2), false), + Pallet::<TestRuntime>::set_operating_mode( + Origin::signed(2), + BasicOperatingMode::Halted + ), DispatchError::BadOrigin, ); - assert_ok!(Pallet::<TestRuntime>::set_operational(Origin::root(), false)); + assert_ok!(Pallet::<TestRuntime>::set_operating_mode( + Origin::root(), + BasicOperatingMode::Halted + )); assert_ok!(Pallet::<TestRuntime>::set_owner(Origin::signed(1), None)); assert_noop!( - Pallet::<TestRuntime>::set_operational(Origin::signed(1), true), + Pallet::<TestRuntime>::set_operating_mode( + Origin::signed(1), + BasicOperatingMode::Normal + ), DispatchError::BadOrigin, ); assert_noop!( - Pallet::<TestRuntime>::set_operational(Origin::signed(2), true), + Pallet::<TestRuntime>::set_operating_mode( + Origin::signed(2), + BasicOperatingMode::Normal + ), DispatchError::BadOrigin, ); - assert_ok!(Pallet::<TestRuntime>::set_operational(Origin::root(), true)); + assert_ok!(Pallet::<TestRuntime>::set_operating_mode( + Origin::root(), + BasicOperatingMode::Normal + )); }); } #[test] fn pallet_may_be_halted_by_root() { run_test(|| { - assert_ok!(Pallet::<TestRuntime>::set_operational(Origin::root(), false)); - assert_ok!(Pallet::<TestRuntime>::set_operational(Origin::root(), true)); + assert_ok!(Pallet::<TestRuntime>::set_operating_mode( + Origin::root(), + BasicOperatingMode::Halted + )); + assert_ok!(Pallet::<TestRuntime>::set_operating_mode( + Origin::root(), + BasicOperatingMode::Normal + )); }); } @@ -738,21 +763,39 @@ mod tests { run_test(|| { PalletOwner::<TestRuntime>::put(2); - assert_ok!(Pallet::<TestRuntime>::set_operational(Origin::signed(2), false)); - assert_ok!(Pallet::<TestRuntime>::set_operational(Origin::signed(2), true)); + assert_ok!(Pallet::<TestRuntime>::set_operating_mode( + Origin::signed(2), + BasicOperatingMode::Halted + )); + assert_ok!(Pallet::<TestRuntime>::set_operating_mode( + Origin::signed(2), + BasicOperatingMode::Normal + )); assert_noop!( - Pallet::<TestRuntime>::set_operational(Origin::signed(1), false), + Pallet::<TestRuntime>::set_operating_mode( + Origin::signed(1), + BasicOperatingMode::Halted + ), DispatchError::BadOrigin, ); assert_noop!( - Pallet::<TestRuntime>::set_operational(Origin::signed(1), true), + Pallet::<TestRuntime>::set_operating_mode( + Origin::signed(1), + BasicOperatingMode::Normal + ), DispatchError::BadOrigin, ); - assert_ok!(Pallet::<TestRuntime>::set_operational(Origin::signed(2), false)); + assert_ok!(Pallet::<TestRuntime>::set_operating_mode( + Origin::signed(2), + BasicOperatingMode::Halted + )); assert_noop!( - Pallet::<TestRuntime>::set_operational(Origin::signed(1), true), + Pallet::<TestRuntime>::set_operating_mode( + Origin::signed(1), + BasicOperatingMode::Normal + ), DispatchError::BadOrigin, ); }); @@ -763,13 +806,19 @@ mod tests { run_test(|| { initialize_substrate_bridge(); - assert_ok!(Pallet::<TestRuntime>::set_operational(Origin::root(), false)); + assert_ok!(Pallet::<TestRuntime>::set_operating_mode( + Origin::root(), + BasicOperatingMode::Halted + )); assert_noop!( submit_finality_proof(1), Error::<TestRuntime>::BridgeModule(bp_runtime::OwnedBridgeModuleError::Halted) ); - assert_ok!(Pallet::<TestRuntime>::set_operational(Origin::root(), true)); + assert_ok!(Pallet::<TestRuntime>::set_operating_mode( + Origin::root(), + BasicOperatingMode::Normal + )); assert_ok!(submit_finality_proof(1)); }) } @@ -851,7 +900,7 @@ mod tests { header: Box::new(genesis), authority_list: invalid_authority_list, set_id: 1, - is_halted: false, + operating_mode: BasicOperatingMode::Normal, }; assert_ok!(Pallet::<TestRuntime>::initialize(Origin::root(), init_data)); @@ -1115,8 +1164,8 @@ mod tests { #[test] fn storage_keys_computed_properly() { assert_eq!( - IsHalted::<TestRuntime>::storage_value_final_key().to_vec(), - bp_header_chain::storage_keys::is_halted_key("Grandpa").0, + PalletOperatingMode::<TestRuntime>::storage_value_final_key().to_vec(), + bp_header_chain::storage_keys::pallet_operating_mode_key("Grandpa").0, ); assert_eq!( diff --git a/bridges/modules/messages/src/lib.rs b/bridges/modules/messages/src/lib.rs index 78f44e75027b58025181fb81f967e6da97feaced..eed718477beb34654e5c6366064d142acb549eba 100644 --- a/bridges/modules/messages/src/lib.rs +++ b/bridges/modules/messages/src/lib.rs @@ -57,11 +57,11 @@ use bp_messages::{ DispatchMessage, MessageDispatch, ProvedLaneMessages, ProvedMessages, SourceHeaderChain, }, total_unrewarded_messages, DeliveredMessages, InboundLaneData, InboundMessageDetails, LaneId, - MessageData, MessageKey, MessageNonce, MessagePayload, OperatingMode, OutboundLaneData, + MessageData, MessageKey, MessageNonce, MessagePayload, MessagesOperatingMode, OutboundLaneData, OutboundMessageDetails, Parameter as MessagesParameter, UnrewardedRelayer, UnrewardedRelayersState, }; -use bp_runtime::{ChainId, OwnedBridgeModule, Size}; +use bp_runtime::{BasicOperatingMode, ChainId, OwnedBridgeModule, Size}; use codec::{Decode, Encode}; use frame_support::{ fail, @@ -218,14 +218,9 @@ pub mod pallet { impl<T: Config<I>, I: 'static> OwnedBridgeModule<T> for Pallet<T, I> { const LOG_TARGET: &'static str = "runtime::bridge-messages"; - const OPERATING_MODE_KEY: &'static str = "PalletOperatingMode"; type OwnerStorage = PalletOwner<T, I>; - type OperatingMode = OperatingMode; + type OperatingMode = MessagesOperatingMode; type OperatingModeStorage = PalletOperatingMode<T, I>; - - fn is_halted() -> bool { - Self::OperatingModeStorage::get() == OperatingMode::Halted - } } #[pallet::call] @@ -244,7 +239,7 @@ pub mod pallet { #[pallet::weight((T::DbWeight::get().reads_writes(1, 1), DispatchClass::Operational))] pub fn set_operating_mode( origin: OriginFor<T>, - operating_mode: OperatingMode, + operating_mode: MessagesOperatingMode, ) -> DispatchResult { <Self as OwnedBridgeModule<_>>::set_operating_mode(origin, operating_mode) } @@ -708,7 +703,7 @@ pub mod pallet { #[pallet::storage] #[pallet::getter(fn operating_mode)] pub type PalletOperatingMode<T: Config<I>, I: 'static = ()> = - StorageValue<_, OperatingMode, ValueQuery>; + StorageValue<_, MessagesOperatingMode, ValueQuery>; /// Map of lane id => inbound lane data. #[pallet::storage] @@ -728,7 +723,7 @@ pub mod pallet { #[pallet::genesis_config] pub struct GenesisConfig<T: Config<I>, I: 'static = ()> { /// Initial pallet operating mode. - pub operating_mode: OperatingMode, + pub operating_mode: MessagesOperatingMode, /// Initial pallet owner. pub owner: Option<T::AccountId>, /// Dummy marker. @@ -972,11 +967,13 @@ where /// Ensure that the pallet is in normal operational mode. fn ensure_normal_operating_mode<T: Config<I>, I: 'static>() -> Result<(), Error<T, I>> { - if PalletOperatingMode::<T, I>::get() != OperatingMode::Normal { - Err(Error::<T, I>::NotOperatingNormally) - } else { - Ok(()) + if PalletOperatingMode::<T, I>::get() == + MessagesOperatingMode::Basic(BasicOperatingMode::Normal) + { + return Ok(()) } + + Err(Error::<T, I>::NotOperatingNormally) } /// Creates new inbound lane object, backed by runtime storage. @@ -1234,26 +1231,35 @@ mod tests { assert_ok!(Pallet::<TestRuntime>::set_owner(Origin::root(), Some(1))); assert_noop!( - Pallet::<TestRuntime>::set_operating_mode(Origin::signed(2), OperatingMode::Halted), + Pallet::<TestRuntime>::set_operating_mode( + Origin::signed(2), + MessagesOperatingMode::Basic(BasicOperatingMode::Halted) + ), DispatchError::BadOrigin, ); assert_ok!(Pallet::<TestRuntime>::set_operating_mode( Origin::root(), - OperatingMode::Halted + MessagesOperatingMode::Basic(BasicOperatingMode::Halted) )); assert_ok!(Pallet::<TestRuntime>::set_owner(Origin::signed(1), None)); assert_noop!( - Pallet::<TestRuntime>::set_operating_mode(Origin::signed(1), OperatingMode::Normal), + Pallet::<TestRuntime>::set_operating_mode( + Origin::signed(1), + MessagesOperatingMode::Basic(BasicOperatingMode::Normal) + ), DispatchError::BadOrigin, ); assert_noop!( - Pallet::<TestRuntime>::set_operating_mode(Origin::signed(2), OperatingMode::Normal), + Pallet::<TestRuntime>::set_operating_mode( + Origin::signed(2), + MessagesOperatingMode::Basic(BasicOperatingMode::Normal) + ), DispatchError::BadOrigin, ); assert_ok!(Pallet::<TestRuntime>::set_operating_mode( Origin::root(), - OperatingMode::Normal + MessagesOperatingMode::Basic(BasicOperatingMode::Normal) )); }); } @@ -1263,11 +1269,11 @@ mod tests { run_test(|| { assert_ok!(Pallet::<TestRuntime>::set_operating_mode( Origin::root(), - OperatingMode::Halted + MessagesOperatingMode::Basic(BasicOperatingMode::Halted) )); assert_ok!(Pallet::<TestRuntime>::set_operating_mode( Origin::root(), - OperatingMode::Normal + MessagesOperatingMode::Basic(BasicOperatingMode::Normal) )); }); } @@ -1279,28 +1285,37 @@ mod tests { assert_ok!(Pallet::<TestRuntime>::set_operating_mode( Origin::signed(2), - OperatingMode::Halted + MessagesOperatingMode::Basic(BasicOperatingMode::Halted) )); assert_ok!(Pallet::<TestRuntime>::set_operating_mode( Origin::signed(2), - OperatingMode::Normal + MessagesOperatingMode::Basic(BasicOperatingMode::Normal) )); assert_noop!( - Pallet::<TestRuntime>::set_operating_mode(Origin::signed(1), OperatingMode::Halted), + Pallet::<TestRuntime>::set_operating_mode( + Origin::signed(1), + MessagesOperatingMode::Basic(BasicOperatingMode::Halted) + ), DispatchError::BadOrigin, ); assert_noop!( - Pallet::<TestRuntime>::set_operating_mode(Origin::signed(1), OperatingMode::Normal), + Pallet::<TestRuntime>::set_operating_mode( + Origin::signed(1), + MessagesOperatingMode::Basic(BasicOperatingMode::Normal) + ), DispatchError::BadOrigin, ); assert_ok!(Pallet::<TestRuntime>::set_operating_mode( Origin::signed(2), - OperatingMode::Halted + MessagesOperatingMode::Basic(BasicOperatingMode::Halted) )); assert_noop!( - Pallet::<TestRuntime>::set_operating_mode(Origin::signed(1), OperatingMode::Normal), + Pallet::<TestRuntime>::set_operating_mode( + Origin::signed(1), + MessagesOperatingMode::Basic(BasicOperatingMode::Normal) + ), DispatchError::BadOrigin, ); }); @@ -1408,7 +1423,9 @@ mod tests { // send message first to be able to check that delivery_proof fails later send_regular_message(); - PalletOperatingMode::<TestRuntime, ()>::put(OperatingMode::Halted); + PalletOperatingMode::<TestRuntime, ()>::put(MessagesOperatingMode::Basic( + BasicOperatingMode::Halted, + )); assert_noop!( Pallet::<TestRuntime>::send_message( @@ -1466,7 +1483,9 @@ mod tests { // send message first to be able to check that delivery_proof fails later send_regular_message(); - PalletOperatingMode::<TestRuntime, ()>::put(OperatingMode::RejectingOutboundMessages); + PalletOperatingMode::<TestRuntime, ()>::put( + MessagesOperatingMode::RejectingOutboundMessages, + ); assert_noop!( Pallet::<TestRuntime>::send_message( diff --git a/bridges/modules/parachains/src/lib.rs b/bridges/modules/parachains/src/lib.rs index cf634e5b5ca5c3fb7ca55469262bcfa1918c05bf..46be3866db12e1f7f2d2f23b003e6f2362cabc4b 100644 --- a/bridges/modules/parachains/src/lib.rs +++ b/bridges/modules/parachains/src/lib.rs @@ -400,6 +400,7 @@ mod tests { run_test, test_relay_header, Origin, TestRuntime, PARAS_PALLET_NAME, UNTRACKED_PARACHAIN_ID, }; + use bp_runtime::BasicOperatingMode; use bp_test_utils::{authority_list, make_default_justification}; use frame_support::{ assert_noop, assert_ok, @@ -420,7 +421,7 @@ mod tests { header: Box::new(test_relay_header(0, state_root)), authority_list: authority_list(), set_id: 1, - is_halted: false, + operating_mode: BasicOperatingMode::Normal, }, ) .unwrap(); diff --git a/bridges/primitives/header-chain/src/lib.rs b/bridges/primitives/header-chain/src/lib.rs index ff8ee82f41e42631b4533674a38bb983c188b822..8ac7972621ce64cce68509fb27cc2963fc016233 100644 --- a/bridges/primitives/header-chain/src/lib.rs +++ b/bridges/primitives/header-chain/src/lib.rs @@ -19,6 +19,7 @@ #![cfg_attr(not(feature = "std"), no_std)] +use bp_runtime::BasicOperatingMode; use codec::{Codec, Decode, Encode, EncodeLike}; use core::{clone::Clone, cmp::Eq, default::Default, fmt::Debug}; use scale_info::TypeInfo; @@ -66,8 +67,8 @@ pub struct InitializationData<H: HeaderT> { pub authority_list: AuthorityList, /// The ID of the initial authority set. pub set_id: SetId, - /// Should the pallet block transaction immediately after initialization. - pub is_halted: bool, + /// Pallet operating mode. + pub operating_mode: BasicOperatingMode, } /// base trait for verifying transaction inclusion proofs. diff --git a/bridges/primitives/header-chain/src/storage_keys.rs b/bridges/primitives/header-chain/src/storage_keys.rs index 14c40d69853b9a4d0866d18e0e3a673f923ee24c..bb642b1817f75e4526e3d52c23dcf05bedea5f9a 100644 --- a/bridges/primitives/header-chain/src/storage_keys.rs +++ b/bridges/primitives/header-chain/src/storage_keys.rs @@ -17,18 +17,18 @@ //! Storage keys of bridge GRANDPA pallet. /// Name of the `IsHalted` storage value. -pub const IS_HALTED_VALUE_NAME: &str = "IsHalted"; +pub const PALLET_OPERATING_MODE_VALUE_NAME: &str = "PalletOperatingMode"; /// Name of the `BestFinalized` storage value. pub const BEST_FINALIZED_VALUE_NAME: &str = "BestFinalized"; use sp_core::storage::StorageKey; -/// Storage key of the `IsHalted` flag in the runtime storage. -pub fn is_halted_key(pallet_prefix: &str) -> StorageKey { +/// Storage key of the `PalletOperatingMode` variable in the runtime storage. +pub fn pallet_operating_mode_key(pallet_prefix: &str) -> StorageKey { StorageKey( bp_runtime::storage_value_final_key( pallet_prefix.as_bytes(), - IS_HALTED_VALUE_NAME.as_bytes(), + PALLET_OPERATING_MODE_VALUE_NAME.as_bytes(), ) .to_vec(), ) @@ -51,13 +51,13 @@ mod tests { use hex_literal::hex; #[test] - fn is_halted_key_computed_properly() { + fn pallet_operating_mode_key_computed_properly() { // If this test fails, then something has been changed in module storage that is breaking // compatibility with previous pallet. - let storage_key = is_halted_key("BridgeGrandpa").0; + let storage_key = pallet_operating_mode_key("BridgeGrandpa").0; assert_eq!( storage_key, - hex!("0b06f475eddb98cf933a12262e0388de9611a984bbd04e2fd39f97bbc006115f").to_vec(), + hex!("0b06f475eddb98cf933a12262e0388de0f4cf0917788d791142ff6c1f216e7b3").to_vec(), "Unexpected storage key: {}", hex::encode(&storage_key), ); diff --git a/bridges/primitives/messages/src/lib.rs b/bridges/primitives/messages/src/lib.rs index 8d51a6fa86462abb1d5d8691cb4ad61661233907..455caad729b70357b904115eb0b79f114cbfd111 100644 --- a/bridges/primitives/messages/src/lib.rs +++ b/bridges/primitives/messages/src/lib.rs @@ -32,14 +32,15 @@ pub mod storage_keys; pub mod target_chain; // Weight is reexported to avoid additional frame-support dependencies in related crates. +use bp_runtime::{BasicOperatingMode, OperatingMode}; pub use frame_support::weights::Weight; /// Messages pallet operating mode. #[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug, TypeInfo)] #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] -pub enum OperatingMode { - /// Normal mode, when all operations are allowed. - Normal, +pub enum MessagesOperatingMode { + /// Basic operating mode (Normal/Halted) + Basic(BasicOperatingMode), /// The pallet is not accepting outbound messages. Inbound messages and receiving proofs /// are still accepted. /// @@ -48,13 +49,20 @@ pub enum OperatingMode { /// queued messages to the bridged chain. Once upgrade is completed, the mode may be switched /// back to `Normal`. RejectingOutboundMessages, - /// The pallet is halted. All operations (except operating mode change) are prohibited. - Halted, } -impl Default for OperatingMode { +impl Default for MessagesOperatingMode { fn default() -> Self { - OperatingMode::Normal + MessagesOperatingMode::Basic(BasicOperatingMode::Normal) + } +} + +impl OperatingMode for MessagesOperatingMode { + fn is_halted(&self) -> bool { + match self { + Self::Basic(operating_mode) => operating_mode.is_halted(), + _ => false, + } } } diff --git a/bridges/primitives/runtime/Cargo.toml b/bridges/primitives/runtime/Cargo.toml index 691426aaf04a7ee71bb9ef542b91bc7c921c05ca..94dd12175d9d648c49a7e6472a85ad39ea7920df 100644 --- a/bridges/primitives/runtime/Cargo.toml +++ b/bridges/primitives/runtime/Cargo.toml @@ -11,6 +11,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = hash-db = { version = "0.15.2", default-features = false } num-traits = { version = "0.2", default-features = false } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +serde = { version = "1.0", optional = true, features = ["derive"] } # Substrate Dependencies @@ -35,6 +36,7 @@ std = [ "hash-db/std", "num-traits/std", "scale-info/std", + "serde", "sp-core/std", "sp-io/std", "sp-runtime/std", diff --git a/bridges/primitives/runtime/src/lib.rs b/bridges/primitives/runtime/src/lib.rs index ee5e6b5d24e99532186b65b286bdc95d4c80891b..cba89df726679011acae146bfe8d4df62235d308 100644 --- a/bridges/primitives/runtime/src/lib.rs +++ b/bridges/primitives/runtime/src/lib.rs @@ -269,18 +269,47 @@ pub enum OwnedBridgeModuleError { Halted, } +/// Operating mode for a bridge module. +pub trait OperatingMode: Send + Copy + Debug + FullCodec { + // Returns true if the bridge module is halted. + fn is_halted(&self) -> bool; +} + +/// Basic operating modes for a bridges module (Normal/Halted). +#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug, TypeInfo)] +#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] +pub enum BasicOperatingMode { + /// Normal mode, when all operations are allowed. + Normal, + /// The pallet is halted. All operations (except operating mode change) are prohibited. + Halted, +} + +impl Default for BasicOperatingMode { + fn default() -> Self { + Self::Normal + } +} + +impl OperatingMode for BasicOperatingMode { + fn is_halted(&self) -> bool { + *self == BasicOperatingMode::Halted + } +} + /// Bridge module that has owner and operating mode pub trait OwnedBridgeModule<T: frame_system::Config> { /// The target that will be used when publishing logs related to this module. const LOG_TARGET: &'static str; - const OPERATING_MODE_KEY: &'static str; type OwnerStorage: StorageValue<T::AccountId, Query = Option<T::AccountId>>; - type OperatingMode: Copy + Debug + FullCodec; - type OperatingModeStorage: StorageValue<Self::OperatingMode>; + type OperatingMode: OperatingMode; + type OperatingModeStorage: StorageValue<Self::OperatingMode, Query = Self::OperatingMode>; /// Check if the module is halted. - fn is_halted() -> bool; + fn is_halted() -> bool { + Self::OperatingModeStorage::get().is_halted() + } /// Ensure that the origin is either root, or `PalletOwner`. fn ensure_owner_or_root(origin: T::Origin) -> Result<(), BadOrigin> { @@ -325,12 +354,7 @@ pub trait OwnedBridgeModule<T: frame_system::Config> { ) -> DispatchResult { Self::ensure_owner_or_root(origin)?; Self::OperatingModeStorage::put(operating_mode); - log::info!( - target: Self::LOG_TARGET, - "Setting operating mode ( {} = {:?}).", - Self::OPERATING_MODE_KEY, - operating_mode - ); + log::info!(target: Self::LOG_TARGET, "Setting operating mode to {:?}.", operating_mode); Ok(()) } } diff --git a/bridges/relays/lib-substrate-relay/src/finality/engine.rs b/bridges/relays/lib-substrate-relay/src/finality/engine.rs index 0f2cc87660bfccc4c1228f3281437f4585ac689e..b2b72e4f2c39f61a4e8327415abd0519aa2f348f 100644 --- a/bridges/relays/lib-substrate-relay/src/finality/engine.rs +++ b/bridges/relays/lib-substrate-relay/src/finality/engine.rs @@ -23,6 +23,7 @@ use bp_header_chain::{ justification::{verify_justification, GrandpaJustification}, FinalityProof, }; +use bp_runtime::{BasicOperatingMode, OperatingMode}; use codec::{Decode, Encode}; use finality_grandpa::voter_set::VoterSet; use num_traits::{One, Zero}; @@ -44,10 +45,12 @@ pub trait Engine<C: Chain>: Send { type FinalityProof: FinalityProof<BlockNumberOf<C>> + Decode + Encode; /// Type of bridge pallet initialization data. type InitializationData: std::fmt::Debug + Send + Sync + 'static; + /// Type of bridge pallet operating mode. + type OperatingMode: OperatingMode + 'static; - /// Returns storage key at the bridged (target) chain that corresponds to the `bool` value, - /// which is true when the bridge pallet is halted. - fn is_halted_key() -> StorageKey; + /// Returns storage key at the bridged (target) chain that corresponds to the variable + /// that holds the operating mode of the pallet. + fn pallet_operating_mode_key() -> StorageKey; /// Returns storage at the bridged (target) chain that corresponds to some value that is /// missing from the storage until bridge pallet is initialized. /// @@ -74,7 +77,11 @@ pub trait Engine<C: Chain>: Send { async fn is_halted<TargetChain: Chain>( target_client: &Client<TargetChain>, ) -> Result<bool, SubstrateError> { - Ok(target_client.storage_value(Self::is_halted_key(), None).await?.unwrap_or(false)) + Ok(target_client + .storage_value::<Self::OperatingMode>(Self::pallet_operating_mode_key(), None) + .await? + .map(|operating_mode| operating_mode.is_halted()) + .unwrap_or(false)) } } @@ -112,9 +119,10 @@ impl<C: ChainWithGrandpa> Engine<C> for Grandpa<C> { const ID: ConsensusEngineId = sp_finality_grandpa::GRANDPA_ENGINE_ID; type FinalityProof = GrandpaJustification<HeaderOf<C>>; type InitializationData = bp_header_chain::InitializationData<C::Header>; + type OperatingMode = BasicOperatingMode; - fn is_halted_key() -> StorageKey { - bp_header_chain::storage_keys::is_halted_key(C::WITH_CHAIN_GRANDPA_PALLET_NAME) + fn pallet_operating_mode_key() -> StorageKey { + bp_header_chain::storage_keys::pallet_operating_mode_key(C::WITH_CHAIN_GRANDPA_PALLET_NAME) } fn is_initialized_key() -> StorageKey { @@ -237,7 +245,7 @@ impl<C: ChainWithGrandpa> Engine<C> for Grandpa<C> { } else { initial_authorities_set_id }, - is_halted: false, + operating_mode: BasicOperatingMode::Normal, }) } } diff --git a/bridges/relays/lib-substrate-relay/src/messages_source.rs b/bridges/relays/lib-substrate-relay/src/messages_source.rs index 0e21ef66eda3b8e22e328aaec101a9423a74a83a..5a6b6554e4bae633e481bf1238afd01638036c6f 100644 --- a/bridges/relays/lib-substrate-relay/src/messages_source.rs +++ b/bridges/relays/lib-substrate-relay/src/messages_source.rs @@ -31,10 +31,10 @@ use async_std::sync::Arc; use async_trait::async_trait; use bp_messages::{ storage_keys::{operating_mode_key, outbound_lane_data_key}, - InboundMessageDetails, LaneId, MessageData, MessageNonce, OperatingMode, OutboundLaneData, - OutboundMessageDetails, UnrewardedRelayersState, + InboundMessageDetails, LaneId, MessageData, MessageNonce, MessagesOperatingMode, + OutboundLaneData, OutboundMessageDetails, UnrewardedRelayersState, }; -use bp_runtime::messages::DispatchFeePayment; +use bp_runtime::{messages::DispatchFeePayment, BasicOperatingMode}; use bridge_runtime_common::messages::{ source::FromBridgedChainMessagesDeliveryProof, target::FromBridgedChainMessagesProof, }; @@ -420,7 +420,8 @@ where let operating_mode = client .storage_value(operating_mode_key(WithChain::WITH_CHAIN_MESSAGES_PALLET_NAME), None) .await?; - let is_halted = operating_mode == Some(OperatingMode::Halted); + let is_halted = + operating_mode == Some(MessagesOperatingMode::Basic(BasicOperatingMode::Halted)); if is_halted { Err(SubstrateError::BridgePalletIsHalted) } else {