Skip to content
Snippets Groups Projects
Unverified Commit 2f7cf417 authored by Branislav Kontur's avatar Branislav Kontur Committed by GitHub
Browse files

xcm: Fixes for `UnpaidLocalExporter` (#7126)

## Description

This PR deprecates `UnpaidLocalExporter` in favor of the new
`LocalExporter`. First, the name is misleading, as it can be used in
both paid and unpaid scenarios. Second, it contains a hard-coded channel
0, whereas `LocalExporter` uses the same algorithm as `xcm-exporter`.

## Future Improvements  

Remove the `channel` argument and slightly modify the
`ExportXcm::validate` signature as part of [this
issue](https://github.com/orgs/paritytech/projects/145/views/8?pane=issue&itemId=84899273).

---------

Co-authored-by: command-bot <>
parent 7d8e3a43
No related merge requests found
Pipeline #511360 waiting for manual action with stages
in 12 minutes and 13 seconds
......@@ -132,11 +132,13 @@ pub use routing::{
mod transactional;
pub use transactional::FrameTransactionalProcessor;
#[allow(deprecated)]
pub use universal_exports::UnpaidLocalExporter;
mod universal_exports;
pub use universal_exports::{
ensure_is_remote, BridgeBlobDispatcher, BridgeMessage, DispatchBlob, DispatchBlobError,
ExporterFor, HaulBlob, HaulBlobError, HaulBlobExporter, NetworkExportTable,
NetworkExportTableItem, SovereignPaidRemoteExporter, UnpaidLocalExporter, UnpaidRemoteExporter,
ExporterFor, HaulBlob, HaulBlobError, HaulBlobExporter, LocalExporter, NetworkExportTable,
NetworkExportTableItem, SovereignPaidRemoteExporter, UnpaidRemoteExporter,
};
mod weight;
......
......@@ -28,7 +28,7 @@ parameter_types! {
type TheBridge =
TestBridge<BridgeBlobDispatcher<TestRemoteIncomingRouter, RemoteUniversalLocation, ()>>;
type Router = TestTopic<
UnpaidLocalExporter<
LocalExporter<
HaulBlobExporter<TheBridge, RemoteNetwork, AlwaysLatest, Price>,
UniversalLocation,
>,
......
......@@ -28,7 +28,7 @@ parameter_types! {
type TheBridge =
TestBridge<BridgeBlobDispatcher<TestRemoteIncomingRouter, RemoteUniversalLocation, ()>>;
type Router = TestTopic<
UnpaidLocalExporter<
LocalExporter<
HaulBlobExporter<TheBridge, RemoteNetwork, AlwaysLatest, Price>,
UniversalLocation,
>,
......
......@@ -209,7 +209,7 @@ impl<Local: Get<Junctions>, Remote: Get<Junctions>, RemoteExporter: ExportXcm> S
let origin = Local::get().relative_to(&Remote::get());
AllowUnpaidFrom::set(vec![origin.clone()]);
set_exporter_override(price::<RemoteExporter>, deliver::<RemoteExporter>);
// The we execute it:
// Then we execute it:
let mut id = fake_id();
let outcome = XcmExecutor::<TestConfig>::prepare_and_execute(
origin,
......
......@@ -16,6 +16,8 @@
//! Traits and utilities to help with origin mutation and bridging.
#![allow(deprecated)]
use crate::InspectMessageQueues;
use alloc::{vec, vec::Vec};
use codec::{Decode, Encode};
......@@ -58,6 +60,8 @@ pub fn ensure_is_remote(
/// that the message sending cannot be abused in any way.
///
/// This is only useful when the local chain has bridging capabilities.
#[deprecated(note = "Will be removed after July 2025; It uses hard-coded channel `0`, \
use `xcm_builder::LocalExporter` directly instead.")]
pub struct UnpaidLocalExporter<Exporter, UniversalLocation>(
PhantomData<(Exporter, UniversalLocation)>,
);
......@@ -100,6 +104,54 @@ impl<Exporter: ExportXcm, UniversalLocation: Get<InteriorLocation>> SendXcm
fn ensure_successful_delivery(_: Option<Location>) {}
}
/// Implementation of `SendXcm` which uses the given `ExportXcm` implementation in order to forward
/// the message over a bridge.
///
/// This is only useful when the local chain has bridging capabilities.
pub struct LocalExporter<Exporter, UniversalLocation>(PhantomData<(Exporter, UniversalLocation)>);
impl<Exporter: ExportXcm, UniversalLocation: Get<InteriorLocation>> SendXcm
for LocalExporter<Exporter, UniversalLocation>
{
type Ticket = Exporter::Ticket;
fn validate(
dest: &mut Option<Location>,
msg: &mut Option<Xcm<()>>,
) -> SendResult<Exporter::Ticket> {
// This `clone` ensures that `dest` is not consumed in any case.
let d = dest.clone().take().ok_or(MissingArgument)?;
let universal_source = UniversalLocation::get();
let devolved = ensure_is_remote(universal_source.clone(), d).map_err(|_| NotApplicable)?;
let (remote_network, remote_location) = devolved;
let xcm = msg.take().ok_or(MissingArgument)?;
let hash =
(Some(Location::here()), &remote_location).using_encoded(sp_io::hashing::blake2_128);
let channel = u32::decode(&mut hash.as_ref()).unwrap_or(0);
validate_export::<Exporter>(
remote_network,
channel,
universal_source,
remote_location,
xcm.clone(),
)
.inspect_err(|err| {
if let NotApplicable = err {
// We need to make sure that msg is not consumed in case of `NotApplicable`.
*msg = Some(xcm);
}
})
}
fn deliver(ticket: Exporter::Ticket) -> Result<XcmHash, SendError> {
Exporter::deliver(ticket)
}
#[cfg(feature = "runtime-benchmarks")]
fn ensure_successful_delivery(_: Option<Location>) {}
}
pub trait ExporterFor {
/// Return the locally-routable bridge (if any) capable of forwarding `message` to the
/// `remote_location` on the remote `network`, together with the payment which is required.
......@@ -703,9 +755,9 @@ mod tests {
let local_dest: Location = (Parent, Parachain(5678)).into();
assert!(ensure_is_remote(UniversalLocation::get(), local_dest.clone()).is_err());
// UnpaidLocalExporter
// LocalExporter
ensure_validate_does_not_consume_dest_or_msg::<
UnpaidLocalExporter<RoutableBridgeExporter, UniversalLocation>,
LocalExporter<RoutableBridgeExporter, UniversalLocation>,
>(local_dest.clone(), |result| assert_eq!(Err(NotApplicable), result));
// 2. check with not applicable from the inner router (using `NotApplicableBridgeSender`)
......@@ -713,14 +765,14 @@ mod tests {
(Parent, Parent, DifferentRemote::get(), RemoteDestination::get()).into();
assert!(ensure_is_remote(UniversalLocation::get(), remote_dest.clone()).is_ok());
// UnpaidLocalExporter
// LocalExporter
ensure_validate_does_not_consume_dest_or_msg::<
UnpaidLocalExporter<NotApplicableBridgeExporter, UniversalLocation>,
LocalExporter<NotApplicableBridgeExporter, UniversalLocation>,
>(remote_dest.clone(), |result| assert_eq!(Err(NotApplicable), result));
// 3. Ok - deliver
// UnpaidRemoteExporter
assert_ok!(send_xcm::<UnpaidLocalExporter<RoutableBridgeExporter, UniversalLocation>>(
assert_ok!(send_xcm::<LocalExporter<RoutableBridgeExporter, UniversalLocation>>(
remote_dest,
Xcm::default()
));
......
title: 'xcm: Fixes for `UnpaidLocalExporter`'
doc:
- audience: Runtime Dev
description: This PR deprecates `UnpaidLocalExporter` in favor of the new `LocalExporter`. First, the name is misleading, as it can be used in both paid and unpaid scenarios. Second, it contains a hard-coded channel 0, whereas `LocalExporter` uses the same algorithm as `xcm-exporter`.
crates:
- name: staging-xcm-builder
bump: minor
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment