diff --git a/Cargo.lock b/Cargo.lock index 01a0ad13299..db42baed86a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6264,6 +6264,7 @@ dependencies = [ "frame-executive", "frame-support", "frame-system", + "log", "pallet-asset-tx-payment", "pallet-assets", "pallet-authorship", diff --git a/polkadot-parachains/parachains-common/Cargo.toml b/polkadot-parachains/parachains-common/Cargo.toml index 6099b2036c3..64ac36f3b35 100644 --- a/polkadot-parachains/parachains-common/Cargo.toml +++ b/polkadot-parachains/parachains-common/Cargo.toml @@ -11,6 +11,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] # External dependencies codec = { package = "parity-scale-codec", version = "2.3.0", features = ["derive"], default-features = false } +log = { version = "0.4.14", default-features = false } scale-info = { version = "1.0.0", default-features = false, features = ["derive"] } # Substrate dependencies diff --git a/polkadot-parachains/parachains-common/src/impls.rs b/polkadot-parachains/parachains-common/src/impls.rs index b5919f736c9..ad06e3e3d94 100644 --- a/polkadot-parachains/parachains-common/src/impls.rs +++ b/polkadot-parachains/parachains-common/src/impls.rs @@ -98,14 +98,33 @@ where } } +/// Tests `loc` whether it starts with `prefix`. +/// Similar to `MultiLocation::match_and_split` but allows arbitrary suffixes (instead of just one +/// junction). +// TODO: Replace usage with `starts_with` implemented on MultiLocation here once XCM v3 is merged: +// https://github.com/paritytech/polkadot/pull/4835 +fn matches_prefix(prefix: &MultiLocation, loc: &MultiLocation) -> bool { + prefix.parent_count() == loc.parent_count() && + loc.len() >= prefix.len() && + prefix + .interior() + .iter() + .zip(loc.interior().iter()) + .all(|(prefix_junction, junction)| prefix_junction == junction) +} + /// Asset filter that allows all assets from a certain location. pub struct AssetsFrom(PhantomData); impl> FilterAssetLocation for AssetsFrom { fn filter_asset_location(asset: &MultiAsset, origin: &MultiLocation) -> bool { - let loc = T::get(); - &loc == origin && - matches!(asset, MultiAsset { id: AssetId::Concrete(asset_loc), fun: Fungible(_a) } - if asset_loc.match_and_split(&loc).is_some()) + let prefix = T::get(); + log::trace!(target: "xcm::AssetsFrom", "prefix: {:?}, origin: {:?}", prefix, origin); + &prefix == origin && + match asset { + MultiAsset { id: AssetId::Concrete(asset_loc), fun: Fungible(_a) } => + matches_prefix(&prefix, asset_loc), + _ => false, + } } } @@ -261,22 +280,81 @@ mod tests { } #[test] - fn assets_from_filters_correctly() { + fn test_matches_prefix_works() { + let prefix = MultiLocation::new(1, X1(Parachain(1234))); + let loc = MultiLocation::new(1, X2(Parachain(1234), GeneralIndex(5))); + assert!(matches_prefix(&prefix, &loc)); + let failing = MultiLocation::new(1, Here); + assert!(!matches_prefix(&prefix, &failing)); + } + + mod assets_from { + use super::*; + parameter_types! { pub SomeSiblingParachain: MultiLocation = MultiLocation::new(1, X1(Parachain(1234))); } - let asset_location = SomeSiblingParachain::get() - .clone() - .pushed_with_interior(GeneralIndex(42)) - .expect("multilocation will only have 2 junctions; qed"); - let asset = MultiAsset { id: Concrete(asset_location), fun: 1_000_000.into() }; - assert!( - AssetsFrom::::filter_asset_location( - &asset, - &SomeSiblingParachain::get() - ), - "AssetsFrom should allow assets from any of its interior locations" - ); + #[test] + fn accepts_native_asset() { + let asset_location = SomeSiblingParachain::get(); + let asset = MultiAsset { id: Concrete(asset_location), fun: 1_000_000.into() }; + assert!( + AssetsFrom::::filter_asset_location( + &asset, + &SomeSiblingParachain::get() + ), + "AssetsFrom should allow the native asset" + ); + } + + #[test] + fn filters_correctly() { + let asset_location = SomeSiblingParachain::get() + .clone() + .pushed_with_interior(GeneralIndex(42)) + .expect("multilocation will only have 2 junctions; qed"); + let asset = MultiAsset { id: Concrete(asset_location), fun: 1_000_000.into() }; + assert!( + AssetsFrom::::filter_asset_location( + &asset, + &SomeSiblingParachain::get() + ), + "AssetsFrom should allow assets from any of its interior locations" + ); + } + + #[test] + fn accepts_long_suffix() { + // make sure assets can have more than one junction inside the prefix location + let asset_location = SomeSiblingParachain::get() + .clone() + .pushed_with_interior(PalletInstance(50)) + .unwrap() + .pushed_with_interior(GeneralIndex(42)) + .expect("multilocation will only have 3 junctions; qed"); + let asset = MultiAsset { id: Concrete(asset_location), fun: 1_000_000.into() }; + assert!( + AssetsFrom::::filter_asset_location( + &asset, + &SomeSiblingParachain::get() + ), + "AssetsFrom should allow assets from any of its interior locations" + ); + } + + #[test] + fn rejects_short_location() { + let asset_location = MultiLocation::parent(); + // make sure assets can have more than one junction inside the prefix location + let asset = MultiAsset { id: Concrete(asset_location), fun: 1_000_000.into() }; + assert!( + !AssetsFrom::::filter_asset_location( + &asset, + &SomeSiblingParachain::get() + ), + "AssetsFrom should filter assets not from the origin" + ); + } } } diff --git a/polkadot-parachains/rococo-parachain/src/lib.rs b/polkadot-parachains/rococo-parachain/src/lib.rs index 218d5ff5d6a..7135099d555 100644 --- a/polkadot-parachains/rococo-parachain/src/lib.rs +++ b/polkadot-parachains/rococo-parachain/src/lib.rs @@ -71,8 +71,8 @@ use pallet_xcm::{EnsureXcm, IsMajorityOfBody, XcmPassthrough}; use polkadot_parachain::primitives::Sibling; use xcm::latest::prelude::*; use xcm_builder::{ - AccountId32Aliases, AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, CurrencyAdapter, - EnsureXcmOrigin, FixedWeightBounds, IsConcrete, LocationInverter, NativeAsset, + AccountId32Aliases, AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, Case, + CurrencyAdapter, EnsureXcmOrigin, FixedWeightBounds, IsConcrete, LocationInverter, NativeAsset, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, UsingComponents, @@ -391,9 +391,13 @@ parameter_types! { // Statemint's Assets pallet index pub StatemintAssetsPalletLocation: MultiLocation = MultiLocation::new(1, X2(Parachain(1000), PalletInstance(50))); + pub KsmFilter: MultiAssetFilter = MultiAssetFilter::Wild(WildMultiAsset::AllOf{ id: (1, Here).into(), fun: WildFungibility::Fungible }); + pub KsmFromStatemint: (MultiAssetFilter, MultiLocation) = ( + KsmFilter::get(), StatemintLocation::get() + ); } -pub type Reserves = (NativeAsset, AssetsFrom); +pub type Reserves = (NativeAsset, AssetsFrom, Case); pub struct XcmConfig; impl Config for XcmConfig {