mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-30 04:41:03 +00:00
[xcm] Small enhancements for NetworkExportTable and xcm-builder (#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>
This commit is contained in:
@@ -27,7 +27,7 @@ use sp_runtime::{
|
|||||||
BuildStorage,
|
BuildStorage,
|
||||||
};
|
};
|
||||||
use xcm::prelude::*;
|
use xcm::prelude::*;
|
||||||
use xcm_builder::NetworkExportTable;
|
use xcm_builder::{NetworkExportTable, NetworkExportTableItem};
|
||||||
|
|
||||||
pub type AccountId = u64;
|
pub type AccountId = u64;
|
||||||
type Block = frame_system::mocking::MockBlock<TestRuntime>;
|
type Block = frame_system::mocking::MockBlock<TestRuntime>;
|
||||||
@@ -53,8 +53,15 @@ parameter_types! {
|
|||||||
pub UniversalLocation: InteriorMultiLocation = X2(GlobalConsensus(ThisNetworkId::get()), Parachain(1000));
|
pub UniversalLocation: InteriorMultiLocation = X2(GlobalConsensus(ThisNetworkId::get()), Parachain(1000));
|
||||||
pub SiblingBridgeHubLocation: MultiLocation = ParentThen(X1(Parachain(1002))).into();
|
pub SiblingBridgeHubLocation: MultiLocation = ParentThen(X1(Parachain(1002))).into();
|
||||||
pub BridgeFeeAsset: AssetId = MultiLocation::parent().into();
|
pub BridgeFeeAsset: AssetId = MultiLocation::parent().into();
|
||||||
pub BridgeTable: Vec<(NetworkId, MultiLocation, Option<MultiAsset>)>
|
pub BridgeTable: Vec<NetworkExportTableItem>
|
||||||
= vec![(BridgedNetworkId::get(), SiblingBridgeHubLocation::get(), Some((BridgeFeeAsset::get(), BASE_FEE).into()))];
|
= vec![
|
||||||
|
NetworkExportTableItem::new(
|
||||||
|
BridgedNetworkId::get(),
|
||||||
|
None,
|
||||||
|
SiblingBridgeHubLocation::get(),
|
||||||
|
Some((BridgeFeeAsset::get(), BASE_FEE).into())
|
||||||
|
)
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
impl frame_system::Config for TestRuntime {
|
impl frame_system::Config for TestRuntime {
|
||||||
|
|||||||
@@ -21,9 +21,7 @@ use super::{
|
|||||||
use crate::ForeignAssets;
|
use crate::ForeignAssets;
|
||||||
use assets_common::{
|
use assets_common::{
|
||||||
local_and_foreign_assets::MatchesLocalAndForeignAssetsMultiLocation,
|
local_and_foreign_assets::MatchesLocalAndForeignAssetsMultiLocation,
|
||||||
matching::{
|
matching::{FromSiblingParachain, IsForeignConcreteAsset},
|
||||||
FromSiblingParachain, IsForeignConcreteAsset, StartsWith, StartsWithExplicitGlobalConsensus,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
use frame_support::{
|
use frame_support::{
|
||||||
match_types, parameter_types,
|
match_types, parameter_types,
|
||||||
@@ -45,8 +43,8 @@ use xcm_builder::{
|
|||||||
EnsureXcmOrigin, FungiblesAdapter, HashedDescription, IsConcrete, LocalMint, NoChecking,
|
EnsureXcmOrigin, FungiblesAdapter, HashedDescription, IsConcrete, LocalMint, NoChecking,
|
||||||
ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative,
|
ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative,
|
||||||
SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32,
|
SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32,
|
||||||
SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents,
|
SovereignSignedViaLocation, StartsWith, StartsWithExplicitGlobalConsensus, TakeWeightCredit,
|
||||||
WeightInfoBounds, WithComputedOrigin, WithUniqueTopic,
|
TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic,
|
||||||
};
|
};
|
||||||
use xcm_executor::{traits::WithOriginFilter, XcmExecutor};
|
use xcm_executor::{traits::WithOriginFilter, XcmExecutor};
|
||||||
|
|
||||||
|
|||||||
@@ -18,9 +18,7 @@ use super::{
|
|||||||
ParachainInfo, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin,
|
ParachainInfo, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin,
|
||||||
TrustBackedAssetsInstance, WeightToFee, XcmpQueue,
|
TrustBackedAssetsInstance, WeightToFee, XcmpQueue,
|
||||||
};
|
};
|
||||||
use assets_common::matching::{
|
use assets_common::matching::{FromSiblingParachain, IsForeignConcreteAsset};
|
||||||
FromSiblingParachain, IsForeignConcreteAsset, StartsWith, StartsWithExplicitGlobalConsensus,
|
|
||||||
};
|
|
||||||
use frame_support::{
|
use frame_support::{
|
||||||
match_types, parameter_types,
|
match_types, parameter_types,
|
||||||
traits::{ConstU32, Contains, Everything, Nothing, PalletInfoAccess},
|
traits::{ConstU32, Contains, Everything, Nothing, PalletInfoAccess},
|
||||||
@@ -41,8 +39,8 @@ use xcm_builder::{
|
|||||||
EnsureXcmOrigin, FungiblesAdapter, HashedDescription, IsConcrete, LocalMint, NoChecking,
|
EnsureXcmOrigin, FungiblesAdapter, HashedDescription, IsConcrete, LocalMint, NoChecking,
|
||||||
ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative,
|
ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative,
|
||||||
SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32,
|
SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32,
|
||||||
SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents,
|
SovereignSignedViaLocation, StartsWith, StartsWithExplicitGlobalConsensus, TakeWeightCredit,
|
||||||
WeightInfoBounds, WithComputedOrigin, WithUniqueTopic,
|
TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic,
|
||||||
};
|
};
|
||||||
use xcm_executor::{traits::WithOriginFilter, XcmExecutor};
|
use xcm_executor::{traits::WithOriginFilter, XcmExecutor};
|
||||||
|
|
||||||
|
|||||||
@@ -21,9 +21,7 @@ use super::{
|
|||||||
use crate::ForeignAssets;
|
use crate::ForeignAssets;
|
||||||
use assets_common::{
|
use assets_common::{
|
||||||
local_and_foreign_assets::MatchesLocalAndForeignAssetsMultiLocation,
|
local_and_foreign_assets::MatchesLocalAndForeignAssetsMultiLocation,
|
||||||
matching::{
|
matching::{FromSiblingParachain, IsForeignConcreteAsset},
|
||||||
FromSiblingParachain, IsForeignConcreteAsset, StartsWith, StartsWithExplicitGlobalConsensus,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
use frame_support::{
|
use frame_support::{
|
||||||
match_types, parameter_types,
|
match_types, parameter_types,
|
||||||
@@ -45,8 +43,8 @@ use xcm_builder::{
|
|||||||
EnsureXcmOrigin, FungiblesAdapter, HashedDescription, IsConcrete, LocalMint, NoChecking,
|
EnsureXcmOrigin, FungiblesAdapter, HashedDescription, IsConcrete, LocalMint, NoChecking,
|
||||||
ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative,
|
ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative,
|
||||||
SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32,
|
SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32,
|
||||||
SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents,
|
SovereignSignedViaLocation, StartsWith, StartsWithExplicitGlobalConsensus, TakeWeightCredit,
|
||||||
WeightInfoBounds, WithComputedOrigin, WithUniqueTopic,
|
TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic,
|
||||||
};
|
};
|
||||||
use xcm_executor::{traits::WithOriginFilter, XcmExecutor};
|
use xcm_executor::{traits::WithOriginFilter, XcmExecutor};
|
||||||
|
|
||||||
|
|||||||
@@ -21,11 +21,11 @@ pub mod local_and_foreign_assets;
|
|||||||
pub mod matching;
|
pub mod matching;
|
||||||
pub mod runtime_api;
|
pub mod runtime_api;
|
||||||
|
|
||||||
use crate::matching::{Equals, LocalMultiLocationPattern, ParentLocation, StartsWith};
|
use crate::matching::{LocalMultiLocationPattern, ParentLocation};
|
||||||
use frame_support::traits::EverythingBut;
|
use frame_support::traits::{Equals, EverythingBut};
|
||||||
use parachains_common::AssetIdForTrustBackedAssets;
|
use parachains_common::AssetIdForTrustBackedAssets;
|
||||||
use xcm::prelude::MultiLocation;
|
use xcm::prelude::MultiLocation;
|
||||||
use xcm_builder::{AsPrefixedGeneralIndex, MatchedConvertedConcreteId};
|
use xcm_builder::{AsPrefixedGeneralIndex, MatchedConvertedConcreteId, StartsWith};
|
||||||
use xcm_executor::traits::{Identity, JustTry};
|
use xcm_executor::traits::{Identity, JustTry};
|
||||||
|
|
||||||
/// `MultiLocation` vs `AssetIdForTrustBackedAssets` converter for `TrustBackedAssets`
|
/// `MultiLocation` vs `AssetIdForTrustBackedAssets` converter for `TrustBackedAssets`
|
||||||
@@ -96,9 +96,9 @@ pub type PoolAssetsConvertedConcreteId<PoolAssetsPalletLocation, Balance> =
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::matching::StartsWithExplicitGlobalConsensus;
|
|
||||||
use sp_runtime::traits::MaybeEquivalence;
|
use sp_runtime::traits::MaybeEquivalence;
|
||||||
use xcm::latest::prelude::*;
|
use xcm::latest::prelude::*;
|
||||||
|
use xcm_builder::StartsWithExplicitGlobalConsensus;
|
||||||
use xcm_executor::traits::{Error as MatchError, MatchesFungibles};
|
use xcm_executor::traits::{Error as MatchError, MatchesFungibles};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -407,13 +407,14 @@ where
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::{
|
use crate::{
|
||||||
local_and_foreign_assets::MultiLocationConverter, matching::StartsWith,
|
local_and_foreign_assets::MultiLocationConverter, AssetIdForPoolAssetsConvert,
|
||||||
AssetIdForPoolAssetsConvert, AssetIdForTrustBackedAssetsConvert,
|
AssetIdForTrustBackedAssetsConvert,
|
||||||
};
|
};
|
||||||
use frame_support::traits::EverythingBut;
|
use frame_support::traits::EverythingBut;
|
||||||
use pallet_asset_conversion::{MultiAssetIdConversionResult, MultiAssetIdConverter};
|
use pallet_asset_conversion::{MultiAssetIdConversionResult, MultiAssetIdConverter};
|
||||||
use sp_runtime::traits::MaybeEquivalence;
|
use sp_runtime::traits::MaybeEquivalence;
|
||||||
use xcm::latest::prelude::*;
|
use xcm::latest::prelude::*;
|
||||||
|
use xcm_builder::StartsWith;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_multi_location_converter_works() {
|
fn test_multi_location_converter_works() {
|
||||||
|
|||||||
@@ -14,38 +14,12 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use cumulus_primitives_core::ParaId;
|
use cumulus_primitives_core::ParaId;
|
||||||
use frame_support::{
|
use frame_support::{pallet_prelude::Get, traits::ContainsPair};
|
||||||
pallet_prelude::Get,
|
|
||||||
traits::{Contains, ContainsPair},
|
|
||||||
};
|
|
||||||
use xcm::{
|
use xcm::{
|
||||||
latest::prelude::{MultiAsset, MultiLocation},
|
latest::prelude::{MultiAsset, MultiLocation},
|
||||||
prelude::*,
|
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! {
|
frame_support::parameter_types! {
|
||||||
pub LocalMultiLocationPattern: MultiLocation = MultiLocation::new(0, Here);
|
pub LocalMultiLocationPattern: MultiLocation = MultiLocation::new(0, Here);
|
||||||
pub ParentLocation: MultiLocation = MultiLocation::parent();
|
pub ParentLocation: MultiLocation = MultiLocation::parent();
|
||||||
|
|||||||
@@ -14,11 +14,12 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
// 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 frame_support::traits::{Contains, ContainsPair, Get};
|
||||||
use sp_std::marker::PhantomData;
|
use sp_std::{marker::PhantomData, vec::Vec};
|
||||||
use xcm::latest::{AssetId::Concrete, MultiAsset, MultiAssetFilter, MultiLocation};
|
use xcm::latest::{AssetId::Concrete, MultiAsset, MultiAssetFilter, MultiLocation, WildMultiAsset};
|
||||||
|
|
||||||
/// Accepts an asset iff it is a native asset.
|
/// Accepts an asset iff it is a native asset.
|
||||||
pub struct NativeAsset;
|
pub struct NativeAsset;
|
||||||
@@ -40,3 +41,171 @@ impl<T: Get<(MultiAssetFilter, MultiLocation)>> ContainsPair<MultiAsset, MultiLo
|
|||||||
a.matches(asset) && &o == origin
|
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,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -83,6 +83,9 @@ pub use weight::{
|
|||||||
FixedRateOfFungible, FixedWeightBounds, TakeRevenue, UsingComponents, WeightInfoBounds,
|
FixedRateOfFungible, FixedWeightBounds, TakeRevenue, UsingComponents, WeightInfoBounds,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
mod matches_location;
|
||||||
|
pub use matches_location::{StartsWith, StartsWithExplicitGlobalConsensus};
|
||||||
|
|
||||||
mod matches_token;
|
mod matches_token;
|
||||||
pub use matches_token::{IsAbstract, IsConcrete};
|
pub use matches_token::{IsAbstract, IsConcrete};
|
||||||
|
|
||||||
@@ -90,7 +93,7 @@ mod matcher;
|
|||||||
pub use matcher::{CreateMatcher, MatchXcm, Matcher};
|
pub use matcher::{CreateMatcher, MatchXcm, Matcher};
|
||||||
|
|
||||||
mod filter_asset_location;
|
mod filter_asset_location;
|
||||||
pub use filter_asset_location::{Case, NativeAsset};
|
pub use filter_asset_location::{AllAssets, Case, LocationWithAssetFilters, NativeAsset};
|
||||||
|
|
||||||
mod routing;
|
mod routing;
|
||||||
pub use routing::{WithTopicSource, WithUniqueTopic};
|
pub use routing::{WithTopicSource, WithUniqueTopic};
|
||||||
@@ -99,7 +102,7 @@ mod universal_exports;
|
|||||||
pub use universal_exports::{
|
pub use universal_exports::{
|
||||||
ensure_is_remote, BridgeBlobDispatcher, BridgeMessage, DispatchBlob, DispatchBlobError,
|
ensure_is_remote, BridgeBlobDispatcher, BridgeMessage, DispatchBlob, DispatchBlobError,
|
||||||
ExporterFor, HaulBlob, HaulBlobError, HaulBlobExporter, NetworkExportTable,
|
ExporterFor, HaulBlob, HaulBlobError, HaulBlobExporter, NetworkExportTable,
|
||||||
SovereignPaidRemoteExporter, UnpaidLocalExporter, UnpaidRemoteExporter,
|
NetworkExportTableItem, SovereignPaidRemoteExporter, UnpaidLocalExporter, UnpaidRemoteExporter,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod origin_aliases;
|
mod origin_aliases;
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
// 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/>.
|
||||||
|
|
||||||
|
//! Various implementations and utilities for matching and filtering `MultiLocation` and
|
||||||
|
//! `InteriorMultiLocation` types.
|
||||||
|
|
||||||
|
use frame_support::traits::{Contains, Get};
|
||||||
|
use xcm::latest::{InteriorMultiLocation, MultiLocation, NetworkId};
|
||||||
|
|
||||||
|
/// An implementation of `Contains` that checks for `MultiLocation` or
|
||||||
|
/// `InteriorMultiLocation` if starts with the provided type `T`.
|
||||||
|
pub struct StartsWith<T>(sp_std::marker::PhantomData<T>);
|
||||||
|
impl<T: Get<MultiLocation>> Contains<MultiLocation> for StartsWith<T> {
|
||||||
|
fn contains(t: &MultiLocation) -> bool {
|
||||||
|
t.starts_with(&T::get())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T: Get<InteriorMultiLocation>> Contains<InteriorMultiLocation> for StartsWith<T> {
|
||||||
|
fn contains(t: &InteriorMultiLocation) -> bool {
|
||||||
|
t.starts_with(&T::get())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An implementation of `Contains` that checks for `MultiLocation` or
|
||||||
|
/// `InteriorMultiLocation` if starts with expected `GlobalConsensus(NetworkId)` provided as type
|
||||||
|
/// `T`.
|
||||||
|
pub struct StartsWithExplicitGlobalConsensus<T>(sp_std::marker::PhantomData<T>);
|
||||||
|
impl<T: Get<NetworkId>> Contains<MultiLocation> for StartsWithExplicitGlobalConsensus<T> {
|
||||||
|
fn contains(location: &MultiLocation) -> bool {
|
||||||
|
matches!(location.interior.global_consensus(), Ok(requested_network) if requested_network.eq(&T::get()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T: Get<NetworkId>> Contains<InteriorMultiLocation> for StartsWithExplicitGlobalConsensus<T> {
|
||||||
|
fn contains(location: &InteriorMultiLocation) -> bool {
|
||||||
|
matches!(location.global_consensus(), Ok(requested_network) if requested_network.eq(&T::get()))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -27,8 +27,14 @@ parameter_types! {
|
|||||||
pub UniversalLocation: Junctions = X2(GlobalConsensus(Local::get()), Parachain(100));
|
pub UniversalLocation: Junctions = X2(GlobalConsensus(Local::get()), Parachain(100));
|
||||||
pub RelayUniversalLocation: Junctions = X1(GlobalConsensus(Local::get()));
|
pub RelayUniversalLocation: Junctions = X1(GlobalConsensus(Local::get()));
|
||||||
pub RemoteUniversalLocation: Junctions = X1(GlobalConsensus(Remote::get()));
|
pub RemoteUniversalLocation: Junctions = X1(GlobalConsensus(Remote::get()));
|
||||||
pub BridgeTable: Vec<(NetworkId, MultiLocation, Option<MultiAsset>)>
|
pub BridgeTable: Vec<NetworkExportTableItem> = vec![
|
||||||
= vec![(Remote::get(), MultiLocation::parent(), Some((Parent, 200u128 + if UsingTopic::get() { 20 } else { 0 }).into()))];
|
NetworkExportTableItem::new(
|
||||||
|
Remote::get(),
|
||||||
|
None,
|
||||||
|
MultiLocation::parent(),
|
||||||
|
Some((Parent, 200u128 + if UsingTopic::get() { 20 } else { 0 }).into())
|
||||||
|
)
|
||||||
|
];
|
||||||
// ^^^ 100 to use the bridge (export) and 100 for the remote execution weight (5 instructions
|
// ^^^ 100 to use the bridge (export) and 100 for the remote execution weight (5 instructions
|
||||||
// x (10 + 10) weight each).
|
// x (10 + 10) weight each).
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,8 +24,14 @@ parameter_types! {
|
|||||||
pub UniversalLocation: Junctions = X2(GlobalConsensus(Local::get()), Parachain(1000));
|
pub UniversalLocation: Junctions = X2(GlobalConsensus(Local::get()), Parachain(1000));
|
||||||
pub ParaBridgeUniversalLocation: Junctions = X2(GlobalConsensus(Local::get()), Parachain(1));
|
pub ParaBridgeUniversalLocation: Junctions = X2(GlobalConsensus(Local::get()), Parachain(1));
|
||||||
pub RemoteParaBridgeUniversalLocation: Junctions = X2(GlobalConsensus(Remote::get()), Parachain(1));
|
pub RemoteParaBridgeUniversalLocation: Junctions = X2(GlobalConsensus(Remote::get()), Parachain(1));
|
||||||
pub BridgeTable: Vec<(NetworkId, MultiLocation, Option<MultiAsset>)>
|
pub BridgeTable: Vec<NetworkExportTableItem> = vec![
|
||||||
= vec![(Remote::get(), (Parent, Parachain(1)).into(), None)];
|
NetworkExportTableItem::new(
|
||||||
|
Remote::get(),
|
||||||
|
None,
|
||||||
|
(Parent, Parachain(1)).into(),
|
||||||
|
None
|
||||||
|
)
|
||||||
|
];
|
||||||
}
|
}
|
||||||
type TheBridge = TestBridge<
|
type TheBridge = TestBridge<
|
||||||
BridgeBlobDispatcher<TestRemoteIncomingRouter, RemoteParaBridgeUniversalLocation, ()>,
|
BridgeBlobDispatcher<TestRemoteIncomingRouter, RemoteParaBridgeUniversalLocation, ()>,
|
||||||
|
|||||||
@@ -24,8 +24,14 @@ parameter_types! {
|
|||||||
pub UniversalLocation: Junctions = X1(GlobalConsensus(Local::get()));
|
pub UniversalLocation: Junctions = X1(GlobalConsensus(Local::get()));
|
||||||
pub ParaBridgeUniversalLocation: Junctions = X2(GlobalConsensus(Local::get()), Parachain(1));
|
pub ParaBridgeUniversalLocation: Junctions = X2(GlobalConsensus(Local::get()), Parachain(1));
|
||||||
pub RemoteParaBridgeUniversalLocation: Junctions = X2(GlobalConsensus(Remote::get()), Parachain(1));
|
pub RemoteParaBridgeUniversalLocation: Junctions = X2(GlobalConsensus(Remote::get()), Parachain(1));
|
||||||
pub BridgeTable: Vec<(NetworkId, MultiLocation, Option<MultiAsset>)>
|
pub BridgeTable: Vec<NetworkExportTableItem> = vec![
|
||||||
= vec![(Remote::get(), Parachain(1).into(), None)];
|
NetworkExportTableItem::new(
|
||||||
|
Remote::get(),
|
||||||
|
None,
|
||||||
|
Parachain(1).into(),
|
||||||
|
None
|
||||||
|
)
|
||||||
|
];
|
||||||
}
|
}
|
||||||
type TheBridge = TestBridge<
|
type TheBridge = TestBridge<
|
||||||
BridgeBlobDispatcher<TestRemoteIncomingRouter, RemoteParaBridgeUniversalLocation, ()>,
|
BridgeBlobDispatcher<TestRemoteIncomingRouter, RemoteParaBridgeUniversalLocation, ()>,
|
||||||
|
|||||||
@@ -24,8 +24,14 @@ parameter_types! {
|
|||||||
pub UniversalLocation: Junctions = X2(GlobalConsensus(Local::get()), Parachain(1000));
|
pub UniversalLocation: Junctions = X2(GlobalConsensus(Local::get()), Parachain(1000));
|
||||||
pub RelayUniversalLocation: Junctions = X1(GlobalConsensus(Local::get()));
|
pub RelayUniversalLocation: Junctions = X1(GlobalConsensus(Local::get()));
|
||||||
pub RemoteUniversalLocation: Junctions = X1(GlobalConsensus(Remote::get()));
|
pub RemoteUniversalLocation: Junctions = X1(GlobalConsensus(Remote::get()));
|
||||||
pub BridgeTable: Vec<(NetworkId, MultiLocation, Option<MultiAsset>)>
|
pub BridgeTable: Vec<NetworkExportTableItem> = vec![
|
||||||
= vec![(Remote::get(), MultiLocation::parent(), None)];
|
NetworkExportTableItem::new(
|
||||||
|
Remote::get(),
|
||||||
|
None,
|
||||||
|
MultiLocation::parent(),
|
||||||
|
None
|
||||||
|
)
|
||||||
|
];
|
||||||
}
|
}
|
||||||
type TheBridge =
|
type TheBridge =
|
||||||
TestBridge<BridgeBlobDispatcher<TestRemoteIncomingRouter, RemoteUniversalLocation, ()>>;
|
TestBridge<BridgeBlobDispatcher<TestRemoteIncomingRouter, RemoteUniversalLocation, ()>>;
|
||||||
|
|||||||
@@ -117,16 +117,54 @@ impl ExporterFor for Tuple {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Configuration item representing a single exporter in the `NetworkExportTable`.
|
||||||
|
pub struct NetworkExportTableItem {
|
||||||
|
/// Supported remote network.
|
||||||
|
pub remote_network: NetworkId,
|
||||||
|
/// Remote location filter.
|
||||||
|
/// If `Some`, the requested remote location must be equal to one of the items in the vector.
|
||||||
|
/// These are locations in the remote network.
|
||||||
|
/// If `None`, then the check is skipped.
|
||||||
|
pub remote_location_filter: Option<Vec<InteriorMultiLocation>>,
|
||||||
|
/// Locally-routable bridge with bridging capabilities to the `remote_network` and
|
||||||
|
/// `remote_location`. See [`ExporterFor`] for more details.
|
||||||
|
pub bridge: MultiLocation,
|
||||||
|
/// The local payment.
|
||||||
|
/// See [`ExporterFor`] for more details.
|
||||||
|
pub payment: Option<MultiAsset>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NetworkExportTableItem {
|
||||||
|
pub fn new(
|
||||||
|
remote_network: NetworkId,
|
||||||
|
remote_location_filter: Option<Vec<InteriorMultiLocation>>,
|
||||||
|
bridge: MultiLocation,
|
||||||
|
payment: Option<MultiAsset>,
|
||||||
|
) -> Self {
|
||||||
|
Self { remote_network, remote_location_filter, bridge, payment }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An adapter for the implementation of `ExporterFor`, which attempts to find the
|
||||||
|
/// `(bridge_location, payment)` for the requested `network` and `remote_location` in the provided
|
||||||
|
/// `T` table containing various exporters.
|
||||||
pub struct NetworkExportTable<T>(sp_std::marker::PhantomData<T>);
|
pub struct NetworkExportTable<T>(sp_std::marker::PhantomData<T>);
|
||||||
impl<T: Get<Vec<(NetworkId, MultiLocation, Option<MultiAsset>)>>> ExporterFor
|
impl<T: Get<Vec<NetworkExportTableItem>>> ExporterFor for NetworkExportTable<T> {
|
||||||
for NetworkExportTable<T>
|
|
||||||
{
|
|
||||||
fn exporter_for(
|
fn exporter_for(
|
||||||
network: &NetworkId,
|
network: &NetworkId,
|
||||||
_: &InteriorMultiLocation,
|
remote_location: &InteriorMultiLocation,
|
||||||
_: &Xcm<()>,
|
_: &Xcm<()>,
|
||||||
) -> Option<(MultiLocation, Option<MultiAsset>)> {
|
) -> Option<(MultiLocation, Option<MultiAsset>)> {
|
||||||
T::get().into_iter().find(|(ref j, ..)| j == network).map(|(_, l, p)| (l, p))
|
T::get()
|
||||||
|
.into_iter()
|
||||||
|
.find(|item| {
|
||||||
|
&item.remote_network == network &&
|
||||||
|
item.remote_location_filter
|
||||||
|
.as_ref()
|
||||||
|
.map(|filters| filters.iter().any(|filter| filter == remote_location))
|
||||||
|
.unwrap_or(true)
|
||||||
|
})
|
||||||
|
.map(|item| (item.bridge, item.payment))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -329,8 +367,8 @@ pub struct BridgeMessage {
|
|||||||
/// The message destination as a *Universal Location*. This means it begins with a
|
/// The message destination as a *Universal Location*. This means it begins with a
|
||||||
/// `GlobalConsensus` junction describing the network under which global consensus happens.
|
/// `GlobalConsensus` junction describing the network under which global consensus happens.
|
||||||
/// If this does not match our global consensus then it's a fatal error.
|
/// If this does not match our global consensus then it's a fatal error.
|
||||||
universal_dest: VersionedInteriorMultiLocation,
|
pub universal_dest: VersionedInteriorMultiLocation,
|
||||||
message: VersionedXcm<()>,
|
pub message: VersionedXcm<()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
@@ -504,7 +542,7 @@ mod tests {
|
|||||||
pub UniversalLocation: InteriorMultiLocation = X2(GlobalConsensus(Local::get()), Parachain(1234));
|
pub UniversalLocation: InteriorMultiLocation = X2(GlobalConsensus(Local::get()), Parachain(1234));
|
||||||
pub DifferentRemote: NetworkId = ByGenesis([22; 32]);
|
pub DifferentRemote: NetworkId = ByGenesis([22; 32]);
|
||||||
// no routers
|
// no routers
|
||||||
pub BridgeTable: Vec<(NetworkId, MultiLocation, Option<MultiAsset>)> = vec![];
|
pub BridgeTable: Vec<NetworkExportTableItem> = vec![];
|
||||||
}
|
}
|
||||||
|
|
||||||
// check with local destination (should be remote)
|
// check with local destination (should be remote)
|
||||||
@@ -539,4 +577,74 @@ mod tests {
|
|||||||
>,
|
>,
|
||||||
>(remote_dest, |result| assert_eq!(Err(NotApplicable), result));
|
>(remote_dest, |result| assert_eq!(Err(NotApplicable), result));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn network_export_table_works() {
|
||||||
|
frame_support::parameter_types! {
|
||||||
|
pub NetworkA: NetworkId = ByGenesis([0; 32]);
|
||||||
|
pub Parachain1000InNetworkA: InteriorMultiLocation = X1(Parachain(1000));
|
||||||
|
pub Parachain2000InNetworkA: InteriorMultiLocation = X1(Parachain(2000));
|
||||||
|
|
||||||
|
pub NetworkB: NetworkId = ByGenesis([1; 32]);
|
||||||
|
|
||||||
|
pub BridgeToALocation: MultiLocation = MultiLocation::new(1, X1(Parachain(1234)));
|
||||||
|
pub BridgeToBLocation: MultiLocation = MultiLocation::new(1, X1(Parachain(4321)));
|
||||||
|
|
||||||
|
pub PaymentForNetworkAAndParachain2000: MultiAsset = (MultiLocation::parent(), 150).into();
|
||||||
|
|
||||||
|
pub BridgeTable: sp_std::vec::Vec<NetworkExportTableItem> = sp_std::vec![
|
||||||
|
// NetworkA allows `Parachain(1000)` as remote location WITHOUT payment.
|
||||||
|
NetworkExportTableItem::new(
|
||||||
|
NetworkA::get(),
|
||||||
|
Some(vec![Parachain1000InNetworkA::get()]),
|
||||||
|
BridgeToALocation::get(),
|
||||||
|
None
|
||||||
|
),
|
||||||
|
// NetworkA allows `Parachain(2000)` as remote location WITH payment.
|
||||||
|
NetworkExportTableItem::new(
|
||||||
|
NetworkA::get(),
|
||||||
|
Some(vec![Parachain2000InNetworkA::get()]),
|
||||||
|
BridgeToALocation::get(),
|
||||||
|
Some(PaymentForNetworkAAndParachain2000::get())
|
||||||
|
),
|
||||||
|
// NetworkB allows all remote location.
|
||||||
|
NetworkExportTableItem::new(
|
||||||
|
NetworkB::get(),
|
||||||
|
None,
|
||||||
|
BridgeToBLocation::get(),
|
||||||
|
None
|
||||||
|
)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
let test_data = vec![
|
||||||
|
(NetworkA::get(), X1(Parachain(1000)), Some((BridgeToALocation::get(), None))),
|
||||||
|
(NetworkA::get(), X2(Parachain(1000), GeneralIndex(1)), None),
|
||||||
|
(
|
||||||
|
NetworkA::get(),
|
||||||
|
X1(Parachain(2000)),
|
||||||
|
Some((BridgeToALocation::get(), Some(PaymentForNetworkAAndParachain2000::get()))),
|
||||||
|
),
|
||||||
|
(NetworkA::get(), X2(Parachain(2000), GeneralIndex(1)), None),
|
||||||
|
(NetworkA::get(), X1(Parachain(3000)), None),
|
||||||
|
(NetworkB::get(), X1(Parachain(1000)), Some((BridgeToBLocation::get(), None))),
|
||||||
|
(NetworkB::get(), X1(Parachain(2000)), Some((BridgeToBLocation::get(), None))),
|
||||||
|
(NetworkB::get(), X1(Parachain(3000)), Some((BridgeToBLocation::get(), None))),
|
||||||
|
];
|
||||||
|
|
||||||
|
for (network, remote_location, expected_result) in test_data {
|
||||||
|
assert_eq!(
|
||||||
|
NetworkExportTable::<BridgeTable>::exporter_for(
|
||||||
|
&network,
|
||||||
|
&remote_location,
|
||||||
|
&Xcm::default()
|
||||||
|
),
|
||||||
|
expected_result,
|
||||||
|
"expected_result: {:?} not matched for network: {:?} and remote_location: {:?}",
|
||||||
|
expected_result,
|
||||||
|
network,
|
||||||
|
remote_location,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ mod members;
|
|||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
pub use members::{AllowAll, DenyAll, Filter};
|
pub use members::{AllowAll, DenyAll, Filter};
|
||||||
pub use members::{
|
pub use members::{
|
||||||
AsContains, ChangeMembers, Contains, ContainsLengthBound, ContainsPair, Everything,
|
AsContains, ChangeMembers, Contains, ContainsLengthBound, ContainsPair, Equals, Everything,
|
||||||
EverythingBut, FromContainsPair, InitializeMembers, InsideBoth, IsInVec, Nothing,
|
EverythingBut, FromContainsPair, InitializeMembers, InsideBoth, IsInVec, Nothing,
|
||||||
RankedMembers, SortedMembers, TheseExcept,
|
RankedMembers, SortedMembers, TheseExcept,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -137,6 +137,14 @@ impl<A, B, These: ContainsPair<A, B>, Those: ContainsPair<A, B>> ContainsPair<A,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An implementation of [`Contains`] which contains only equal members to `T`.
|
||||||
|
pub struct Equals<T>(PhantomData<T>);
|
||||||
|
impl<X: PartialEq, T: super::Get<X>> Contains<X> for Equals<T> {
|
||||||
|
fn contains(t: &X) -> bool {
|
||||||
|
t == &T::get()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Create a type which implements the `Contains` trait for a particular type with syntax similar
|
/// Create a type which implements the `Contains` trait for a particular type with syntax similar
|
||||||
/// to `matches!`.
|
/// to `matches!`.
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
|
|||||||
Reference in New Issue
Block a user