Skip to content

Commit

Permalink
Reject transactions if bridge pallets are halted (paritytech#2600)
Browse files Browse the repository at this point in the history
* reject transactions if bridge pallets are halted

* fixed CI (paritytech#2598)
  • Loading branch information
svyatonik authored and serban300 committed Apr 10, 2024
1 parent 93b4ffb commit 9053c05
Show file tree
Hide file tree
Showing 5 changed files with 152 additions and 14 deletions.
13 changes: 12 additions & 1 deletion bridges/bin/runtime-common/src/messages_call_ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use crate::messages::{
source::FromBridgedChainMessagesDeliveryProof, target::FromBridgedChainMessagesProof,
};
use bp_messages::{target_chain::MessageDispatch, InboundLaneData, LaneId, MessageNonce};
use bp_runtime::OwnedBridgeModule;
use frame_support::{
dispatch::CallableCallFor,
traits::{Get, IsSubType},
Expand Down Expand Up @@ -278,7 +279,17 @@ impl<
}

fn check_obsolete_call(&self) -> TransactionValidity {
let is_pallet_halted = Pallet::<T, I>::ensure_not_halted().is_err();
match self.call_info() {
Some(proof_info) if is_pallet_halted => {
log::trace!(
target: pallet_bridge_messages::LOG_TARGET,
"Rejecting messages transaction on halted pallet: {:?}",
proof_info
);

return sp_runtime::transaction_validity::InvalidTransaction::Call.into()
},
Some(CallInfo::ReceiveMessagesProof(proof_info))
if proof_info.is_obsolete(T::MessageDispatch::is_active()) =>
{
Expand All @@ -291,7 +302,7 @@ impl<
return sp_runtime::transaction_validity::InvalidTransaction::Stale.into()
},
Some(CallInfo::ReceiveMessagesDeliveryProof(proof_info))
if proof_info.is_obsolete() =>
if is_pallet_halted || proof_info.is_obsolete() =>
{
log::trace!(
target: pallet_bridge_messages::LOG_TARGET,
Expand Down
107 changes: 101 additions & 6 deletions bridges/bin/runtime-common/src/refund_relayer_extension.rs
Original file line number Diff line number Diff line change
Expand Up @@ -838,21 +838,23 @@ mod tests {
mock::*,
};
use bp_messages::{
DeliveredMessages, InboundLaneData, MessageNonce, OutboundLaneData, UnrewardedRelayer,
UnrewardedRelayersState,
DeliveredMessages, InboundLaneData, MessageNonce, MessagesOperatingMode, OutboundLaneData,
UnrewardedRelayer, UnrewardedRelayersState,
};
use bp_parachains::{BestParaHeadHash, ParaInfo};
use bp_polkadot_core::parachains::{ParaHeadsProof, ParaId};
use bp_runtime::HeaderId;
use bp_runtime::{BasicOperatingMode, HeaderId};
use bp_test_utils::{make_default_justification, test_keyring};
use frame_support::{
assert_storage_noop, parameter_types,
traits::{fungible::Mutate, ReservableCurrency},
weights::Weight,
};
use pallet_bridge_grandpa::{Call as GrandpaCall, StoredAuthoritySet};
use pallet_bridge_messages::Call as MessagesCall;
use pallet_bridge_parachains::{Call as ParachainsCall, RelayBlockHash};
use pallet_bridge_grandpa::{Call as GrandpaCall, Pallet as GrandpaPallet, StoredAuthoritySet};
use pallet_bridge_messages::{Call as MessagesCall, Pallet as MessagesPallet};
use pallet_bridge_parachains::{
Call as ParachainsCall, Pallet as ParachainsPallet, RelayBlockHash,
};
use sp_runtime::{
traits::{ConstU64, Header as HeaderT},
transaction_validity::{InvalidTransaction, ValidTransaction},
Expand Down Expand Up @@ -1592,6 +1594,99 @@ mod tests {
});
}

#[test]
fn ext_rejects_batch_with_grandpa_finality_proof_when_grandpa_pallet_is_halted() {
run_test(|| {
initialize_environment(100, 100, 100);

GrandpaPallet::<TestRuntime, ()>::set_operating_mode(
RuntimeOrigin::root(),
BasicOperatingMode::Halted,
)
.unwrap();

assert_eq!(
run_pre_dispatch(all_finality_and_delivery_batch_call(200, 200, 200)),
Err(TransactionValidityError::Invalid(InvalidTransaction::Call)),
);
assert_eq!(
run_pre_dispatch(all_finality_and_confirmation_batch_call(200, 200, 200)),
Err(TransactionValidityError::Invalid(InvalidTransaction::Call)),
);
});
}

#[test]
fn ext_rejects_batch_with_parachain_finality_proof_when_parachains_pallet_is_halted() {
run_test(|| {
initialize_environment(100, 100, 100);

ParachainsPallet::<TestRuntime, ()>::set_operating_mode(
RuntimeOrigin::root(),
BasicOperatingMode::Halted,
)
.unwrap();

assert_eq!(
run_pre_dispatch(all_finality_and_delivery_batch_call(200, 200, 200)),
Err(TransactionValidityError::Invalid(InvalidTransaction::Call)),
);
assert_eq!(
run_pre_dispatch(all_finality_and_confirmation_batch_call(200, 200, 200)),
Err(TransactionValidityError::Invalid(InvalidTransaction::Call)),
);

assert_eq!(
run_pre_dispatch(parachain_finality_and_delivery_batch_call(200, 200)),
Err(TransactionValidityError::Invalid(InvalidTransaction::Call)),
);
assert_eq!(
run_pre_dispatch(parachain_finality_and_confirmation_batch_call(200, 200)),
Err(TransactionValidityError::Invalid(InvalidTransaction::Call)),
);
});
}

#[test]
fn ext_rejects_transaction_when_messages_pallet_is_halted() {
run_test(|| {
initialize_environment(100, 100, 100);

MessagesPallet::<TestRuntime, ()>::set_operating_mode(
RuntimeOrigin::root(),
MessagesOperatingMode::Basic(BasicOperatingMode::Halted),
)
.unwrap();

assert_eq!(
run_pre_dispatch(all_finality_and_delivery_batch_call(200, 200, 200)),
Err(TransactionValidityError::Invalid(InvalidTransaction::Call)),
);
assert_eq!(
run_pre_dispatch(all_finality_and_confirmation_batch_call(200, 200, 200)),
Err(TransactionValidityError::Invalid(InvalidTransaction::Call)),
);

assert_eq!(
run_pre_dispatch(parachain_finality_and_delivery_batch_call(200, 200)),
Err(TransactionValidityError::Invalid(InvalidTransaction::Call)),
);
assert_eq!(
run_pre_dispatch(parachain_finality_and_confirmation_batch_call(200, 200)),
Err(TransactionValidityError::Invalid(InvalidTransaction::Call)),
);

assert_eq!(
run_pre_dispatch(message_delivery_call(200)),
Err(TransactionValidityError::Invalid(InvalidTransaction::Call)),
);
assert_eq!(
run_pre_dispatch(message_confirmation_call(200)),
Err(TransactionValidityError::Invalid(InvalidTransaction::Call)),
);
});
}

#[test]
fn pre_dispatch_parses_batch_with_relay_chain_and_parachain_headers() {
run_test(|| {
Expand Down
6 changes: 3 additions & 3 deletions bridges/modules/beefy/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -601,7 +601,7 @@ mod tests {
.is_some());
assert_eq!(
ImportedBlockNumbers::<TestRuntime>::get(index),
Some(index + 1).map(Into::into)
Some(Into::into(index + 1)),
);
}

Expand All @@ -619,7 +619,7 @@ mod tests {
.is_some());
assert_eq!(
ImportedBlockNumbers::<TestRuntime>::get(0),
Some(commitments_to_keep + 1).map(Into::into)
Some(Into::into(commitments_to_keep + 1)),
);
// the side effect of the import is that the commitment#1 is pruned
assert!(ImportedCommitments::<TestRuntime>::get(1).is_none());
Expand All @@ -638,7 +638,7 @@ mod tests {
.is_some());
assert_eq!(
ImportedBlockNumbers::<TestRuntime>::get(1),
Some(commitments_to_keep + 2).map(Into::into)
Some(Into::into(commitments_to_keep + 2)),
);
// the side effect of the import is that the commitment#2 is pruned
assert!(ImportedCommitments::<TestRuntime>::get(1).is_none());
Expand Down
21 changes: 18 additions & 3 deletions bridges/modules/grandpa/src/call_ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

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

if Pallet::<T, I>::ensure_not_halted().is_err() {
return InvalidTransaction::Call.into()
}

match SubmitFinalityProofHelper::<T, I>::check_obsolete(finality_target.block_number) {
Ok(_) => Ok(ValidTransaction::default()),
Err(Error::<T, I>::OldHeader) => InvalidTransaction::Stale.into(),
Expand Down Expand Up @@ -192,10 +196,10 @@ mod tests {
use crate::{
call_ext::CallSubType,
mock::{run_test, test_header, RuntimeCall, TestBridgedChain, TestNumber, TestRuntime},
BestFinalized, Config, WeightInfo,
BestFinalized, Config, PalletOperatingMode, WeightInfo,
};
use bp_header_chain::ChainWithGrandpa;
use bp_runtime::HeaderId;
use bp_runtime::{BasicOperatingMode, HeaderId};
use bp_test_utils::{
make_default_justification, make_justification_for_header, JustificationGeneratorParams,
};
Expand Down Expand Up @@ -238,6 +242,17 @@ mod tests {
});
}

#[test]
fn extension_rejects_new_header_if_pallet_is_halted() {
run_test(|| {
// when pallet is halted => tx is rejected
sync_to_header_10();
PalletOperatingMode::<TestRuntime, ()>::put(BasicOperatingMode::Halted);

assert!(!validate_block_submit(15));
});
}

#[test]
fn extension_accepts_new_header() {
run_test(|| {
Expand Down
19 changes: 18 additions & 1 deletion bridges/modules/parachains/src/call_ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
use crate::{Config, Pallet, RelayBlockNumber};
use bp_parachains::BestParaHeadHash;
use bp_polkadot_core::parachains::{ParaHash, ParaId};
use bp_runtime::OwnedBridgeModule;
use frame_support::{dispatch::CallableCallFor, traits::IsSubType};
use sp_runtime::{
transaction_validity::{InvalidTransaction, TransactionValidity, ValidTransaction},
Expand Down Expand Up @@ -141,6 +142,10 @@ pub trait CallSubType<T: Config<I, RuntimeCall = Self>, I: 'static>:
None => return Ok(ValidTransaction::default()),
};

if Pallet::<T, I>::ensure_not_halted().is_err() {
return InvalidTransaction::Call.into()
}

if SubmitParachainHeadsHelper::<T, I>::is_obsolete(&update) {
return InvalidTransaction::Stale.into()
}
Expand All @@ -160,10 +165,11 @@ where
mod tests {
use crate::{
mock::{run_test, RuntimeCall, TestRuntime},
CallSubType, ParaInfo, ParasInfo, RelayBlockNumber,
CallSubType, PalletOperatingMode, ParaInfo, ParasInfo, RelayBlockNumber,
};
use bp_parachains::BestParaHeadHash;
use bp_polkadot_core::parachains::{ParaHash, ParaHeadsProof, ParaId};
use bp_runtime::BasicOperatingMode;

fn validate_submit_parachain_heads(
num: RelayBlockNumber,
Expand Down Expand Up @@ -221,6 +227,17 @@ mod tests {
});
}

#[test]
fn extension_rejects_header_if_pallet_is_halted() {
run_test(|| {
// when pallet is halted => tx is rejected
sync_to_relay_header_10();
PalletOperatingMode::<TestRuntime, ()>::put(BasicOperatingMode::Halted);

assert!(!validate_submit_parachain_heads(15, vec![(ParaId(1), [2u8; 32].into())]));
});
}

#[test]
fn extension_accepts_new_header() {
run_test(|| {
Expand Down

0 comments on commit 9053c05

Please sign in to comment.