mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-01 02:11:01 +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:
@@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user