Skip to content

Commit

Permalink
[xcm] Small enhancements for NetworkExportTable and xcm-builder (#…
Browse files Browse the repository at this point in the history
…1848)

## Summary

This PR introduces several enhancements.

The current implementation of `NetworkExportTable` lacks remote location
filtering support beyond `NetworkId` lookup. To provide more control and
granularity, it's essential to allow configuration for bridging to
different consensus `NetworkId` while restricting access e.g. to
particular remote parachains.

Additionally, the `StartsWith` and `Equals` and
`StartsWithExplicitGlobalConsensus` helper functions, which are in
active use, are moved to the `xcm-builder` and `frame_support` modules
for better code organization.

Adds a new `LocationWithAssetFilters` filter to enable location-based
and asset-related filtering. This filter is useful for configuring the
`pallet_xcm` filter for
[XcmTeleportFilter](https://github.com/paritytech/polkadot-sdk/blob/master/polkadot/xcm/pallet-xcm/src/lib.rs#L212)
and
[XcmReserveTransferFilter](https://github.com/paritytech/polkadot-sdk/blob/master/polkadot/xcm/pallet-xcm/src/lib.rs#L216)
to restrict specific assets.

Furthermore, the `BridgeMessage` fields are not accessible outside of
`xcm-builder`, limiting the ability to create custom logic dependent on
it.

---------

Co-authored-by: Francisco Aguirre <franciscoaguirreperez@gmail.com>
  • Loading branch information
bkontur and franciscoaguirre authored Oct 17, 2023
1 parent e10de2e commit 5cdd819
Show file tree
Hide file tree
Showing 17 changed files with 412 additions and 74 deletions.
13 changes: 10 additions & 3 deletions bridges/modules/xcm-bridge-hub-router/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use sp_runtime::{
BuildStorage,
};
use xcm::prelude::*;
use xcm_builder::NetworkExportTable;
use xcm_builder::{NetworkExportTable, NetworkExportTableItem};

pub type AccountId = u64;
type Block = frame_system::mocking::MockBlock<TestRuntime>;
Expand All @@ -53,8 +53,15 @@ parameter_types! {
pub UniversalLocation: InteriorMultiLocation = X2(GlobalConsensus(ThisNetworkId::get()), Parachain(1000));
pub SiblingBridgeHubLocation: MultiLocation = ParentThen(X1(Parachain(1002))).into();
pub BridgeFeeAsset: AssetId = MultiLocation::parent().into();
pub BridgeTable: Vec<(NetworkId, MultiLocation, Option<MultiAsset>)>
= vec![(BridgedNetworkId::get(), SiblingBridgeHubLocation::get(), Some((BridgeFeeAsset::get(), BASE_FEE).into()))];
pub BridgeTable: Vec<NetworkExportTableItem>
= vec![
NetworkExportTableItem::new(
BridgedNetworkId::get(),
None,
SiblingBridgeHubLocation::get(),
Some((BridgeFeeAsset::get(), BASE_FEE).into())
)
];
}

impl frame_system::Config for TestRuntime {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,7 @@ use super::{
use crate::ForeignAssets;
use assets_common::{
local_and_foreign_assets::MatchesLocalAndForeignAssetsMultiLocation,
matching::{
FromSiblingParachain, IsForeignConcreteAsset, StartsWith, StartsWithExplicitGlobalConsensus,
},
matching::{FromSiblingParachain, IsForeignConcreteAsset},
};
use frame_support::{
match_types, parameter_types,
Expand All @@ -45,8 +43,8 @@ use xcm_builder::{
EnsureXcmOrigin, FungiblesAdapter, HashedDescription, IsConcrete, LocalMint, NoChecking,
ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative,
SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32,
SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents,
WeightInfoBounds, WithComputedOrigin, WithUniqueTopic,
SovereignSignedViaLocation, StartsWith, StartsWithExplicitGlobalConsensus, TakeWeightCredit,
TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic,
};
use xcm_executor::{traits::WithOriginFilter, XcmExecutor};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,7 @@ use super::{
ParachainInfo, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin,
TrustBackedAssetsInstance, WeightToFee, XcmpQueue,
};
use assets_common::matching::{
FromSiblingParachain, IsForeignConcreteAsset, StartsWith, StartsWithExplicitGlobalConsensus,
};
use assets_common::matching::{FromSiblingParachain, IsForeignConcreteAsset};
use frame_support::{
match_types, parameter_types,
traits::{ConstU32, Contains, Everything, Nothing, PalletInfoAccess},
Expand All @@ -41,8 +39,8 @@ use xcm_builder::{
EnsureXcmOrigin, FungiblesAdapter, HashedDescription, IsConcrete, LocalMint, NoChecking,
ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative,
SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32,
SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents,
WeightInfoBounds, WithComputedOrigin, WithUniqueTopic,
SovereignSignedViaLocation, StartsWith, StartsWithExplicitGlobalConsensus, TakeWeightCredit,
TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic,
};
use xcm_executor::{traits::WithOriginFilter, XcmExecutor};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,7 @@ use super::{
use crate::ForeignAssets;
use assets_common::{
local_and_foreign_assets::MatchesLocalAndForeignAssetsMultiLocation,
matching::{
FromSiblingParachain, IsForeignConcreteAsset, StartsWith, StartsWithExplicitGlobalConsensus,
},
matching::{FromSiblingParachain, IsForeignConcreteAsset},
};
use frame_support::{
match_types, parameter_types,
Expand All @@ -45,8 +43,8 @@ use xcm_builder::{
EnsureXcmOrigin, FungiblesAdapter, HashedDescription, IsConcrete, LocalMint, NoChecking,
ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative,
SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32,
SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents,
WeightInfoBounds, WithComputedOrigin, WithUniqueTopic,
SovereignSignedViaLocation, StartsWith, StartsWithExplicitGlobalConsensus, TakeWeightCredit,
TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic,
};
use xcm_executor::{traits::WithOriginFilter, XcmExecutor};

Expand Down
8 changes: 4 additions & 4 deletions cumulus/parachains/runtimes/assets/common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ pub mod local_and_foreign_assets;
pub mod matching;
pub mod runtime_api;

use crate::matching::{Equals, LocalMultiLocationPattern, ParentLocation, StartsWith};
use frame_support::traits::EverythingBut;
use crate::matching::{LocalMultiLocationPattern, ParentLocation};
use frame_support::traits::{Equals, EverythingBut};
use parachains_common::AssetIdForTrustBackedAssets;
use xcm::prelude::MultiLocation;
use xcm_builder::{AsPrefixedGeneralIndex, MatchedConvertedConcreteId};
use xcm_builder::{AsPrefixedGeneralIndex, MatchedConvertedConcreteId, StartsWith};
use xcm_executor::traits::{Identity, JustTry};

/// `MultiLocation` vs `AssetIdForTrustBackedAssets` converter for `TrustBackedAssets`
Expand Down Expand Up @@ -96,9 +96,9 @@ pub type PoolAssetsConvertedConcreteId<PoolAssetsPalletLocation, Balance> =
#[cfg(test)]
mod tests {
use super::*;
use crate::matching::StartsWithExplicitGlobalConsensus;
use sp_runtime::traits::MaybeEquivalence;
use xcm::latest::prelude::*;
use xcm_builder::StartsWithExplicitGlobalConsensus;
use xcm_executor::traits::{Error as MatchError, MatchesFungibles};

#[test]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -407,13 +407,14 @@ where
#[cfg(test)]
mod tests {
use crate::{
local_and_foreign_assets::MultiLocationConverter, matching::StartsWith,
AssetIdForPoolAssetsConvert, AssetIdForTrustBackedAssetsConvert,
local_and_foreign_assets::MultiLocationConverter, AssetIdForPoolAssetsConvert,
AssetIdForTrustBackedAssetsConvert,
};
use frame_support::traits::EverythingBut;
use pallet_asset_conversion::{MultiAssetIdConversionResult, MultiAssetIdConverter};
use sp_runtime::traits::MaybeEquivalence;
use xcm::latest::prelude::*;
use xcm_builder::StartsWith;

#[test]
fn test_multi_location_converter_works() {
Expand Down
28 changes: 1 addition & 27 deletions cumulus/parachains/runtimes/assets/common/src/matching.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,38 +14,12 @@
// limitations under the License.

use cumulus_primitives_core::ParaId;
use frame_support::{
pallet_prelude::Get,
traits::{Contains, ContainsPair},
};
use frame_support::{pallet_prelude::Get, traits::ContainsPair};
use xcm::{
latest::prelude::{MultiAsset, MultiLocation},
prelude::*,
};

pub struct StartsWith<T>(sp_std::marker::PhantomData<T>);
impl<Location: Get<MultiLocation>> Contains<MultiLocation> for StartsWith<Location> {
fn contains(t: &MultiLocation) -> bool {
t.starts_with(&Location::get())
}
}

pub struct Equals<T>(sp_std::marker::PhantomData<T>);
impl<Location: Get<MultiLocation>> Contains<MultiLocation> for Equals<Location> {
fn contains(t: &MultiLocation) -> bool {
t == &Location::get()
}
}

pub struct StartsWithExplicitGlobalConsensus<T>(sp_std::marker::PhantomData<T>);
impl<Network: Get<NetworkId>> Contains<MultiLocation>
for StartsWithExplicitGlobalConsensus<Network>
{
fn contains(t: &MultiLocation) -> bool {
matches!(t.interior.global_consensus(), Ok(requested_network) if requested_network.eq(&Network::get()))
}
}

frame_support::parameter_types! {
pub LocalMultiLocationPattern: MultiLocation = MultiLocation::new(0, Here);
pub ParentLocation: MultiLocation = MultiLocation::parent();
Expand Down
177 changes: 173 additions & 4 deletions polkadot/xcm/xcm-builder/src/filter_asset_location.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,12 @@
// You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.

//! Various implementations of `ContainsPair<MultiAsset, MultiLocation>`.
//! Various implementations of `ContainsPair<MultiAsset, MultiLocation>` or
//! `Contains<(MultiLocation, Vec<MultiAsset>)>`.

use frame_support::traits::{ContainsPair, Get};
use sp_std::marker::PhantomData;
use xcm::latest::{AssetId::Concrete, MultiAsset, MultiAssetFilter, MultiLocation};
use frame_support::traits::{Contains, ContainsPair, Get};
use sp_std::{marker::PhantomData, vec::Vec};
use xcm::latest::{AssetId::Concrete, MultiAsset, MultiAssetFilter, MultiLocation, WildMultiAsset};

/// Accepts an asset iff it is a native asset.
pub struct NativeAsset;
Expand All @@ -40,3 +41,171 @@ impl<T: Get<(MultiAssetFilter, MultiLocation)>> ContainsPair<MultiAsset, MultiLo
a.matches(asset) && &o == origin
}
}

/// Accepts a tuple `(location, assets)` if the `location` is contained in the `Contains`
/// implementation of the given `Location` and if every asset from `assets` matches at least one of
/// the `MultiAssetFilter` instances provided by the `Get` implementation of `AssetFilters`.
pub struct LocationWithAssetFilters<Location, AssetFilters>(
sp_std::marker::PhantomData<(Location, AssetFilters)>,
);
impl<Location: Contains<MultiLocation>, AssetFilters: Get<Vec<MultiAssetFilter>>>
Contains<(MultiLocation, Vec<MultiAsset>)> for LocationWithAssetFilters<Location, AssetFilters>
{
fn contains((location, assets): &(MultiLocation, Vec<MultiAsset>)) -> bool {
log::trace!(target: "xcm::contains", "LocationWithAssetFilters location: {:?}, assets: {:?}", location, assets);

// `location` must match the `Location` filter.
if !Location::contains(location) {
return false
}

// All `assets` must match at least one of the `AssetFilters`.
let filters = AssetFilters::get();
assets.iter().all(|asset| {
for filter in &filters {
if filter.matches(asset) {
return true
}
}
false
})
}
}

/// Implementation of `Get<Vec<MultiAssetFilter>>` which accepts every asset.
/// (For example, it can be used with `LocationWithAssetFilters`).
pub struct AllAssets;
impl Get<Vec<MultiAssetFilter>> for AllAssets {
fn get() -> Vec<MultiAssetFilter> {
sp_std::vec![MultiAssetFilter::Wild(WildMultiAsset::All)]
}
}

#[cfg(test)]
mod tests {
use super::*;
use frame_support::traits::Equals;
use xcm::latest::prelude::*;

#[test]
fn location_with_asset_filters_works() {
frame_support::parameter_types! {
pub ParaA: MultiLocation = MultiLocation::new(1, X1(Parachain(1001)));
pub ParaB: MultiLocation = MultiLocation::new(1, X1(Parachain(1002)));
pub ParaC: MultiLocation = MultiLocation::new(1, X1(Parachain(1003)));

pub AssetXLocation: MultiLocation = MultiLocation::new(1, X1(GeneralIndex(1111)));
pub AssetYLocation: MultiLocation = MultiLocation::new(1, X1(GeneralIndex(2222)));
pub AssetZLocation: MultiLocation = MultiLocation::new(1, X1(GeneralIndex(3333)));

pub OnlyAssetXOrAssetY: sp_std::vec::Vec<MultiAssetFilter> = sp_std::vec![
Wild(AllOf { fun: WildFungible, id: Concrete(AssetXLocation::get()) }),
Wild(AllOf { fun: WildFungible, id: Concrete(AssetYLocation::get()) }),
];
pub OnlyAssetZ: sp_std::vec::Vec<MultiAssetFilter> = sp_std::vec![
Wild(AllOf { fun: WildFungible, id: Concrete(AssetZLocation::get()) })
];
}

let test_data: Vec<(MultiLocation, Vec<MultiAsset>, bool)> = vec![
(ParaA::get(), vec![(AssetXLocation::get(), 1).into()], true),
(ParaA::get(), vec![(AssetYLocation::get(), 1).into()], true),
(ParaA::get(), vec![(AssetZLocation::get(), 1).into()], false),
(
ParaA::get(),
vec![(AssetXLocation::get(), 1).into(), (AssetYLocation::get(), 1).into()],
true,
),
(
ParaA::get(),
vec![(AssetXLocation::get(), 1).into(), (AssetZLocation::get(), 1).into()],
false,
),
(
ParaA::get(),
vec![(AssetYLocation::get(), 1).into(), (AssetZLocation::get(), 1).into()],
false,
),
(
ParaA::get(),
vec![
(AssetXLocation::get(), 1).into(),
(AssetYLocation::get(), 1).into(),
(AssetZLocation::get(), 1).into(),
],
false,
),
(ParaB::get(), vec![(AssetXLocation::get(), 1).into()], false),
(ParaB::get(), vec![(AssetYLocation::get(), 1).into()], false),
(ParaB::get(), vec![(AssetZLocation::get(), 1).into()], true),
(
ParaB::get(),
vec![(AssetXLocation::get(), 1).into(), (AssetYLocation::get(), 1).into()],
false,
),
(
ParaB::get(),
vec![(AssetXLocation::get(), 1).into(), (AssetZLocation::get(), 1).into()],
false,
),
(
ParaB::get(),
vec![(AssetYLocation::get(), 1).into(), (AssetZLocation::get(), 1).into()],
false,
),
(
ParaB::get(),
vec![
(AssetXLocation::get(), 1).into(),
(AssetYLocation::get(), 1).into(),
(AssetZLocation::get(), 1).into(),
],
false,
),
(ParaC::get(), vec![(AssetXLocation::get(), 1).into()], true),
(ParaC::get(), vec![(AssetYLocation::get(), 1).into()], true),
(ParaC::get(), vec![(AssetZLocation::get(), 1).into()], true),
(
ParaC::get(),
vec![(AssetXLocation::get(), 1).into(), (AssetYLocation::get(), 1).into()],
true,
),
(
ParaC::get(),
vec![(AssetXLocation::get(), 1).into(), (AssetZLocation::get(), 1).into()],
true,
),
(
ParaC::get(),
vec![(AssetYLocation::get(), 1).into(), (AssetZLocation::get(), 1).into()],
true,
),
(
ParaC::get(),
vec![
(AssetXLocation::get(), 1).into(),
(AssetYLocation::get(), 1).into(),
(AssetZLocation::get(), 1).into(),
],
true,
),
];

type Filter = (
// For ParaA accept only asset X and Y.
LocationWithAssetFilters<Equals<ParaA>, OnlyAssetXOrAssetY>,
// For ParaB accept only asset Z.
LocationWithAssetFilters<Equals<ParaB>, OnlyAssetZ>,
// For ParaC accept all assets.
LocationWithAssetFilters<Equals<ParaC>, AllAssets>,
);

for (location, assets, expected_result) in test_data {
assert_eq!(
Filter::contains(&(location, assets.clone())),
expected_result,
"expected_result: {expected_result} not matched for (location, assets): ({:?}, {:?})!", location, assets,
)
}
}
}
7 changes: 5 additions & 2 deletions polkadot/xcm/xcm-builder/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,14 +83,17 @@ pub use weight::{
FixedRateOfFungible, FixedWeightBounds, TakeRevenue, UsingComponents, WeightInfoBounds,
};

mod matches_location;
pub use matches_location::{StartsWith, StartsWithExplicitGlobalConsensus};

mod matches_token;
pub use matches_token::{IsAbstract, IsConcrete};

mod matcher;
pub use matcher::{CreateMatcher, MatchXcm, Matcher};

mod filter_asset_location;
pub use filter_asset_location::{Case, NativeAsset};
pub use filter_asset_location::{AllAssets, Case, LocationWithAssetFilters, NativeAsset};

mod routing;
pub use routing::{WithTopicSource, WithUniqueTopic};
Expand All @@ -99,7 +102,7 @@ mod universal_exports;
pub use universal_exports::{
ensure_is_remote, BridgeBlobDispatcher, BridgeMessage, DispatchBlob, DispatchBlobError,
ExporterFor, HaulBlob, HaulBlobError, HaulBlobExporter, NetworkExportTable,
SovereignPaidRemoteExporter, UnpaidLocalExporter, UnpaidRemoteExporter,
NetworkExportTableItem, SovereignPaidRemoteExporter, UnpaidLocalExporter, UnpaidRemoteExporter,
};

mod origin_aliases;
Expand Down
Loading

0 comments on commit 5cdd819

Please sign in to comment.