Skip to content

Commit fe90a2d

Browse files
svyatonikbkchr
authored andcommitted
Reject transactions if bridge pallets are halted (#2600)
* reject transactions if bridge pallets are halted * fixed CI (#2598)
1 parent 2d15d10 commit fe90a2d

5 files changed

Lines changed: 152 additions & 14 deletions

File tree

bridges/bin/runtime-common/src/messages_call_ext.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use crate::messages::{
1818
source::FromBridgedChainMessagesDeliveryProof, target::FromBridgedChainMessagesProof,
1919
};
2020
use bp_messages::{target_chain::MessageDispatch, InboundLaneData, LaneId, MessageNonce};
21+
use bp_runtime::OwnedBridgeModule;
2122
use frame_support::{
2223
dispatch::CallableCallFor,
2324
traits::{Get, IsSubType},
@@ -278,7 +279,17 @@ impl<
278279
}
279280

280281
fn check_obsolete_call(&self) -> TransactionValidity {
282+
let is_pallet_halted = Pallet::<T, I>::ensure_not_halted().is_err();
281283
match self.call_info() {
284+
Some(proof_info) if is_pallet_halted => {
285+
log::trace!(
286+
target: pallet_bridge_messages::LOG_TARGET,
287+
"Rejecting messages transaction on halted pallet: {:?}",
288+
proof_info
289+
);
290+
291+
return sp_runtime::transaction_validity::InvalidTransaction::Call.into()
292+
},
282293
Some(CallInfo::ReceiveMessagesProof(proof_info))
283294
if proof_info.is_obsolete(T::MessageDispatch::is_active()) =>
284295
{
@@ -291,7 +302,7 @@ impl<
291302
return sp_runtime::transaction_validity::InvalidTransaction::Stale.into()
292303
},
293304
Some(CallInfo::ReceiveMessagesDeliveryProof(proof_info))
294-
if proof_info.is_obsolete() =>
305+
if is_pallet_halted || proof_info.is_obsolete() =>
295306
{
296307
log::trace!(
297308
target: pallet_bridge_messages::LOG_TARGET,

bridges/bin/runtime-common/src/refund_relayer_extension.rs

Lines changed: 101 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -838,21 +838,23 @@ mod tests {
838838
mock::*,
839839
};
840840
use bp_messages::{
841-
DeliveredMessages, InboundLaneData, MessageNonce, OutboundLaneData, UnrewardedRelayer,
842-
UnrewardedRelayersState,
841+
DeliveredMessages, InboundLaneData, MessageNonce, MessagesOperatingMode, OutboundLaneData,
842+
UnrewardedRelayer, UnrewardedRelayersState,
843843
};
844844
use bp_parachains::{BestParaHeadHash, ParaInfo};
845845
use bp_polkadot_core::parachains::{ParaHeadsProof, ParaId};
846-
use bp_runtime::HeaderId;
846+
use bp_runtime::{BasicOperatingMode, HeaderId};
847847
use bp_test_utils::{make_default_justification, test_keyring};
848848
use frame_support::{
849849
assert_storage_noop, parameter_types,
850850
traits::{fungible::Mutate, ReservableCurrency},
851851
weights::Weight,
852852
};
853-
use pallet_bridge_grandpa::{Call as GrandpaCall, StoredAuthoritySet};
854-
use pallet_bridge_messages::Call as MessagesCall;
855-
use pallet_bridge_parachains::{Call as ParachainsCall, RelayBlockHash};
853+
use pallet_bridge_grandpa::{Call as GrandpaCall, Pallet as GrandpaPallet, StoredAuthoritySet};
854+
use pallet_bridge_messages::{Call as MessagesCall, Pallet as MessagesPallet};
855+
use pallet_bridge_parachains::{
856+
Call as ParachainsCall, Pallet as ParachainsPallet, RelayBlockHash,
857+
};
856858
use sp_runtime::{
857859
traits::{ConstU64, Header as HeaderT},
858860
transaction_validity::{InvalidTransaction, ValidTransaction},
@@ -1592,6 +1594,99 @@ mod tests {
15921594
});
15931595
}
15941596

1597+
#[test]
1598+
fn ext_rejects_batch_with_grandpa_finality_proof_when_grandpa_pallet_is_halted() {
1599+
run_test(|| {
1600+
initialize_environment(100, 100, 100);
1601+
1602+
GrandpaPallet::<TestRuntime, ()>::set_operating_mode(
1603+
RuntimeOrigin::root(),
1604+
BasicOperatingMode::Halted,
1605+
)
1606+
.unwrap();
1607+
1608+
assert_eq!(
1609+
run_pre_dispatch(all_finality_and_delivery_batch_call(200, 200, 200)),
1610+
Err(TransactionValidityError::Invalid(InvalidTransaction::Call)),
1611+
);
1612+
assert_eq!(
1613+
run_pre_dispatch(all_finality_and_confirmation_batch_call(200, 200, 200)),
1614+
Err(TransactionValidityError::Invalid(InvalidTransaction::Call)),
1615+
);
1616+
});
1617+
}
1618+
1619+
#[test]
1620+
fn ext_rejects_batch_with_parachain_finality_proof_when_parachains_pallet_is_halted() {
1621+
run_test(|| {
1622+
initialize_environment(100, 100, 100);
1623+
1624+
ParachainsPallet::<TestRuntime, ()>::set_operating_mode(
1625+
RuntimeOrigin::root(),
1626+
BasicOperatingMode::Halted,
1627+
)
1628+
.unwrap();
1629+
1630+
assert_eq!(
1631+
run_pre_dispatch(all_finality_and_delivery_batch_call(200, 200, 200)),
1632+
Err(TransactionValidityError::Invalid(InvalidTransaction::Call)),
1633+
);
1634+
assert_eq!(
1635+
run_pre_dispatch(all_finality_and_confirmation_batch_call(200, 200, 200)),
1636+
Err(TransactionValidityError::Invalid(InvalidTransaction::Call)),
1637+
);
1638+
1639+
assert_eq!(
1640+
run_pre_dispatch(parachain_finality_and_delivery_batch_call(200, 200)),
1641+
Err(TransactionValidityError::Invalid(InvalidTransaction::Call)),
1642+
);
1643+
assert_eq!(
1644+
run_pre_dispatch(parachain_finality_and_confirmation_batch_call(200, 200)),
1645+
Err(TransactionValidityError::Invalid(InvalidTransaction::Call)),
1646+
);
1647+
});
1648+
}
1649+
1650+
#[test]
1651+
fn ext_rejects_transaction_when_messages_pallet_is_halted() {
1652+
run_test(|| {
1653+
initialize_environment(100, 100, 100);
1654+
1655+
MessagesPallet::<TestRuntime, ()>::set_operating_mode(
1656+
RuntimeOrigin::root(),
1657+
MessagesOperatingMode::Basic(BasicOperatingMode::Halted),
1658+
)
1659+
.unwrap();
1660+
1661+
assert_eq!(
1662+
run_pre_dispatch(all_finality_and_delivery_batch_call(200, 200, 200)),
1663+
Err(TransactionValidityError::Invalid(InvalidTransaction::Call)),
1664+
);
1665+
assert_eq!(
1666+
run_pre_dispatch(all_finality_and_confirmation_batch_call(200, 200, 200)),
1667+
Err(TransactionValidityError::Invalid(InvalidTransaction::Call)),
1668+
);
1669+
1670+
assert_eq!(
1671+
run_pre_dispatch(parachain_finality_and_delivery_batch_call(200, 200)),
1672+
Err(TransactionValidityError::Invalid(InvalidTransaction::Call)),
1673+
);
1674+
assert_eq!(
1675+
run_pre_dispatch(parachain_finality_and_confirmation_batch_call(200, 200)),
1676+
Err(TransactionValidityError::Invalid(InvalidTransaction::Call)),
1677+
);
1678+
1679+
assert_eq!(
1680+
run_pre_dispatch(message_delivery_call(200)),
1681+
Err(TransactionValidityError::Invalid(InvalidTransaction::Call)),
1682+
);
1683+
assert_eq!(
1684+
run_pre_dispatch(message_confirmation_call(200)),
1685+
Err(TransactionValidityError::Invalid(InvalidTransaction::Call)),
1686+
);
1687+
});
1688+
}
1689+
15951690
#[test]
15961691
fn pre_dispatch_parses_batch_with_relay_chain_and_parachain_headers() {
15971692
run_test(|| {

bridges/modules/beefy/src/lib.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -601,7 +601,7 @@ mod tests {
601601
.is_some());
602602
assert_eq!(
603603
ImportedBlockNumbers::<TestRuntime>::get(index),
604-
Some(index + 1).map(Into::into)
604+
Some(Into::into(index + 1)),
605605
);
606606
}
607607

@@ -619,7 +619,7 @@ mod tests {
619619
.is_some());
620620
assert_eq!(
621621
ImportedBlockNumbers::<TestRuntime>::get(0),
622-
Some(commitments_to_keep + 1).map(Into::into)
622+
Some(Into::into(commitments_to_keep + 1)),
623623
);
624624
// the side effect of the import is that the commitment#1 is pruned
625625
assert!(ImportedCommitments::<TestRuntime>::get(1).is_none());
@@ -638,7 +638,7 @@ mod tests {
638638
.is_some());
639639
assert_eq!(
640640
ImportedBlockNumbers::<TestRuntime>::get(1),
641-
Some(commitments_to_keep + 2).map(Into::into)
641+
Some(Into::into(commitments_to_keep + 2)),
642642
);
643643
// the side effect of the import is that the commitment#2 is pruned
644644
assert!(ImportedCommitments::<TestRuntime>::get(1).is_none());

bridges/modules/grandpa/src/call_ext.rs

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
use crate::{weights::WeightInfo, BridgedBlockNumber, BridgedHeader, Config, Error, Pallet};
1818
use bp_header_chain::{justification::GrandpaJustification, ChainWithGrandpa};
19-
use bp_runtime::BlockNumberOf;
19+
use bp_runtime::{BlockNumberOf, OwnedBridgeModule};
2020
use codec::Encode;
2121
use frame_support::{dispatch::CallableCallFor, traits::IsSubType, weights::Weight};
2222
use sp_runtime::{
@@ -126,6 +126,10 @@ pub trait CallSubType<T: Config<I, RuntimeCall = Self>, I: 'static>:
126126
_ => return Ok(ValidTransaction::default()),
127127
};
128128

129+
if Pallet::<T, I>::ensure_not_halted().is_err() {
130+
return InvalidTransaction::Call.into()
131+
}
132+
129133
match SubmitFinalityProofHelper::<T, I>::check_obsolete(finality_target.block_number) {
130134
Ok(_) => Ok(ValidTransaction::default()),
131135
Err(Error::<T, I>::OldHeader) => InvalidTransaction::Stale.into(),
@@ -192,10 +196,10 @@ mod tests {
192196
use crate::{
193197
call_ext::CallSubType,
194198
mock::{run_test, test_header, RuntimeCall, TestBridgedChain, TestNumber, TestRuntime},
195-
BestFinalized, Config, WeightInfo,
199+
BestFinalized, Config, PalletOperatingMode, WeightInfo,
196200
};
197201
use bp_header_chain::ChainWithGrandpa;
198-
use bp_runtime::HeaderId;
202+
use bp_runtime::{BasicOperatingMode, HeaderId};
199203
use bp_test_utils::{
200204
make_default_justification, make_justification_for_header, JustificationGeneratorParams,
201205
};
@@ -238,6 +242,17 @@ mod tests {
238242
});
239243
}
240244

245+
#[test]
246+
fn extension_rejects_new_header_if_pallet_is_halted() {
247+
run_test(|| {
248+
// when pallet is halted => tx is rejected
249+
sync_to_header_10();
250+
PalletOperatingMode::<TestRuntime, ()>::put(BasicOperatingMode::Halted);
251+
252+
assert!(!validate_block_submit(15));
253+
});
254+
}
255+
241256
#[test]
242257
fn extension_accepts_new_header() {
243258
run_test(|| {

bridges/modules/parachains/src/call_ext.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use crate::{Config, Pallet, RelayBlockNumber};
1818
use bp_parachains::BestParaHeadHash;
1919
use bp_polkadot_core::parachains::{ParaHash, ParaId};
20+
use bp_runtime::OwnedBridgeModule;
2021
use frame_support::{dispatch::CallableCallFor, traits::IsSubType};
2122
use sp_runtime::{
2223
transaction_validity::{InvalidTransaction, TransactionValidity, ValidTransaction},
@@ -141,6 +142,10 @@ pub trait CallSubType<T: Config<I, RuntimeCall = Self>, I: 'static>:
141142
None => return Ok(ValidTransaction::default()),
142143
};
143144

145+
if Pallet::<T, I>::ensure_not_halted().is_err() {
146+
return InvalidTransaction::Call.into()
147+
}
148+
144149
if SubmitParachainHeadsHelper::<T, I>::is_obsolete(&update) {
145150
return InvalidTransaction::Stale.into()
146151
}
@@ -160,10 +165,11 @@ where
160165
mod tests {
161166
use crate::{
162167
mock::{run_test, RuntimeCall, TestRuntime},
163-
CallSubType, ParaInfo, ParasInfo, RelayBlockNumber,
168+
CallSubType, PalletOperatingMode, ParaInfo, ParasInfo, RelayBlockNumber,
164169
};
165170
use bp_parachains::BestParaHeadHash;
166171
use bp_polkadot_core::parachains::{ParaHash, ParaHeadsProof, ParaId};
172+
use bp_runtime::BasicOperatingMode;
167173

168174
fn validate_submit_parachain_heads(
169175
num: RelayBlockNumber,
@@ -221,6 +227,17 @@ mod tests {
221227
});
222228
}
223229

230+
#[test]
231+
fn extension_rejects_header_if_pallet_is_halted() {
232+
run_test(|| {
233+
// when pallet is halted => tx is rejected
234+
sync_to_relay_header_10();
235+
PalletOperatingMode::<TestRuntime, ()>::put(BasicOperatingMode::Halted);
236+
237+
assert!(!validate_submit_parachain_heads(15, vec![(ParaId(1), [2u8; 32].into())]));
238+
});
239+
}
240+
224241
#[test]
225242
fn extension_accepts_new_header() {
226243
run_test(|| {

0 commit comments

Comments
 (0)