Skip to content

Commit

Permalink
pallet-xcm: filter assets teleports based on XcmExecutor configuration
Browse files Browse the repository at this point in the history
Add AssetTransferFilter trait for configuring transfer types.
Implement it for XcmExecutor based on existing executor teleports and
reserves configuration.
Filter assets on pallet-xcm::limited_teleport_assets() based on above.
  • Loading branch information
acatangiu committed Sep 25, 2023
1 parent b2a3d89 commit ae6290a
Show file tree
Hide file tree
Showing 11 changed files with 84 additions and 78 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -519,12 +519,6 @@ asset_test_utils::include_teleports_for_native_asset_works!(
_ => None,
}
}),
Box::new(|runtime_event_encoded: Vec<u8>| {
match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) {
Ok(RuntimeEvent::XcmpQueue(event)) => Some(event),
_ => None,
}
}),
1000
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -532,12 +532,6 @@ asset_test_utils::include_teleports_for_native_asset_works!(
_ => None,
}
}),
Box::new(|runtime_event_encoded: Vec<u8>| {
match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) {
Ok(RuntimeEvent::XcmpQueue(event)) => Some(event),
_ => None,
}
}),
1000
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -526,12 +526,6 @@ asset_test_utils::include_teleports_for_native_asset_works!(
_ => None,
}
}),
Box::new(|runtime_event_encoded: Vec<u8>| {
match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) {
Ok(RuntimeEvent::XcmpQueue(event)) => Some(event),
_ => None,
}
}),
1000
);

Expand Down
57 changes: 25 additions & 32 deletions cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ type RuntimeHelper<Runtime, AllPalletsWithoutSystem = ()> =
// Re-export test_case from `parachains-runtimes-test-utils`
pub use parachains_runtimes_test_utils::test_cases::change_storage_constant_by_governance_works;

/// Test-case makes sure that `Runtime` can receive native asset from relay chain
/// and can teleport it back and to the other parachains
/// Test-case makes sure that `Runtime` can receive native asset from relay chain and can teleport
/// it back
pub fn teleports_for_native_asset_works<
Runtime,
AllPalletsWithoutSystem,
Expand All @@ -56,9 +56,6 @@ pub fn teleports_for_native_asset_works<
existential_deposit: BalanceOf<Runtime>,
target_account: AccountIdOf<Runtime>,
unwrap_pallet_xcm_event: Box<dyn Fn(Vec<u8>) -> Option<pallet_xcm::Event<Runtime>>>,
unwrap_xcmp_queue_event: Box<
dyn Fn(Vec<u8>) -> Option<cumulus_pallet_xcmp_queue::Event<Runtime>>,
>,
runtime_para_id: u32,
) where
Runtime: frame_system::Config
Expand Down Expand Up @@ -204,7 +201,8 @@ pub fn teleports_for_native_asset_works<
);
}

// 3. try to teleport asset away to other parachain (1234)
// 3. try to teleport assets away to other parachain (1234): should not work as we don't
// trust `IsTeleporter` for `(relay-native-asset, para(1234))` pair
{
let other_para_id = 1234;
let dest = MultiLocation::new(1, X1(Parachain(other_para_id)));
Expand All @@ -217,41 +215,38 @@ pub fn teleports_for_native_asset_works<

let target_account_balance_before_teleport =
<pallet_balances::Pallet<Runtime>>::free_balance(&target_account);

let native_asset_to_teleport_away = native_asset_amount_unit * 3.into();
assert!(
native_asset_to_teleport_away <
target_account_balance_before_teleport - existential_deposit
);

assert_ok!(RuntimeHelper::<Runtime>::do_teleport_assets::<HrmpChannelOpener>(
RuntimeHelper::<Runtime>::origin_of(target_account.clone()),
dest,
dest_beneficiary,
(native_asset_id, native_asset_to_teleport_away.into()),
Some((runtime_para_id, other_para_id)),
included_head,
&alice,
));
assert_eq!(
RuntimeHelper::<Runtime>::do_teleport_assets::<HrmpChannelOpener>(
RuntimeHelper::<Runtime>::origin_of(target_account.clone()),
dest,
dest_beneficiary,
(native_asset_id, native_asset_to_teleport_away.into()),
Some((runtime_para_id, other_para_id)),
included_head,
&alice,
),
Err(DispatchError::Module(sp_runtime::ModuleError {
index: 31,
error: [2, 0, 0, 0,],
message: Some("Filtered",),
},),)
);

// check balances
assert_eq!(
<pallet_balances::Pallet<Runtime>>::free_balance(&target_account),
target_account_balance_before_teleport - native_asset_to_teleport_away
target_account_balance_before_teleport
);
assert_eq!(
<pallet_balances::Pallet<Runtime>>::free_balance(&CheckingAccount::get()),
0.into()
);

// check events
RuntimeHelper::<Runtime>::assert_pallet_xcm_event_outcome(
&unwrap_pallet_xcm_event,
|outcome| {
assert_ok!(outcome.ensure_complete());
},
);
assert!(RuntimeHelper::<Runtime>::xcmp_queue_message_sent(unwrap_xcmp_queue_event)
.is_some());
}
})
}
Expand All @@ -268,7 +263,6 @@ macro_rules! include_teleports_for_native_asset_works(
$collator_session_key:expr,
$existential_deposit:expr,
$unwrap_pallet_xcm_event:expr,
$unwrap_xcmp_queue_event:expr,
$runtime_para_id:expr
) => {
#[test]
Expand All @@ -288,15 +282,14 @@ macro_rules! include_teleports_for_native_asset_works(
$existential_deposit,
target_account,
$unwrap_pallet_xcm_event,
$unwrap_xcmp_queue_event,
$runtime_para_id
)
}
}
);

/// Test-case makes sure that `Runtime` can receive teleported assets from sibling parachain relay
/// chain
/// Test-case makes sure that `Runtime` can receive teleported assets from sibling parachain, and
/// can teleport it back
pub fn teleports_for_foreign_assets_works<
Runtime,
AllPalletsWithoutSystem,
Expand Down Expand Up @@ -442,7 +435,7 @@ pub fn teleports_for_foreign_assets_works<
>(foreign_asset_id_multilocation, 0, 0);
assert!(teleported_foreign_asset_amount > asset_minimum_asset_balance);

// 1. process received teleported assets from relaychain
// 1. process received teleported assets from sibling parachain (foreign_para_id)
let xcm = Xcm(vec![
// BuyExecution with relaychain native token
WithdrawAsset(buy_execution_fee.clone().into()),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,5 @@ bridge_hub_test_utils::test_cases::include_teleports_for_native_asset_works!(
_ => None,
}
}),
Box::new(|runtime_event_encoded: Vec<u8>| {
match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) {
Ok(RuntimeEvent::XcmpQueue(event)) => Some(event),
_ => None,
}
}),
1002
);
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,5 @@ bridge_hub_test_utils::test_cases::include_teleports_for_native_asset_works!(
_ => None,
}
}),
Box::new(|runtime_event_encoded: Vec<u8>| {
match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) {
Ok(RuntimeEvent::XcmpQueue(event)) => Some(event),
_ => None,
}
}),
1002
);
Original file line number Diff line number Diff line change
Expand Up @@ -118,12 +118,6 @@ mod bridge_hub_rococo_tests {
_ => None,
}
}),
Box::new(|runtime_event_encoded: Vec<u8>| {
match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) {
Ok(RuntimeEvent::XcmpQueue(event)) => Some(event),
_ => None,
}
}),
bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID
);

Expand Down Expand Up @@ -297,12 +291,6 @@ mod bridge_hub_wococo_tests {
_ => None,
}
}),
Box::new(|runtime_event_encoded: Vec<u8>| {
match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) {
Ok(RuntimeEvent::XcmpQueue(event)) => Some(event),
_ => None,
}
}),
bp_bridge_hub_wococo::BRIDGE_HUB_WOCOCO_PARACHAIN_ID
);

Expand Down
22 changes: 20 additions & 2 deletions polkadot/xcm/pallet-xcm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ use sp_runtime::{
};
use sp_std::{boxed::Box, marker::PhantomData, prelude::*, result::Result, vec};
use xcm::{latest::QueryResponseInfo, prelude::*};
use xcm_executor::traits::{ConvertOrigin, Properties};
use xcm_executor::traits::{AssetTransferFilter, ConvertOrigin, Properties};

use frame_support::{
dispatch::GetDispatchInfo, pallet_prelude::*, traits::WithdrawReasons, PalletId,
Expand Down Expand Up @@ -206,7 +206,7 @@ pub mod pallet {
type XcmExecuteFilter: Contains<(MultiLocation, Xcm<<Self as Config>::RuntimeCall>)>;

/// Something to execute an XCM message.
type XcmExecutor: ExecuteXcm<<Self as Config>::RuntimeCall>;
type XcmExecutor: ExecuteXcm<<Self as Config>::RuntimeCall> + AssetTransferFilter;

/// Our XCM filter which messages to be teleported using the dedicated extrinsic must pass.
type XcmTeleportFilter: Contains<(MultiLocation, Vec<MultiAsset>)>;
Expand Down Expand Up @@ -1212,6 +1212,18 @@ impl<T: Config> Pallet<T> {
let value = (origin_location, assets.into_inner());
ensure!(T::XcmReserveTransferFilter::contains(&value), Error::<T>::Filtered);
let (origin_location, assets) = value;
// Don't allow inclusion of teleportable assets in this reserve-based-transfer (other than
// fee asset).
for (idx, asset) in assets.iter().enumerate() {
ensure!(
idx == fee_asset_item as usize ||
!<T::XcmExecutor as AssetTransferFilter>::IsTeleporter::contains(
asset, &dest
),
Error::<T>::Filtered
);
}

let context = T::UniversalLocation::get();
let fees = assets
.get(fee_asset_item as usize)
Expand Down Expand Up @@ -1256,6 +1268,12 @@ impl<T: Config> Pallet<T> {
let value = (origin_location, assets.into_inner());
ensure!(T::XcmTeleportFilter::contains(&value), Error::<T>::Filtered);
let (origin_location, assets) = value;
for asset in assets.iter() {
ensure!(
<T::XcmExecutor as AssetTransferFilter>::IsTeleporter::contains(asset, &dest),
Error::<T>::Filtered
);
}
let context = T::UniversalLocation::get();
let fees = assets
.get(fee_asset_item as usize)
Expand Down
6 changes: 6 additions & 0 deletions polkadot/xcm/xcm-executor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ use traits::{
mod assets;
pub use assets::Assets;
mod config;
use crate::traits::AssetTransferFilter;
pub use config::Config;

/// A struct to specify how fees are being paid.
Expand Down Expand Up @@ -254,6 +255,11 @@ impl<Config: config::Config> ExecuteXcm<Config::RuntimeCall> for XcmExecutor<Con
}
}

impl<Config: config::Config> AssetTransferFilter for XcmExecutor<Config> {
type IsReserve = Config::IsReserve;
type IsTeleporter = Config::IsTeleporter;
}

#[derive(Debug)]
pub struct ExecutorError {
pub index: u32,
Expand Down
29 changes: 29 additions & 0 deletions polkadot/xcm/xcm-executor/src/traits/asset_transfer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright (C) Parity Technologies (UK) Ltd.
// This file is part of Polkadot.

// Polkadot is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Polkadot is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.

use frame_support::traits::ContainsPair;
use xcm::prelude::*;

/// A trait for identifying asset transfer type.
pub trait AssetTransferFilter {
/// Combinations of (Asset, Location) pairs which we trust as reserves. Meaning
/// reserve-based-transfers are to be used for assets matching this filter.
type IsReserve: ContainsPair<MultiAsset, MultiLocation>;

/// Combinations of (Asset, Location) pairs which we trust as teleporters. Meaning teleports are
/// to be used for assets matching this filter.
type IsTeleporter: ContainsPair<MultiAsset, MultiLocation>;
}
6 changes: 4 additions & 2 deletions polkadot/xcm/xcm-executor/src/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,12 @@ mod conversion;
pub use conversion::{CallDispatcher, ConvertLocation, ConvertOrigin, WithOriginFilter};
mod drop_assets;
pub use drop_assets::{ClaimAssets, DropAssets};
mod asset_lock;
pub use asset_lock::{AssetLock, Enact, LockError};
mod asset_exchange;
pub use asset_exchange::AssetExchange;
mod asset_lock;
pub use asset_lock::{AssetLock, Enact, LockError};
mod asset_transfer;
pub use asset_transfer::AssetTransferFilter;
mod export;
pub use export::{export_xcm, validate_export, ExportXcm};
mod fee_manager;
Expand Down

0 comments on commit ae6290a

Please sign in to comment.