diff --git a/cumulus/parachain-template/runtime/src/xcm_config.rs b/cumulus/parachain-template/runtime/src/xcm_config.rs index 75f203f97cd326cbeddb5cbd276be9cba4dac0f8..3c77efba37e91b147e2a108807c6f246c20c2635 100644 --- a/cumulus/parachain-template/runtime/src/xcm_config.rs +++ b/cumulus/parachain-template/runtime/src/xcm_config.rs @@ -2,8 +2,9 @@ use super::{ AccountId, Balances, Call, Event, Origin, ParachainInfo, ParachainSystem, PolkadotXcm, Runtime, WeightToFee, XcmpQueue, }; +use core::marker::PhantomData; use frame_support::{ - match_types, parameter_types, + log, match_types, parameter_types, traits::{Everything, Nothing}, weights::Weight, }; @@ -18,7 +19,7 @@ use xcm_builder::{ SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, UsingComponents, }; -use xcm_executor::XcmExecutor; +use xcm_executor::{traits::ShouldExecute, XcmExecutor}; parameter_types! { pub const RelayLocation: MultiLocation = MultiLocation::parent(); @@ -87,12 +88,78 @@ match_types! { }; } -pub type Barrier = ( - TakeWeightCredit, - AllowTopLevelPaidExecutionFrom<Everything>, - AllowUnpaidExecutionFrom<ParentOrParentsExecutivePlurality>, - // ^^^ Parent and its exec plurality get free execution -); +//TODO: move DenyThenTry to polkadot's xcm module. +/// Deny executing the xcm message if it matches any of the Deny filter regardless of anything else. +/// If it passes the Deny, and matches one of the Allow cases then it is let through. +pub struct DenyThenTry<Deny, Allow>(PhantomData<Deny>, PhantomData<Allow>) +where + Deny: ShouldExecute, + Allow: ShouldExecute; + +impl<Deny, Allow> ShouldExecute for DenyThenTry<Deny, Allow> +where + Deny: ShouldExecute, + Allow: ShouldExecute, +{ + fn should_execute<Call>( + origin: &MultiLocation, + message: &mut Xcm<Call>, + max_weight: Weight, + weight_credit: &mut Weight, + ) -> Result<(), ()> { + Deny::should_execute(origin, message, max_weight, weight_credit)?; + Allow::should_execute(origin, message, max_weight, weight_credit) + } +} + +// See issue #5233 +pub struct DenyReserveTransferToRelayChain; +impl ShouldExecute for DenyReserveTransferToRelayChain { + fn should_execute<Call>( + origin: &MultiLocation, + message: &mut Xcm<Call>, + _max_weight: Weight, + _weight_credit: &mut Weight, + ) -> Result<(), ()> { + if message.0.iter().any(|inst| { + matches!( + inst, + InitiateReserveWithdraw { + reserve: MultiLocation { parents: 1, interior: Here }, + .. + } | DepositReserveAsset { dest: MultiLocation { parents: 1, interior: Here }, .. } | + TransferReserveAsset { + dest: MultiLocation { parents: 1, interior: Here }, + .. + } + ) + }) { + return Err(()) // Deny + } + + // allow reserve transfers to arrive from relay chain + if matches!(origin, MultiLocation { parents: 1, interior: Here }) && + message.0.iter().any(|inst| matches!(inst, ReserveAssetDeposited { .. })) + { + log::warn!( + target: "xcm::barriers", + "Unexpected ReserveAssetDeposited from the relay chain", + ); + } + // Permit everything else + Ok(()) + } +} + +pub type Barrier = DenyThenTry< + DenyReserveTransferToRelayChain, + ( + TakeWeightCredit, + AllowTopLevelPaidExecutionFrom<Everything>, + AllowUnpaidExecutionFrom<ParentOrParentsExecutivePlurality>, + // ^^^ Parent and its exec plurality get free execution + ), +>; pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { diff --git a/cumulus/polkadot-parachains/canvas-kusama/src/xcm_config.rs b/cumulus/polkadot-parachains/canvas-kusama/src/xcm_config.rs index c129d4d0162fedef2b8865e865f68b24880b740e..6a33909332c96d7fa97125c1f90ccccd103dd048 100644 --- a/cumulus/polkadot-parachains/canvas-kusama/src/xcm_config.rs +++ b/cumulus/polkadot-parachains/canvas-kusama/src/xcm_config.rs @@ -24,6 +24,7 @@ use frame_support::{ }; use frame_system::EnsureRoot; use pallet_xcm::{EnsureXcm, IsMajorityOfBody, XcmPassthrough}; +use parachains_common::xcm_config::{DenyReserveTransferToRelayChain, DenyThenTry}; use polkadot_parachain::primitives::Sibling; use xcm::latest::prelude::*; use xcm_builder::{ @@ -117,16 +118,19 @@ match_types! { }; } -pub type Barrier = ( - TakeWeightCredit, - AllowTopLevelPaidExecutionFrom<Everything>, - // Parent and its exec plurality get free execution - AllowUnpaidExecutionFrom<ParentOrParentsExecutivePlurality>, - // Expected responses are OK. - AllowKnownQueryResponses<PolkadotXcm>, - // Subscriptions for version tracking are OK. - AllowSubscriptionsFrom<ParentOrSiblings>, -); +pub type Barrier = DenyThenTry< + DenyReserveTransferToRelayChain, + ( + TakeWeightCredit, + AllowTopLevelPaidExecutionFrom<Everything>, + // Parent and its exec plurality get free execution + AllowUnpaidExecutionFrom<ParentOrParentsExecutivePlurality>, + // Expected responses are OK. + AllowKnownQueryResponses<PolkadotXcm>, + // Subscriptions for version tracking are OK. + AllowSubscriptionsFrom<ParentOrSiblings>, + ), +>; pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { diff --git a/cumulus/polkadot-parachains/parachains-common/src/lib.rs b/cumulus/polkadot-parachains/parachains-common/src/lib.rs index c04f0a37798bf18385e25f2313bbd245f53783f4..fcec189a210d4135774381a4f7484b79ffd427e7 100644 --- a/cumulus/polkadot-parachains/parachains-common/src/lib.rs +++ b/cumulus/polkadot-parachains/parachains-common/src/lib.rs @@ -16,9 +16,11 @@ #![cfg_attr(not(feature = "std"), no_std)] pub mod impls; +pub mod xcm_config; pub use constants::*; pub use opaque::*; pub use types::*; + /// Common types of parachains. mod types { use sp_runtime::traits::{IdentifyAccount, Verify}; diff --git a/cumulus/polkadot-parachains/parachains-common/src/xcm_config.rs b/cumulus/polkadot-parachains/parachains-common/src/xcm_config.rs new file mode 100644 index 0000000000000000000000000000000000000000..63b388acaebe5d722ff328cac03cdeeb2f4da038 --- /dev/null +++ b/cumulus/polkadot-parachains/parachains-common/src/xcm_config.rs @@ -0,0 +1,67 @@ +use core::marker::PhantomData; +use frame_support::{log, weights::Weight}; +use xcm::latest::prelude::*; +use xcm_executor::traits::ShouldExecute; + +//TODO: move DenyThenTry to polkadot's xcm module. +/// Deny executing the XCM if it matches any of the Deny filter regardless of anything else. +/// If it passes the Deny, and matches one of the Allow cases then it is let through. +pub struct DenyThenTry<Deny, Allow>(PhantomData<Deny>, PhantomData<Allow>) +where + Deny: ShouldExecute, + Allow: ShouldExecute; + +impl<Deny, Allow> ShouldExecute for DenyThenTry<Deny, Allow> +where + Deny: ShouldExecute, + Allow: ShouldExecute, +{ + fn should_execute<Call>( + origin: &MultiLocation, + message: &mut Xcm<Call>, + max_weight: Weight, + weight_credit: &mut Weight, + ) -> Result<(), ()> { + Deny::should_execute(origin, message, max_weight, weight_credit)?; + Allow::should_execute(origin, message, max_weight, weight_credit) + } +} + +// See issue #5233 +pub struct DenyReserveTransferToRelayChain; +impl ShouldExecute for DenyReserveTransferToRelayChain { + fn should_execute<Call>( + origin: &MultiLocation, + message: &mut Xcm<Call>, + _max_weight: Weight, + _weight_credit: &mut Weight, + ) -> Result<(), ()> { + if message.0.iter().any(|inst| { + matches!( + inst, + InitiateReserveWithdraw { + reserve: MultiLocation { parents: 1, interior: Here }, + .. + } | DepositReserveAsset { dest: MultiLocation { parents: 1, interior: Here }, .. } | + TransferReserveAsset { + dest: MultiLocation { parents: 1, interior: Here }, + .. + } + ) + }) { + return Err(()) // Deny + } + + // allow reserve transfers to arrive from relay chain + if matches!(origin, MultiLocation { parents: 1, interior: Here }) && + message.0.iter().any(|inst| matches!(inst, ReserveAssetDeposited { .. })) + { + log::info!( + target: "runtime::xcm-barier", + "Unexpected Reserve Assets Deposited on the relay chain", + ); + } + // Permit everything else + Ok(()) + } +} diff --git a/cumulus/polkadot-parachains/statemine/src/xcm_config.rs b/cumulus/polkadot-parachains/statemine/src/xcm_config.rs index 9bf8b827f1f83c7aec17d8d943807933789cfe80..7ace1bf2b32031ebed9f95845e4ee0317e309a54 100644 --- a/cumulus/polkadot-parachains/statemine/src/xcm_config.rs +++ b/cumulus/polkadot-parachains/statemine/src/xcm_config.rs @@ -23,7 +23,10 @@ use frame_support::{ weights::Weight, }; use pallet_xcm::XcmPassthrough; -use parachains_common::impls::ToStakingPot; +use parachains_common::{ + impls::ToStakingPot, + xcm_config::{DenyReserveTransferToRelayChain, DenyThenTry}, +}; use polkadot_parachain::primitives::Sibling; use xcm::latest::prelude::*; use xcm_builder::{ @@ -139,16 +142,19 @@ match_types! { }; } -pub type Barrier = ( - TakeWeightCredit, - AllowTopLevelPaidExecutionFrom<Everything>, - // Parent and its exec plurality get free execution - AllowUnpaidExecutionFrom<ParentOrParentsExecutivePlurality>, - // Expected responses are OK. - AllowKnownQueryResponses<PolkadotXcm>, - // Subscriptions for version tracking are OK. - AllowSubscriptionsFrom<ParentOrSiblings>, -); +pub type Barrier = DenyThenTry< + DenyReserveTransferToRelayChain, + ( + TakeWeightCredit, + AllowTopLevelPaidExecutionFrom<Everything>, + // Parent and its exec plurality get free execution + AllowUnpaidExecutionFrom<ParentOrParentsExecutivePlurality>, + // Expected responses are OK. + AllowKnownQueryResponses<PolkadotXcm>, + // Subscriptions for version tracking are OK. + AllowSubscriptionsFrom<ParentOrSiblings>, + ), +>; pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { diff --git a/cumulus/polkadot-parachains/statemint/src/xcm_config.rs b/cumulus/polkadot-parachains/statemint/src/xcm_config.rs index bb4d16b4746da8b1d65e93347f9ed02637538d5a..f7f72065937487701e0668cc658c2667a8508587 100644 --- a/cumulus/polkadot-parachains/statemint/src/xcm_config.rs +++ b/cumulus/polkadot-parachains/statemint/src/xcm_config.rs @@ -23,7 +23,10 @@ use frame_support::{ weights::Weight, }; use pallet_xcm::XcmPassthrough; -use parachains_common::impls::ToStakingPot; +use parachains_common::{ + impls::ToStakingPot, + xcm_config::{DenyReserveTransferToRelayChain, DenyThenTry}, +}; use polkadot_parachain::primitives::Sibling; use xcm::latest::prelude::*; use xcm_builder::{ @@ -139,16 +142,19 @@ match_types! { }; } -pub type Barrier = ( - TakeWeightCredit, - AllowTopLevelPaidExecutionFrom<Everything>, - // Parent and its exec plurality get free execution - AllowUnpaidExecutionFrom<ParentOrParentsExecutivePlurality>, - // Expected responses are OK. - AllowKnownQueryResponses<PolkadotXcm>, - // Subscriptions for version tracking are OK. - AllowSubscriptionsFrom<ParentOrSiblings>, -); +pub type Barrier = DenyThenTry< + DenyReserveTransferToRelayChain, + ( + TakeWeightCredit, + AllowTopLevelPaidExecutionFrom<Everything>, + // Parent and its exec plurality get free execution + AllowUnpaidExecutionFrom<ParentOrParentsExecutivePlurality>, + // Expected responses are OK. + AllowKnownQueryResponses<PolkadotXcm>, + // Subscriptions for version tracking are OK. + AllowSubscriptionsFrom<ParentOrSiblings>, + ), +>; pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { diff --git a/cumulus/polkadot-parachains/westmint/src/xcm_config.rs b/cumulus/polkadot-parachains/westmint/src/xcm_config.rs index d95cbe7cfd0599cde9a67f088f187a3bdcc9139f..c0dd1da1fd75433ae89ad05f1b27b17d27f15219 100644 --- a/cumulus/polkadot-parachains/westmint/src/xcm_config.rs +++ b/cumulus/polkadot-parachains/westmint/src/xcm_config.rs @@ -23,7 +23,10 @@ use frame_support::{ weights::Weight, }; use pallet_xcm::XcmPassthrough; -use parachains_common::impls::ToStakingPot; +use parachains_common::{ + impls::ToStakingPot, + xcm_config::{DenyReserveTransferToRelayChain, DenyThenTry}, +}; use polkadot_parachain::primitives::Sibling; use xcm::latest::prelude::*; use xcm_builder::{ @@ -135,16 +138,19 @@ match_types! { }; } -pub type Barrier = ( - TakeWeightCredit, - AllowTopLevelPaidExecutionFrom<Everything>, - // Parent and its plurality get free execution - AllowUnpaidExecutionFrom<ParentOrParentsPlurality>, - // Expected responses are OK. - AllowKnownQueryResponses<PolkadotXcm>, - // Subscriptions for version tracking are OK. - AllowSubscriptionsFrom<Everything>, -); +pub type Barrier = DenyThenTry< + DenyReserveTransferToRelayChain, + ( + TakeWeightCredit, + AllowTopLevelPaidExecutionFrom<Everything>, + // Parent and its plurality get free execution + AllowUnpaidExecutionFrom<ParentOrParentsPlurality>, + // Expected responses are OK. + AllowKnownQueryResponses<PolkadotXcm>, + // Subscriptions for version tracking are OK. + AllowSubscriptionsFrom<Everything>, + ), +>; pub struct XcmConfig; impl xcm_executor::Config for XcmConfig {