Skip to content

Commit b910df5

Browse files
svyatonikHCastano
andauthored
Flag for rejecting all outbound messages (paritytech#982)
* flag for rejecting all outbound messages * update weights * Revert "update weights" This reverts commit 992b866. * Revert "flag for rejecting all outbound messages" This reverts commit d094964. * OperatingMode * Update modules/messages/src/lib.rs Co-authored-by: Hernando Castano <[email protected]> * Poke CI * RustFmt Co-authored-by: Hernando Castano <[email protected]> Co-authored-by: Hernando Castano <[email protected]>
1 parent a6b215c commit b910df5

3 files changed

Lines changed: 142 additions & 32 deletions

File tree

modules/messages/src/lib.rs

Lines changed: 116 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ use bp_messages::{
5050
source_chain::{LaneMessageVerifier, MessageDeliveryAndDispatchPayment, RelayersRewards, TargetHeaderChain},
5151
target_chain::{DispatchMessage, MessageDispatch, ProvedLaneMessages, ProvedMessages, SourceHeaderChain},
5252
total_unrewarded_messages, InboundLaneData, LaneId, MessageData, MessageKey, MessageNonce, MessagePayload,
53-
OutboundLaneData, Parameter as MessagesParameter, UnrewardedRelayersState,
53+
OperatingMode, OutboundLaneData, Parameter as MessagesParameter, UnrewardedRelayersState,
5454
};
5555
use bp_runtime::Size;
5656
use codec::{Decode, Encode};
@@ -198,8 +198,10 @@ decl_storage! {
198198
/// runtime methods may still be used to do that (i.e. democracy::referendum to update halt
199199
/// flag directly or call the `halt_operations`).
200200
pub PalletOwner get(fn module_owner): Option<T::AccountId>;
201-
/// If true, all pallet transactions are failed immediately.
202-
pub IsHalted get(fn is_halted) config(): bool;
201+
/// The current operating mode of the pallet.
202+
///
203+
/// Depending on the mode either all, some, or no transactions will be allowed.
204+
pub PalletOperatingMode get(fn operating_mode) config(): OperatingMode;
203205
/// Map of lane id => inbound lane data.
204206
pub InboundLanes: map hasher(blake2_128_concat) LaneId => InboundLaneData<T::InboundRelayer>;
205207
/// Map of lane id => outbound lane data.
@@ -266,19 +268,18 @@ decl_module! {
266268
}
267269
}
268270

269-
/// Halt or resume all pallet operations.
271+
/// Halt or resume all/some pallet operations.
270272
///
271273
/// May only be called either by root, or by `PalletOwner`.
272274
#[weight = (T::DbWeight::get().reads_writes(1, 1), DispatchClass::Operational)]
273-
pub fn set_operational(origin, operational: bool) {
275+
pub fn set_operating_mode(origin, operating_mode: OperatingMode) {
274276
ensure_owner_or_root::<T, I>(origin)?;
275-
<IsHalted<I>>::put(operational);
276-
277-
if operational {
278-
log::info!(target: "runtime::bridge-messages", "Resuming pallet operations.");
279-
} else {
280-
log::warn!(target: "runtime::bridge-messages", "Stopping pallet operations.");
281-
}
277+
<PalletOperatingMode<I>>::put(operating_mode);
278+
log::info!(
279+
target: "runtime::bridge-messages",
280+
"Setting messages pallet operating mode to {:?}.",
281+
operating_mode,
282+
);
282283
}
283284

284285
/// Update pallet parameter.
@@ -301,7 +302,7 @@ decl_module! {
301302
payload: T::OutboundPayload,
302303
delivery_and_dispatch_fee: T::OutboundMessageFee,
303304
) -> DispatchResult {
304-
ensure_operational::<T, I>()?;
305+
ensure_normal_operating_mode::<T, I>()?;
305306
let submitter = origin.into().map_err(|_| BadOrigin)?;
306307

307308
// let's first check if message can be delivered to target chain
@@ -384,6 +385,7 @@ decl_module! {
384385
nonce: MessageNonce,
385386
additional_fee: T::OutboundMessageFee,
386387
) -> DispatchResult {
388+
ensure_not_halted::<T, I>()?;
387389
// if someone tries to pay for already-delivered message, we're rejecting this intention
388390
// (otherwise this additional fee will be locked forever in relayers fund)
389391
//
@@ -441,7 +443,7 @@ decl_module! {
441443
messages_count: u32,
442444
dispatch_weight: Weight,
443445
) -> DispatchResult {
444-
ensure_operational::<T, I>()?;
446+
ensure_not_halted::<T, I>()?;
445447
let _ = ensure_signed(origin)?;
446448

447449
// reject transactions that are declaring too many messages
@@ -532,7 +534,7 @@ decl_module! {
532534
proof: MessagesDeliveryProofOf<T, I>,
533535
relayers_state: UnrewardedRelayersState,
534536
) -> DispatchResult {
535-
ensure_operational::<T, I>()?;
537+
ensure_not_halted::<T, I>()?;
536538

537539
let confirmation_relayer = ensure_signed(origin)?;
538540
let (lane_id, lane_data) = T::TargetHeaderChain::verify_messages_delivery_proof(proof).map_err(|err| {
@@ -697,9 +699,18 @@ fn ensure_owner_or_root<T: Config<I>, I: Instance>(origin: T::Origin) -> Result<
697699
}
698700
}
699701

700-
/// Ensure that the pallet is in operational mode (not halted).
701-
fn ensure_operational<T: Config<I>, I: Instance>() -> Result<(), Error<T, I>> {
702-
if IsHalted::<I>::get() {
702+
/// Ensure that the pallet is in normal operational mode.
703+
fn ensure_normal_operating_mode<T: Config<I>, I: Instance>() -> Result<(), Error<T, I>> {
704+
if PalletOperatingMode::<I>::get() != OperatingMode::Normal {
705+
Err(Error::<T, I>::Halted)
706+
} else {
707+
Ok(())
708+
}
709+
}
710+
711+
/// Ensure that the pallet is not halted.
712+
fn ensure_not_halted<T: Config<I>, I: Instance>() -> Result<(), Error<T, I>> {
713+
if PalletOperatingMode::<I>::get() == OperatingMode::Halted {
703714
Err(Error::<T, I>::Halted)
704715
} else {
705716
Ok(())
@@ -922,29 +933,41 @@ mod tests {
922933

923934
assert_ok!(Pallet::<TestRuntime>::set_owner(Origin::root(), Some(1)));
924935
assert_noop!(
925-
Pallet::<TestRuntime>::set_operational(Origin::signed(2), false),
936+
Pallet::<TestRuntime>::set_operating_mode(Origin::signed(2), OperatingMode::Halted),
926937
DispatchError::BadOrigin,
927938
);
928-
assert_ok!(Pallet::<TestRuntime>::set_operational(Origin::root(), false));
939+
assert_ok!(Pallet::<TestRuntime>::set_operating_mode(
940+
Origin::root(),
941+
OperatingMode::Halted
942+
));
929943

930944
assert_ok!(Pallet::<TestRuntime>::set_owner(Origin::signed(1), None));
931945
assert_noop!(
932-
Pallet::<TestRuntime>::set_operational(Origin::signed(1), true),
946+
Pallet::<TestRuntime>::set_operating_mode(Origin::signed(1), OperatingMode::Normal),
933947
DispatchError::BadOrigin,
934948
);
935949
assert_noop!(
936-
Pallet::<TestRuntime>::set_operational(Origin::signed(2), true),
950+
Pallet::<TestRuntime>::set_operating_mode(Origin::signed(2), OperatingMode::Normal),
937951
DispatchError::BadOrigin,
938952
);
939-
assert_ok!(Pallet::<TestRuntime>::set_operational(Origin::root(), true));
953+
assert_ok!(Pallet::<TestRuntime>::set_operating_mode(
954+
Origin::root(),
955+
OperatingMode::Normal
956+
));
940957
});
941958
}
942959

943960
#[test]
944961
fn pallet_may_be_halted_by_root() {
945962
run_test(|| {
946-
assert_ok!(Pallet::<TestRuntime>::set_operational(Origin::root(), false));
947-
assert_ok!(Pallet::<TestRuntime>::set_operational(Origin::root(), true));
963+
assert_ok!(Pallet::<TestRuntime>::set_operating_mode(
964+
Origin::root(),
965+
OperatingMode::Halted
966+
));
967+
assert_ok!(Pallet::<TestRuntime>::set_operating_mode(
968+
Origin::root(),
969+
OperatingMode::Normal
970+
));
948971
});
949972
}
950973

@@ -953,21 +976,30 @@ mod tests {
953976
run_test(|| {
954977
PalletOwner::<TestRuntime>::put(2);
955978

956-
assert_ok!(Pallet::<TestRuntime>::set_operational(Origin::signed(2), false));
957-
assert_ok!(Pallet::<TestRuntime>::set_operational(Origin::signed(2), true));
979+
assert_ok!(Pallet::<TestRuntime>::set_operating_mode(
980+
Origin::signed(2),
981+
OperatingMode::Halted
982+
));
983+
assert_ok!(Pallet::<TestRuntime>::set_operating_mode(
984+
Origin::signed(2),
985+
OperatingMode::Normal
986+
));
958987

959988
assert_noop!(
960-
Pallet::<TestRuntime>::set_operational(Origin::signed(1), false),
989+
Pallet::<TestRuntime>::set_operating_mode(Origin::signed(1), OperatingMode::Halted),
961990
DispatchError::BadOrigin,
962991
);
963992
assert_noop!(
964-
Pallet::<TestRuntime>::set_operational(Origin::signed(1), true),
993+
Pallet::<TestRuntime>::set_operating_mode(Origin::signed(1), OperatingMode::Normal),
965994
DispatchError::BadOrigin,
966995
);
967996

968-
assert_ok!(Pallet::<TestRuntime>::set_operational(Origin::signed(2), false));
997+
assert_ok!(Pallet::<TestRuntime>::set_operating_mode(
998+
Origin::signed(2),
999+
OperatingMode::Halted
1000+
));
9691001
assert_noop!(
970-
Pallet::<TestRuntime>::set_operational(Origin::signed(1), true),
1002+
Pallet::<TestRuntime>::set_operating_mode(Origin::signed(1), OperatingMode::Normal),
9711003
DispatchError::BadOrigin,
9721004
);
9731005
});
@@ -1074,7 +1106,7 @@ mod tests {
10741106
// send message first to be able to check that delivery_proof fails later
10751107
send_regular_message();
10761108

1077-
IsHalted::<DefaultInstance>::put(true);
1109+
PalletOperatingMode::<DefaultInstance>::put(OperatingMode::Halted);
10781110

10791111
assert_noop!(
10801112
Pallet::<TestRuntime>::send_message(
@@ -1086,6 +1118,11 @@ mod tests {
10861118
Error::<TestRuntime, DefaultInstance>::Halted,
10871119
);
10881120

1121+
assert_noop!(
1122+
Pallet::<TestRuntime>::increase_message_fee(Origin::signed(1), TEST_LANE_ID, 1, 1,),
1123+
Error::<TestRuntime, DefaultInstance>::Halted,
1124+
);
1125+
10891126
assert_noop!(
10901127
Pallet::<TestRuntime>::receive_messages_proof(
10911128
Origin::signed(1),
@@ -1114,6 +1151,53 @@ mod tests {
11141151
});
11151152
}
11161153

1154+
#[test]
1155+
fn pallet_rejects_new_messages_in_rejecting_outbound_messages_operating_mode() {
1156+
run_test(|| {
1157+
// send message first to be able to check that delivery_proof fails later
1158+
send_regular_message();
1159+
1160+
PalletOperatingMode::<DefaultInstance>::put(OperatingMode::RejectingOutboundMessages);
1161+
1162+
assert_noop!(
1163+
Pallet::<TestRuntime>::send_message(
1164+
Origin::signed(1),
1165+
TEST_LANE_ID,
1166+
REGULAR_PAYLOAD,
1167+
REGULAR_PAYLOAD.1,
1168+
),
1169+
Error::<TestRuntime, DefaultInstance>::Halted,
1170+
);
1171+
1172+
assert_ok!(Pallet::<TestRuntime>::increase_message_fee(
1173+
Origin::signed(1),
1174+
TEST_LANE_ID,
1175+
1,
1176+
1,
1177+
));
1178+
1179+
assert_ok!(Pallet::<TestRuntime>::receive_messages_proof(
1180+
Origin::signed(1),
1181+
TEST_RELAYER_A,
1182+
Ok(vec![message(1, REGULAR_PAYLOAD)]).into(),
1183+
1,
1184+
REGULAR_PAYLOAD.1,
1185+
),);
1186+
1187+
assert_ok!(Pallet::<TestRuntime>::receive_messages_delivery_proof(
1188+
Origin::signed(1),
1189+
TestMessagesDeliveryProof(Ok((
1190+
TEST_LANE_ID,
1191+
InboundLaneData {
1192+
last_confirmed_nonce: 1,
1193+
..Default::default()
1194+
},
1195+
))),
1196+
Default::default(),
1197+
));
1198+
});
1199+
}
1200+
11171201
#[test]
11181202
fn send_message_works() {
11191203
run_test(|| {

primitives/messages/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
88

99
[dependencies]
1010
codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] }
11+
serde = { version = "1.0.101", optional = true, features = ["derive"] }
1112

1213
# Bridge dependencies
1314

@@ -26,5 +27,6 @@ std = [
2627
"codec/std",
2728
"frame-support/std",
2829
"frame-system/std",
30+
"serde",
2931
"sp-std/std"
3032
]

primitives/messages/src/lib.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,30 @@ pub mod target_chain;
3232
// Weight is reexported to avoid additional frame-support dependencies in related crates.
3333
pub use frame_support::weights::Weight;
3434

35+
/// Messages pallet operating mode.
36+
#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug)]
37+
#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
38+
pub enum OperatingMode {
39+
/// Normal mode, when all operations are allowed.
40+
Normal,
41+
/// The pallet is not accepting outbound messages. Inbound messages and receival proofs
42+
/// are still accepted.
43+
///
44+
/// This mode may be used e.g. when bridged chain expects upgrade. Then to avoid dispatch
45+
/// failures, the pallet owner may stop accepting new messages, while continuing to deliver
46+
/// queued messages to the bridged chain. Once upgrade is completed, the mode may be switched
47+
/// back to `Normal`.
48+
RejectingOutboundMessages,
49+
/// The pallet is halted. All operations (except operating mode change) are prohibited.
50+
Halted,
51+
}
52+
53+
impl Default for OperatingMode {
54+
fn default() -> Self {
55+
OperatingMode::Normal
56+
}
57+
}
58+
3559
/// Messages pallet parameter.
3660
pub trait Parameter: frame_support::Parameter {
3761
/// Save parameter value in the runtime storage.

0 commit comments

Comments
 (0)