diff --git a/bridges/modules/messages/src/lib.rs b/bridges/modules/messages/src/lib.rs index 53694e6ee2368..66bfecd2592b2 100644 --- a/bridges/modules/messages/src/lib.rs +++ b/bridges/modules/messages/src/lib.rs @@ -1113,7 +1113,11 @@ mod tests { REGULAR_PAYLOAD, TEST_LANE_ID, TEST_RELAYER_A, TEST_RELAYER_B, }; use bp_messages::{UnrewardedRelayer, UnrewardedRelayersState}; - use frame_support::{assert_noop, assert_ok, storage::generator::StorageMap, weights::Weight}; + use frame_support::{ + assert_noop, assert_ok, + storage::generator::{StorageMap, StorageValue}, + weights::Weight, + }; use frame_system::{EventRecord, Pallet as System, Phase}; use sp_runtime::DispatchError; @@ -2276,6 +2280,11 @@ mod tests { #[test] fn storage_keys_computed_properly() { + assert_eq!( + PalletOperatingMode::::storage_value_final_key().to_vec(), + bp_messages::storage_keys::operating_mode_key("Messages").0, + ); + assert_eq!( OutboundMessages::::storage_map_final_key(MessageKey { lane_id: TEST_LANE_ID, diff --git a/bridges/primitives/messages/src/storage_keys.rs b/bridges/primitives/messages/src/storage_keys.rs index 3e8dc672541b6..19494b8b8527e 100644 --- a/bridges/primitives/messages/src/storage_keys.rs +++ b/bridges/primitives/messages/src/storage_keys.rs @@ -16,6 +16,8 @@ //! Storage keys of bridge messages pallet. +/// Name of the `OPERATING_MODE_VALUE_NAME` storage value. +pub const OPERATING_MODE_VALUE_NAME: &str = "PalletOperatingMode"; /// Name of the `OutboundMessages` storage map. pub const OUTBOUND_MESSAGES_MAP_NAME: &str = "OutboundMessages"; /// Name of the `OutboundLanes` storage map. @@ -29,6 +31,17 @@ use codec::Encode; use frame_support::Blake2_128Concat; use sp_core::storage::StorageKey; +/// Storage key of the `PalletOperatingMode` value in the runtime storage. +pub fn operating_mode_key(pallet_prefix: &str) -> StorageKey { + StorageKey( + bp_runtime::storage_value_final_key( + pallet_prefix.as_bytes(), + OPERATING_MODE_VALUE_NAME.as_bytes(), + ) + .to_vec(), + ) +} + /// Storage key of the outbound message in the runtime storage. pub fn message_key(pallet_prefix: &str, lane: &LaneId, nonce: MessageNonce) -> StorageKey { bp_runtime::storage_map_final_key::( @@ -61,6 +74,19 @@ mod tests { use super::*; use hex_literal::hex; + #[test] + fn operating_mode_key_computed_properly() { + // If this test fails, then something has been changed in module storage that is possibly + // breaking all existing message relays. + let storage_key = operating_mode_key("BridgeMessages").0; + assert_eq!( + storage_key, + hex!("dd16c784ebd3390a9bc0357c7511ed010f4cf0917788d791142ff6c1f216e7b3").to_vec(), + "Unexpected storage key: {}", + hex::encode(&storage_key), + ); + } + #[test] fn storage_message_key_computed_properly() { // If this test fails, then something has been changed in module storage that is breaking diff --git a/bridges/relays/lib-substrate-relay/src/messages_source.rs b/bridges/relays/lib-substrate-relay/src/messages_source.rs index 80da24910222c..de2306be3fef4 100644 --- a/bridges/relays/lib-substrate-relay/src/messages_source.rs +++ b/bridges/relays/lib-substrate-relay/src/messages_source.rs @@ -29,8 +29,8 @@ use crate::{ use async_trait::async_trait; use bp_messages::{ - storage_keys::outbound_lane_data_key, LaneId, MessageNonce, OutboundLaneData, - UnrewardedRelayersState, + storage_keys::{operating_mode_key, outbound_lane_data_key}, + LaneId, MessageNonce, OperatingMode, OutboundLaneData, UnrewardedRelayersState, }; use bridge_runtime_common::messages::{ source::FromBridgedChainMessagesDeliveryProof, target::FromBridgedChainMessagesProof, @@ -99,6 +99,11 @@ impl SubstrateMessagesSource

{ ) .await } + + /// Ensure that the messages pallet at source chain is active. + async fn ensure_pallet_active(&self) -> Result<(), SubstrateError> { + ensure_messages_pallet_active::(&self.client).await + } } impl Clone for SubstrateMessagesSource

{ @@ -132,6 +137,8 @@ where // we can't continue to deliver confirmations if source node is out of sync, because // it may have already received confirmations that we're going to deliver self.client.ensure_synced().await?; + // we can't relay confirmations if messages pallet at source chain is halted + self.ensure_pallet_active().await?; read_client_state::< _, @@ -292,6 +299,25 @@ where } } +/// Ensure that the messages pallet at source chain is active. +pub(crate) async fn ensure_messages_pallet_active( + client: &Client, +) -> Result<(), SubstrateError> +where + AtChain: ChainWithMessages, + WithChain: ChainWithMessages, +{ + 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); + if is_halted { + Err(SubstrateError::BridgePalletIsHalted) + } else { + Ok(()) + } +} + /// Make messages delivery proof transaction from given proof. fn make_messages_delivery_proof_transaction( spec_version: u32, diff --git a/bridges/relays/lib-substrate-relay/src/messages_target.rs b/bridges/relays/lib-substrate-relay/src/messages_target.rs index 26d376cd5efed..f973cef897357 100644 --- a/bridges/relays/lib-substrate-relay/src/messages_target.rs +++ b/bridges/relays/lib-substrate-relay/src/messages_target.rs @@ -21,7 +21,7 @@ use crate::{ messages_lane::{MessageLaneAdapter, ReceiveMessagesProofCallBuilder, SubstrateMessageLane}, messages_metrics::StandaloneMessagesMetrics, - messages_source::{read_client_state, SubstrateMessagesProof}, + messages_source::{ensure_messages_pallet_active, read_client_state, SubstrateMessagesProof}, on_demand_headers::OnDemandHeadersRelay, TransactionParams, }; @@ -100,6 +100,11 @@ impl SubstrateMessagesTarget

{ ) .await } + + /// Ensure that the messages pallet at target chain is active. + async fn ensure_pallet_active(&self) -> Result<(), SubstrateError> { + ensure_messages_pallet_active::(&self.client).await + } } impl Clone for SubstrateMessagesTarget

{ @@ -136,6 +141,8 @@ where // we can't continue to deliver messages if target node is out of sync, because // it may have already received (some of) messages that we're going to deliver self.client.ensure_synced().await?; + // we can't relay messages if messages pallet at target chain is halted + self.ensure_pallet_active().await?; read_client_state::< _,