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,
|
||||
};
|
||||
use xcm::prelude::*;
|
||||
use xcm_builder::NetworkExportTable;
|
||||
use xcm_builder::{NetworkExportTable, NetworkExportTableItem};
|
||||
|
||||
pub type AccountId = u64;
|
||||
type Block = frame_system::mocking::MockBlock<TestRuntime>;
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
@@ -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};
|
||||
|
||||
|
||||
@@ -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},
|
||||
@@ -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};
|
||||
|
||||
|
||||
@@ -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,
|
||||
@@ -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};
|
||||
|
||||
|
||||
@@ -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`
|
||||
@@ -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]
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
@@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,6 +83,9 @@ 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};
|
||||
|
||||
@@ -90,7 +93,7 @@ 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};
|
||||
@@ -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;
|
||||
|
||||
@@ -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 RelayUniversalLocation: Junctions = X1(GlobalConsensus(Local::get()));
|
||||
pub RemoteUniversalLocation: Junctions = X1(GlobalConsensus(Remote::get()));
|
||||
pub BridgeTable: Vec<(NetworkId, MultiLocation, Option<MultiAsset>)>
|
||||
= vec![(Remote::get(), MultiLocation::parent(), Some((Parent, 200u128 + if UsingTopic::get() { 20 } else { 0 }).into()))];
|
||||
pub BridgeTable: Vec<NetworkExportTableItem> = vec![
|
||||
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
|
||||
// x (10 + 10) weight each).
|
||||
}
|
||||
|
||||
@@ -24,8 +24,14 @@ parameter_types! {
|
||||
pub UniversalLocation: Junctions = X2(GlobalConsensus(Local::get()), Parachain(1000));
|
||||
pub ParaBridgeUniversalLocation: Junctions = X2(GlobalConsensus(Local::get()), Parachain(1));
|
||||
pub RemoteParaBridgeUniversalLocation: Junctions = X2(GlobalConsensus(Remote::get()), Parachain(1));
|
||||
pub BridgeTable: Vec<(NetworkId, MultiLocation, Option<MultiAsset>)>
|
||||
= vec![(Remote::get(), (Parent, Parachain(1)).into(), None)];
|
||||
pub BridgeTable: Vec<NetworkExportTableItem> = vec![
|
||||
NetworkExportTableItem::new(
|
||||
Remote::get(),
|
||||
None,
|
||||
(Parent, Parachain(1)).into(),
|
||||
None
|
||||
)
|
||||
];
|
||||
}
|
||||
type TheBridge = TestBridge<
|
||||
BridgeBlobDispatcher<TestRemoteIncomingRouter, RemoteParaBridgeUniversalLocation, ()>,
|
||||
|
||||
@@ -24,8 +24,14 @@ parameter_types! {
|
||||
pub UniversalLocation: Junctions = X1(GlobalConsensus(Local::get()));
|
||||
pub ParaBridgeUniversalLocation: Junctions = X2(GlobalConsensus(Local::get()), Parachain(1));
|
||||
pub RemoteParaBridgeUniversalLocation: Junctions = X2(GlobalConsensus(Remote::get()), Parachain(1));
|
||||
pub BridgeTable: Vec<(NetworkId, MultiLocation, Option<MultiAsset>)>
|
||||
= vec![(Remote::get(), Parachain(1).into(), None)];
|
||||
pub BridgeTable: Vec<NetworkExportTableItem> = vec![
|
||||
NetworkExportTableItem::new(
|
||||
Remote::get(),
|
||||
None,
|
||||
Parachain(1).into(),
|
||||
None
|
||||
)
|
||||
];
|
||||
}
|
||||
type TheBridge = TestBridge<
|
||||
BridgeBlobDispatcher<TestRemoteIncomingRouter, RemoteParaBridgeUniversalLocation, ()>,
|
||||
|
||||
@@ -24,8 +24,14 @@ parameter_types! {
|
||||
pub UniversalLocation: Junctions = X2(GlobalConsensus(Local::get()), Parachain(1000));
|
||||
pub RelayUniversalLocation: Junctions = X1(GlobalConsensus(Local::get()));
|
||||
pub RemoteUniversalLocation: Junctions = X1(GlobalConsensus(Remote::get()));
|
||||
pub BridgeTable: Vec<(NetworkId, MultiLocation, Option<MultiAsset>)>
|
||||
= vec![(Remote::get(), MultiLocation::parent(), None)];
|
||||
pub BridgeTable: Vec<NetworkExportTableItem> = vec![
|
||||
NetworkExportTableItem::new(
|
||||
Remote::get(),
|
||||
None,
|
||||
MultiLocation::parent(),
|
||||
None
|
||||
)
|
||||
];
|
||||
}
|
||||
type TheBridge =
|
||||
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>);
|
||||
impl<T: Get<Vec<(NetworkId, MultiLocation, Option<MultiAsset>)>>> ExporterFor
|
||||
for NetworkExportTable<T>
|
||||
{
|
||||
impl<T: Get<Vec<NetworkExportTableItem>>> ExporterFor for NetworkExportTable<T> {
|
||||
fn exporter_for(
|
||||
network: &NetworkId,
|
||||
_: &InteriorMultiLocation,
|
||||
remote_location: &InteriorMultiLocation,
|
||||
_: &Xcm<()>,
|
||||
) -> 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
|
||||
/// `GlobalConsensus` junction describing the network under which global consensus happens.
|
||||
/// If this does not match our global consensus then it's a fatal error.
|
||||
universal_dest: VersionedInteriorMultiLocation,
|
||||
message: VersionedXcm<()>,
|
||||
pub universal_dest: VersionedInteriorMultiLocation,
|
||||
pub message: VersionedXcm<()>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
@@ -504,7 +542,7 @@ mod tests {
|
||||
pub UniversalLocation: InteriorMultiLocation = X2(GlobalConsensus(Local::get()), Parachain(1234));
|
||||
pub DifferentRemote: NetworkId = ByGenesis([22; 32]);
|
||||
// no routers
|
||||
pub BridgeTable: Vec<(NetworkId, MultiLocation, Option<MultiAsset>)> = vec![];
|
||||
pub BridgeTable: Vec<NetworkExportTableItem> = vec![];
|
||||
}
|
||||
|
||||
// check with local destination (should be remote)
|
||||
@@ -539,4 +577,74 @@ mod tests {
|
||||
>,
|
||||
>(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)]
|
||||
pub use members::{AllowAll, DenyAll, Filter};
|
||||
pub use members::{
|
||||
AsContains, ChangeMembers, Contains, ContainsLengthBound, ContainsPair, Everything,
|
||||
AsContains, ChangeMembers, Contains, ContainsLengthBound, ContainsPair, Equals, Everything,
|
||||
EverythingBut, FromContainsPair, InitializeMembers, InsideBoth, IsInVec, Nothing,
|
||||
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
|
||||
/// to `matches!`.
|
||||
#[macro_export]
|
||||
|
||||
Reference in New Issue
Block a user