Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Make most XCM APIs accept an Into<MultiLocation> where MultiLocation is accepted #3627

Merged
18 commits merged into from
Sep 29, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion runtime/common/src/xcm_sender.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ pub struct ChildParachainRouter<T, W>(PhantomData<(T, W)>);
impl<T: configuration::Config + dmp::Config, W: xcm::WrapVersion> SendXcm
for ChildParachainRouter<T, W>
{
fn send_xcm(dest: MultiLocation, msg: Xcm<()>) -> SendResult {
fn send_xcm(dest: impl Into<MultiLocation>, msg: Xcm<()>) -> SendResult {
let dest = dest.into();
match dest {
MultiLocation { parents: 0, interior: X1(Parachain(id)) } => {
// Downward message passing.
Expand Down
7 changes: 3 additions & 4 deletions runtime/parachains/src/ump.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ impl<XcmExecutor: xcm::latest::ExecuteXcm<C::Call>, C: Config> UmpSink for XcmSi
) -> Result<Weight, (MessageId, Weight)> {
use parity_scale_codec::DecodeLimit;
use xcm::{
latest::{Error as XcmError, Junction, MultiLocation, Xcm},
latest::{Error as XcmError, Junction, Xcm},
VersionedXcm,
};

Expand All @@ -111,9 +111,8 @@ impl<XcmExecutor: xcm::latest::ExecuteXcm<C::Call>, C: Config> UmpSink for XcmSi
Ok(0)
},
Ok(Ok(xcm_message)) => {
let xcm_junction: Junction = Junction::Parachain(origin.into());
let xcm_location: MultiLocation = xcm_junction.into();
let outcome = XcmExecutor::execute_xcm(xcm_location, xcm_message, max_weight);
let xcm_junction = Junction::Parachain(origin.into());
let outcome = XcmExecutor::execute_xcm(xcm_junction, xcm_message, max_weight);
match outcome {
Outcome::Error(XcmError::WeightLimitReached(required)) => Err((id, required)),
outcome => {
Expand Down
2 changes: 1 addition & 1 deletion runtime/test-runtime/src/xcm_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ pub type LocalOriginToLocation = (

pub struct DoNothingRouter;
impl SendXcm for DoNothingRouter {
fn send_xcm(_dest: MultiLocation, _msg: Xcm<()>) -> SendResult {
fn send_xcm(_dest: impl Into<MultiLocation>, _msg: Xcm<()>) -> SendResult {
Ok(())
}
}
Expand Down
46 changes: 31 additions & 15 deletions xcm/pallet-xcm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,7 @@ pub mod pallet {
weight_used += T::DbWeight::get().read + T::DbWeight::get().write;
q.sort_by_key(|i| i.1);
while let Some((versioned_dest, _)) = q.pop() {
if let Ok(dest) = versioned_dest.try_into() {
if let Ok(dest) = MultiLocation::try_from(versioned_dest) {
if Self::request_version_notify(dest).is_ok() {
// TODO: correct weights.
weight_used += T::DbWeight::get().read + T::DbWeight::get().write;
Expand Down Expand Up @@ -458,7 +458,7 @@ pub mod pallet {
message: Box<VersionedXcm<()>>,
) -> DispatchResult {
let origin_location = T::SendXcmOrigin::ensure_origin(origin)?;
let interior =
let interior: Junctions =
origin_location.clone().try_into().map_err(|_| Error::<T>::InvalidOrigin)?;
let dest = MultiLocation::try_from(*dest).map_err(|()| Error::<T>::BadVersion)?;
let message: Xcm<()> = (*message).try_into().map_err(|()| Error::<T>::BadVersion)?;
Expand Down Expand Up @@ -688,7 +688,8 @@ pub mod pallet {
location: Box<VersionedMultiLocation>,
) -> DispatchResult {
ensure_root(origin)?;
let location = (*location).try_into().map_err(|()| Error::<T>::BadLocation)?;
let location: MultiLocation =
(*location).try_into().map_err(|()| Error::<T>::BadLocation)?;
Self::request_version_notify(location).map_err(|e| {
match e {
XcmError::InvalidLocation => Error::<T>::AlreadySubscribed,
Expand All @@ -710,7 +711,8 @@ pub mod pallet {
location: Box<VersionedMultiLocation>,
) -> DispatchResult {
ensure_root(origin)?;
let location = (*location).try_into().map_err(|()| Error::<T>::BadLocation)?;
let location: MultiLocation =
(*location).try_into().map_err(|()| Error::<T>::BadLocation)?;
Self::unrequest_version_notify(location).map_err(|e| {
match e {
XcmError::InvalidLocation => Error::<T>::NoSubscription,
Expand Down Expand Up @@ -867,7 +869,8 @@ pub mod pallet {
}

/// Request that `dest` informs us of its version.
pub fn request_version_notify(dest: MultiLocation) -> XcmResult {
pub fn request_version_notify(dest: impl Into<MultiLocation>) -> XcmResult {
let dest = dest.into();
let versioned_dest = VersionedMultiLocation::from(dest.clone());
let already = VersionNotifiers::<T>::contains_key(XCM_VERSION, &versioned_dest);
ensure!(!already, XcmError::InvalidLocation);
Expand All @@ -887,7 +890,8 @@ pub mod pallet {
}

/// Request that `dest` ceases informing us of its version.
pub fn unrequest_version_notify(dest: MultiLocation) -> XcmResult {
pub fn unrequest_version_notify(dest: impl Into<MultiLocation>) -> XcmResult {
let dest = dest.into();
let versioned_dest = LatestVersionedMultiLocation(&dest);
let query_id = VersionNotifiers::<T>::take(XCM_VERSION, versioned_dest)
.ok_or(XcmError::InvalidLocation)?;
Expand All @@ -899,10 +903,12 @@ pub mod pallet {
/// Relay an XCM `message` from a given `interior` location in this context to a given `dest`
/// location. A null `dest` is not handled.
pub fn send_xcm(
interior: Junctions,
dest: MultiLocation,
interior: impl Into<Junctions>,
dest: impl Into<MultiLocation>,
mut message: Xcm<()>,
) -> Result<(), SendError> {
let interior = interior.into();
let dest = dest.into();
if interior != Junctions::Here {
message.0.insert(0, DescendOrigin(interior))
};
Expand All @@ -916,7 +922,7 @@ pub mod pallet {
}

fn do_new_query(
responder: MultiLocation,
responder: impl Into<MultiLocation>,
maybe_notify: Option<(u8, u8)>,
timeout: T::BlockNumber,
) -> u64 {
Expand All @@ -925,7 +931,11 @@ pub mod pallet {
q.saturating_inc();
Queries::<T>::insert(
r,
QueryStatus::Pending { responder: responder.into(), maybe_notify, timeout },
QueryStatus::Pending {
responder: responder.into().into(),
maybe_notify,
timeout,
},
);
r
})
Expand All @@ -945,9 +955,10 @@ pub mod pallet {
/// value.
pub fn report_outcome(
message: &mut Xcm<()>,
responder: MultiLocation,
responder: impl Into<MultiLocation>,
timeout: T::BlockNumber,
) -> Result<QueryId, XcmError> {
let responder = responder.into();
let dest = T::LocationInverter::invert_location(&responder)
.map_err(|()| XcmError::MultiLocationNotInvertible)?;
let query_id = Self::new_query(responder, timeout);
Expand Down Expand Up @@ -978,10 +989,11 @@ pub mod pallet {
/// may be put in the overweight queue and need to be manually executed.
pub fn report_outcome_notify(
message: &mut Xcm<()>,
responder: MultiLocation,
responder: impl Into<MultiLocation>,
notify: impl Into<<T as Config>::Call>,
timeout: T::BlockNumber,
) -> Result<(), XcmError> {
let responder = responder.into();
let dest = T::LocationInverter::invert_location(&responder)
.map_err(|()| XcmError::MultiLocationNotInvertible)?;
let notify: <T as Config>::Call = notify.into();
Expand All @@ -993,14 +1005,14 @@ pub mod pallet {
}

/// Attempt to create a new query ID and register it as a query that is yet to respond.
pub fn new_query(responder: MultiLocation, timeout: T::BlockNumber) -> u64 {
pub fn new_query(responder: impl Into<MultiLocation>, timeout: T::BlockNumber) -> u64 {
Self::do_new_query(responder, None, timeout)
}

/// Attempt to create a new query ID and register it as a query that is yet to respond, and
/// which will call a dispatchable when a response happens.
pub fn new_notify_query(
responder: MultiLocation,
responder: impl Into<MultiLocation>,
notify: impl Into<<T as Config>::Call>,
timeout: T::BlockNumber,
) -> u64 {
Expand Down Expand Up @@ -1368,7 +1380,11 @@ where
/// this crate's `Origin::Xcm` value.
pub struct XcmPassthrough<Origin>(PhantomData<Origin>);
impl<Origin: From<crate::Origin>> ConvertOrigin<Origin> for XcmPassthrough<Origin> {
fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result<Origin, MultiLocation> {
fn convert_origin(
origin: impl Into<MultiLocation>,
kind: OriginKind,
) -> Result<Origin, MultiLocation> {
let origin = origin.into();
match kind {
OriginKind::Xcm => Ok(crate::Origin::Xcm(origin).into()),
_ => Err(origin),
Expand Down
7 changes: 4 additions & 3 deletions xcm/pallet-xcm/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,15 +147,16 @@ pub(crate) fn take_sent_xcm() -> Vec<(MultiLocation, Xcm<()>)> {
/// Sender that never returns error, always sends
pub struct TestSendXcm;
impl SendXcm for TestSendXcm {
fn send_xcm(dest: MultiLocation, msg: Xcm<()>) -> SendResult {
SENT_XCM.with(|q| q.borrow_mut().push((dest, msg)));
fn send_xcm(dest: impl Into<MultiLocation>, msg: Xcm<()>) -> SendResult {
SENT_XCM.with(|q| q.borrow_mut().push((dest.into(), msg)));
Ok(())
}
}
/// Sender that returns error if `X8` junction and stops routing
pub struct TestSendXcmErrX8;
impl SendXcm for TestSendXcmErrX8 {
fn send_xcm(dest: MultiLocation, msg: Xcm<()>) -> SendResult {
fn send_xcm(dest: impl Into<MultiLocation>, msg: Xcm<()>) -> SendResult {
let dest = dest.into();
if dest.len() == 8 {
Err(SendError::Transport("Destination location full"))
} else {
Expand Down
12 changes: 6 additions & 6 deletions xcm/src/v1/multilocation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -338,26 +338,26 @@ impl From<Parent> for MultiLocation {
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
pub struct ParentThen(Junctions);
impl From<ParentThen> for MultiLocation {
fn from(x: ParentThen) -> Self {
MultiLocation { parents: 1, interior: x.0 }
fn from(ParentThen(interior): ParentThen) -> Self {
MultiLocation { parents: 1, interior }
}
}

/// A unit struct which can be converted into a `MultiLocation` of the inner `parents` value.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
pub struct Ancestor(u8);
impl From<Ancestor> for MultiLocation {
fn from(x: Ancestor) -> Self {
MultiLocation { parents: x.0, interior: Junctions::Here }
fn from(Ancestor(parents): Ancestor) -> Self {
MultiLocation { parents, interior: Junctions::Here }
}
}

/// A unit struct which can be converted into a `MultiLocation` of the inner `parents` value and the inner interior.
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
pub struct AncestorThen(u8, Junctions);
impl From<AncestorThen> for MultiLocation {
fn from(x: AncestorThen) -> Self {
MultiLocation { parents: x.0, interior: x.1 }
fn from(AncestorThen(parents, interior): AncestorThen) -> Self {
MultiLocation { parents, interior }
}
}

Expand Down
32 changes: 19 additions & 13 deletions xcm/src/v1/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,12 @@ pub trait ExecuteXcm<Call> {
/// Execute some XCM `message` from `origin` using no more than `weight_limit` weight. The weight limit is
/// a basic hard-limit and the implementation may place further restrictions or requirements on weight and
/// other aspects.
fn execute_xcm(origin: MultiLocation, message: Xcm<Call>, weight_limit: Weight) -> Outcome {
fn execute_xcm(
origin: impl Into<MultiLocation>,
message: Xcm<Call>,
weight_limit: Weight,
) -> Outcome {
let origin = origin.into();
log::debug!(
target: "xcm::execute_xcm",
"origin: {:?}, message: {:?}, weight_limit: {:?}",
Expand All @@ -162,7 +167,7 @@ pub trait ExecuteXcm<Call> {
/// Some amount of `weight_credit` may be provided which, depending on the implementation, may allow
/// execution without associated payment.
fn execute_xcm_in_credit(
origin: MultiLocation,
origin: impl Into<MultiLocation>,
message: Xcm<Call>,
weight_limit: Weight,
weight_credit: Weight,
Expand All @@ -171,7 +176,7 @@ pub trait ExecuteXcm<Call> {

impl<C> ExecuteXcm<C> for () {
fn execute_xcm_in_credit(
_origin: MultiLocation,
_origin: impl Into<MultiLocation>,
_message: Xcm<C>,
_weight_limit: Weight,
_weight_credit: Weight,
Expand All @@ -195,15 +200,16 @@ impl<C> ExecuteXcm<C> for () {
/// /// A sender that only passes the message through and does nothing.
/// struct Sender1;
/// impl SendXcm for Sender1 {
/// fn send_xcm(destination: MultiLocation, message: Xcm<()>) -> Result {
/// return Err(Error::CannotReachDestination(destination, message))
/// fn send_xcm(destination: impl Into<MultiLocation>, message: Xcm<()>) -> Result {
/// return Err(Error::CannotReachDestination(destination.into(), message))
/// }
/// }
///
/// /// A sender that accepts a message that has an X2 junction, otherwise stops the routing.
/// struct Sender2;
/// impl SendXcm for Sender2 {
/// fn send_xcm(destination: MultiLocation, message: Xcm<()>) -> Result {
/// fn send_xcm(destination: impl Into<MultiLocation>, message: Xcm<()>) -> Result {
/// let destination = destination.into();
/// if matches!(destination.interior(), Junctions::X2(j1, j2))
/// && destination.parent_count() == 0
/// {
Expand All @@ -217,7 +223,8 @@ impl<C> ExecuteXcm<C> for () {
/// /// A sender that accepts a message from an X1 parent junction, passing through otherwise.
/// struct Sender3;
/// impl SendXcm for Sender3 {
/// fn send_xcm(destination: MultiLocation, message: Xcm<()>) -> Result {
/// fn send_xcm(destination: impl Into<MultiLocation>, message: Xcm<()>) -> Result {
/// let destination = destination.into();
/// if matches!(destination.interior(), Junctions::Here)
/// && destination.parent_count() == 1
/// {
Expand All @@ -232,17 +239,16 @@ impl<C> ExecuteXcm<C> for () {
/// # fn main() {
/// let call: Vec<u8> = ().encode();
/// let message = Xcm::Transact { origin_type: OriginKind::Superuser, require_weight_at_most: 0, call: call.into() };
/// let destination: MultiLocation = Parent.into();
///
/// assert!(
/// // Sender2 will block this.
/// <(Sender1, Sender2, Sender3) as SendXcm>::send_xcm(destination.clone(), message.clone())
/// <(Sender1, Sender2, Sender3) as SendXcm>::send_xcm(Parent, message.clone())
/// .is_err()
/// );
///
/// assert!(
/// // Sender3 will catch this.
/// <(Sender1, Sender3) as SendXcm>::send_xcm(destination.clone(), message.clone())
/// <(Sender1, Sender3) as SendXcm>::send_xcm(Parent, message.clone())
/// .is_ok()
/// );
/// # }
Expand All @@ -253,19 +259,19 @@ pub trait SendXcm {
/// If it is not a destination which can be reached with this type but possibly could by others, then it *MUST*
/// return `CannotReachDestination`. Any other error will cause the tuple implementation to exit early without
/// trying other type fields.
fn send_xcm(destination: MultiLocation, message: Xcm<()>) -> Result;
fn send_xcm(destination: impl Into<MultiLocation>, message: Xcm<()>) -> Result;
}

#[impl_trait_for_tuples::impl_for_tuples(30)]
impl SendXcm for Tuple {
fn send_xcm(destination: MultiLocation, message: Xcm<()>) -> Result {
fn send_xcm(destination: impl Into<MultiLocation>, message: Xcm<()>) -> Result {
for_tuples!( #(
// we shadow `destination` and `message` in each expansion for the next one.
let (destination, message) = match Tuple::send_xcm(destination, message) {
Err(Error::CannotReachDestination(d, m)) => (d, m),
o @ _ => return o,
};
)* );
Err(Error::CannotReachDestination(destination, message))
Err(Error::CannotReachDestination(destination.into(), message))
}
}
Loading