diff --git a/runtime/common/src/xcm_sender.rs b/runtime/common/src/xcm_sender.rs index c386fc5252d4..602f45bbadf6 100644 --- a/runtime/common/src/xcm_sender.rs +++ b/runtime/common/src/xcm_sender.rs @@ -19,7 +19,7 @@ use parity_scale_codec::Encode; use runtime_parachains::{configuration, dmp}; use sp_std::marker::PhantomData; -use xcm::opaque::v1::{Error, Junction, MultiLocation, Result, SendXcm, Xcm}; +use xcm::opaque::latest::*; /// XCM sender for relay chain. It only sends downward message. pub struct ChildParachainRouter(PhantomData<(T, W)>); @@ -28,21 +28,21 @@ impl SendXcm for ChildParachainRouter { fn send_xcm(dest: MultiLocation, msg: Xcm) -> Result { - match &dest { - MultiLocation::X1(Junction::Parachain(id)) => { + match dest { + MultiLocation { parents: 0, interior: Junctions::X1(Junction::Parachain(id)) } => { // Downward message passing. let versioned_xcm = W::wrap_version(&dest, msg).map_err(|()| Error::DestinationUnsupported)?; let config = >::config(); >::queue_downward_message( &config, - (*id).into(), + id.into(), versioned_xcm.encode(), ) .map_err(Into::::into)?; Ok(()) }, - _ => Err(Error::CannotReachDestination(dest, msg)), + dest => Err(Error::CannotReachDestination(dest, msg)), } } } diff --git a/runtime/kusama/src/lib.rs b/runtime/kusama/src/lib.rs index 9b9780155ce3..fdbf7ccdecfa 100644 --- a/runtime/kusama/src/lib.rs +++ b/runtime/kusama/src/lib.rs @@ -1203,12 +1203,12 @@ parameter_types! { /// The location of the KSM token, from the context of this chain. Since this token is native to this /// chain, we make it synonymous with it and thus it is the `Here` location, which means "equivalent to /// the context". - pub const KsmLocation: MultiLocation = MultiLocation::Here; + pub const KsmLocation: MultiLocation = Here.into(); /// The Kusama network ID. This is named. pub const KusamaNetwork: NetworkId = NetworkId::Kusama; /// Our XCM location ancestry - i.e. what, if anything, `Parent` means evaluated in our context. Since /// Kusama is a top-level relay-chain, there is no ancestry. - pub const Ancestry: MultiLocation = MultiLocation::Here; + pub const Ancestry: MultiLocation = Here.into(); /// The check account, which holds any native assets that have been teleported out and not back in (yet). pub CheckAccount: AccountId = XcmPallet::check_account(); } @@ -1265,7 +1265,7 @@ pub type XcmRouter = ( parameter_types! { pub const Kusama: MultiAssetFilter = Wild(AllOf { fun: WildFungible, id: Concrete(KsmLocation::get()) }); - pub const KusamaForStatemint: (MultiAssetFilter, MultiLocation) = (Kusama::get(), X1(Parachain(1000))); + pub const KusamaForStatemint: (MultiAssetFilter, MultiLocation) = (Kusama::get(), Parachain(1000).into()); } pub type TrustedTeleporters = (xcm_builder::Case,); diff --git a/runtime/rococo/src/lib.rs b/runtime/rococo/src/lib.rs index c43a03c3087a..b0f412eb1c68 100644 --- a/runtime/rococo/src/lib.rs +++ b/runtime/rococo/src/lib.rs @@ -583,9 +583,9 @@ impl parachains_paras::Config for Runtime { } parameter_types! { - pub const RocLocation: MultiLocation = MultiLocation::Here; + pub const RocLocation: MultiLocation = Here.into(); pub const RococoNetwork: NetworkId = NetworkId::Polkadot; - pub const Ancestry: MultiLocation = MultiLocation::Here; + pub const Ancestry: MultiLocation = Here.into(); pub CheckAccount: AccountId = XcmPallet::check_account(); } @@ -625,10 +625,10 @@ pub type XcmRouter = ( parameter_types! { pub const Rococo: MultiAssetFilter = Wild(AllOf { fun: WildFungible, id: Concrete(RocLocation::get()) }); - pub const RococoForTick: (MultiAssetFilter, MultiLocation) = (Rococo::get(), X1(Parachain(100))); - pub const RococoForTrick: (MultiAssetFilter, MultiLocation) = (Rococo::get(), X1(Parachain(110))); - pub const RococoForTrack: (MultiAssetFilter, MultiLocation) = (Rococo::get(), X1(Parachain(120))); - pub const RococoForStatemint: (MultiAssetFilter, MultiLocation) = (Rococo::get(), X1(Parachain(1001))); + pub const RococoForTick: (MultiAssetFilter, MultiLocation) = (Rococo::get(), Parachain(100).into()); + pub const RococoForTrick: (MultiAssetFilter, MultiLocation) = (Rococo::get(), Parachain(110).into()); + pub const RococoForTrack: (MultiAssetFilter, MultiLocation) = (Rococo::get(), Parachain(120).into()); + pub const RococoForStatemint: (MultiAssetFilter, MultiLocation) = (Rococo::get(), Parachain(1001).into()); } pub type TrustedTeleporters = ( xcm_builder::Case, @@ -640,10 +640,10 @@ pub type TrustedTeleporters = ( parameter_types! { pub AllowUnpaidFrom: Vec = vec![ - X1(Parachain(100)), - X1(Parachain(110)), - X1(Parachain(120)), - X1(Parachain(1001)) + Parachain(100).into(), + Parachain(110).into(), + Parachain(120).into(), + Parachain(1001).into(), ]; } diff --git a/runtime/test-runtime/src/xcm_config.rs b/runtime/test-runtime/src/xcm_config.rs index a87e8730c746..7748d55e1875 100644 --- a/runtime/test-runtime/src/xcm_config.rs +++ b/runtime/test-runtime/src/xcm_config.rs @@ -16,7 +16,7 @@ use frame_support::{parameter_types, traits::Everything, weights::Weight}; use xcm::latest::{ - Error as XcmError, Junction::*, MultiAsset, MultiLocation, MultiLocation::*, NetworkId, + Error as XcmError, Junctions::Here, MultiAsset, MultiLocation, NetworkId, Parent, Result as XcmResult, SendXcm, Xcm, }; use xcm_builder::{AllowUnpaidExecutionFrom, FixedWeightBounds, SignedToAccountId32}; @@ -52,7 +52,7 @@ impl TransactAsset for DummyAssetTransactor { } fn withdraw_asset(_what: &MultiAsset, _who: &MultiLocation) -> Result { - let asset: MultiAsset = (X1(Parent), 100_000).into(); + let asset: MultiAsset = (Parent, 100_000).into(); Ok(asset.into()) } } @@ -71,7 +71,7 @@ impl WeightTrader for DummyWeightTrader { pub struct InvertNothing; impl InvertLocation for InvertNothing { fn invert_location(_: &MultiLocation) -> MultiLocation { - MultiLocation::Here + Here.into() } } diff --git a/runtime/westend/src/lib.rs b/runtime/westend/src/lib.rs index 9a7944254435..93fd23c48f08 100644 --- a/runtime/westend/src/lib.rs +++ b/runtime/westend/src/lib.rs @@ -866,8 +866,8 @@ impl auctions::Config for Runtime { } parameter_types! { - pub const WndLocation: MultiLocation = MultiLocation::Here; - pub const Ancestry: MultiLocation = MultiLocation::Here; + pub const WndLocation: MultiLocation = Here.into(); + pub const Ancestry: MultiLocation = Here.into(); pub WestendNetwork: NetworkId = NetworkId::Named(b"Westend".to_vec()); pub CheckAccount: AccountId = XcmPallet::check_account(); } @@ -908,7 +908,7 @@ pub type XcmRouter = ( parameter_types! { pub const WestendForWestmint: (MultiAssetFilter, MultiLocation) = - (Wild(AllOf { fun: WildFungible, id: Concrete(WndLocation::get()) }), X1(Parachain(1000))); + (Wild(AllOf { fun: WildFungible, id: Concrete(WndLocation::get()) }), Parachain(1000).into()); } pub type TrustedTeleporters = (xcm_builder::Case,); diff --git a/xcm/pallet-xcm/src/lib.rs b/xcm/pallet-xcm/src/lib.rs index ad0cb4174815..e08bf7c1cbb1 100644 --- a/xcm/pallet-xcm/src/lib.rs +++ b/xcm/pallet-xcm/src/lib.rs @@ -102,7 +102,7 @@ pub mod pallet { UnweighableMessage, /// The assets to be sent are empty. Empty, - /// Could not reanchor the assets to declare the fees for the destination chain. + /// Could not re-anchor the assets to declare the fees for the destination chain. CannotReanchor, /// Too many assets have been attempted for transfer. TooManyAssets, @@ -306,9 +306,10 @@ pub mod pallet { dest: MultiLocation, message: Xcm<()>, ) -> Result<(), XcmError> { - let message = match interior { - MultiLocation::Here => message, - who => Xcm::<()>::RelayedFrom { who, message: Box::new(message) }, + let message = if interior.is_here() { + message + } else { + Xcm::<()>::RelayedFrom { who: interior, message: Box::new(message) } }; log::trace!(target: "xcm::send_xcm", "dest: {:?}, message: {:?}", &dest, &message); T::XcmRouter::send_xcm(dest, message) @@ -384,7 +385,7 @@ where #[cfg(feature = "runtime-benchmarks")] fn successful_origin() -> O { - O::from(Origin::Xcm(MultiLocation::Here)) + O::from(Origin::Xcm(Here.into())) } } @@ -393,9 +394,9 @@ where pub struct XcmPassthrough(PhantomData); impl> ConvertOrigin for XcmPassthrough { fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result { - match (kind, origin) { - (OriginKind::Xcm, l) => Ok(crate::Origin::Xcm(l).into()), - (_, origin) => Err(origin), + match kind { + OriginKind::Xcm => Ok(crate::Origin::Xcm(origin).into()), + _ => Err(origin), } } } diff --git a/xcm/pallet-xcm/src/mock.rs b/xcm/pallet-xcm/src/mock.rs index 50840aa8c78e..4dd6537cc1d7 100644 --- a/xcm/pallet-xcm/src/mock.rs +++ b/xcm/pallet-xcm/src/mock.rs @@ -71,7 +71,7 @@ impl SendXcm for TestSendXcm { pub struct TestSendXcmErrX8; impl SendXcm for TestSendXcmErrX8 { fn send_xcm(dest: MultiLocation, msg: Xcm) -> XcmResult { - if let MultiLocation::X8(..) = dest { + if dest.len() == 8 { Err(XcmError::Undefined) } else { SENT_XCM.with(|q| q.borrow_mut().push((dest, msg))); @@ -129,9 +129,9 @@ impl pallet_balances::Config for Test { } parameter_types! { - pub const RelayLocation: MultiLocation = MultiLocation::Here; + pub const RelayLocation: MultiLocation = Here.into(); pub const AnyNetwork: NetworkId = NetworkId::Any; - pub Ancestry: MultiLocation = MultiLocation::Here; + pub Ancestry: MultiLocation = Here.into(); pub UnitWeightCost: Weight = 1_000; } diff --git a/xcm/pallet-xcm/src/tests.rs b/xcm/pallet-xcm/src/tests.rs index dd8d992bb1c6..1e9d9acb42dc 100644 --- a/xcm/pallet-xcm/src/tests.rs +++ b/xcm/pallet-xcm/src/tests.rs @@ -40,7 +40,7 @@ fn send_works() { let sender: MultiLocation = AccountId32 { network: AnyNetwork::get(), id: ALICE.into() }.into(); let message = Xcm::ReserveAssetDeposited { - assets: (X1(Parent), SEND_AMOUNT).into(), + assets: (Parent, SEND_AMOUNT).into(), effects: vec![ buy_execution((Parent, SEND_AMOUNT), weight), DepositAsset { assets: All.into(), max_assets: 1, beneficiary: sender.clone() }, @@ -54,7 +54,7 @@ fn send_works() { assert_eq!( sent_xcm(), vec![( - MultiLocation::Here, + Here.into(), RelayedFrom { who: sender.clone(), message: Box::new(message.clone()) } )] ); @@ -87,16 +87,7 @@ fn send_fails_when_xcm_router_blocks() { assert_noop!( XcmPallet::send( Origin::signed(ALICE), - Box::new(X8( - Junction::Parent, - Junction::Parent, - Junction::Parent, - Junction::Parent, - Junction::Parent, - Junction::Parent, - Junction::Parent, - Junction::Parent - )), + Box::new(MultiLocation::ancestor(8)), Box::new(message.clone()) ), crate::Error::::SendFailure @@ -118,7 +109,7 @@ fn teleport_assets_works() { assert_ok!(XcmPallet::teleport_assets( Origin::signed(ALICE), Box::new(RelayLocation::get()), - Box::new(X1(AccountId32 { network: Any, id: BOB.into() })), + Box::new(AccountId32 { network: Any, id: BOB.into() }.into()), (Here, SEND_AMOUNT).into(), 0, weight, @@ -162,7 +153,7 @@ fn reserve_transfer_assets_works() { vec![( Parachain(PARA_ID).into(), Xcm::ReserveAssetDeposited { - assets: (X1(Parent), SEND_AMOUNT).into(), + assets: (Parent, SEND_AMOUNT).into(), effects: vec![ buy_execution((Parent, SEND_AMOUNT), weight), DepositAsset { assets: All.into(), max_assets: 1, beneficiary: dest }, diff --git a/xcm/src/v0/junction.rs b/xcm/src/v0/junction.rs index 569930506664..ff08f435472a 100644 --- a/xcm/src/v0/junction.rs +++ b/xcm/src/v0/junction.rs @@ -17,7 +17,7 @@ //! Support data structures for `MultiLocation`, primarily the `Junction` datatype. use alloc::vec::Vec; -use parity_scale_codec::{self, Decode, Encode}; +use parity_scale_codec::{Decode, Encode}; /// A global identifier of an account-bearing consensus system. #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug)] @@ -140,10 +140,7 @@ pub enum Junction { /// Usage will vary widely owing to its generality. /// /// NOTE: Try to avoid using this and instead use a more specific item. - GeneralIndex { - #[codec(compact)] - id: u128, - }, + GeneralIndex(#[codec(compact)] u128), /// A nondescript datum acting as a key within the context location. /// /// Usage will vary widely owing to its generality. @@ -161,6 +158,23 @@ pub enum Junction { Plurality { id: BodyId, part: BodyPart }, } +impl From for Junction { + fn from(v1: crate::v1::Junction) -> Junction { + use crate::v1::Junction::*; + match v1 { + Parachain(id) => Self::Parachain(id), + AccountId32 { network, id } => Self::AccountId32 { network, id }, + AccountIndex64 { network, index } => Self::AccountIndex64 { network, index }, + AccountKey20 { network, key } => Self::AccountKey20 { network, key }, + PalletInstance(index) => Self::PalletInstance(index), + GeneralIndex(index) => Self::GeneralIndex(index), + GeneralKey(key) => Self::GeneralKey(key), + OnlyChild => Self::OnlyChild, + Plurality { id, part } => Self::Plurality { id, part }, + } + } +} + impl Junction { /// Returns true if this junction is a `Parent` item. pub fn is_parent(&self) -> bool { diff --git a/xcm/src/v0/mod.rs b/xcm/src/v0/mod.rs index 626353abf275..8b41eaec85f1 100644 --- a/xcm/src/v0/mod.rs +++ b/xcm/src/v0/mod.rs @@ -33,13 +33,14 @@ mod traits; use super::v1::{Response as Response1, Xcm as Xcm1}; pub use junction::{BodyId, BodyPart, Junction, NetworkId}; pub use multi_asset::{AssetInstance, MultiAsset}; -pub use multi_location::MultiLocation; +pub use multi_location::MultiLocation::{self, *}; pub use order::Order; pub use traits::{Error, ExecuteXcm, Outcome, Result, SendXcm}; /// A prelude for importing all types typically used when interacting with XCM messages. pub mod prelude { pub use super::{ + junction::{BodyId, Junction::*}, multi_asset::{ AssetInstance::{self, *}, MultiAsset::{self, *}, @@ -47,9 +48,8 @@ pub mod prelude { multi_location::MultiLocation::{self, *}, order::Order::{self, *}, traits::{Error as XcmError, ExecuteXcm, Outcome, Result as XcmResult, SendXcm}, - BodyId, BodyPart, Junction::*, - NetworkId, OriginKind, + OriginKind, Xcm::{self, *}, }; } @@ -321,11 +321,12 @@ pub mod opaque { } // Convert from a v1 response to a v0 response -impl From for Response { - fn from(new_response: Response1) -> Self { - match new_response { - Response1::Assets(assets) => Self::Assets(assets.into()), - } +impl TryFrom for Response { + type Error = (); + fn try_from(new_response: Response1) -> result::Result { + Ok(match new_response { + Response1::Assets(assets) => Self::Assets(assets.try_into()?), + }) } } @@ -335,33 +336,33 @@ impl TryFrom> for Xcm { use Xcm::*; Ok(match x { Xcm1::WithdrawAsset { assets, effects } => WithdrawAsset { - assets: assets.into(), + assets: assets.try_into()?, effects: effects .into_iter() .map(Order::try_from) .collect::>()?, }, Xcm1::ReserveAssetDeposited { assets, effects } => ReserveAssetDeposit { - assets: assets.into(), + assets: assets.try_into()?, effects: effects .into_iter() .map(Order::try_from) .collect::>()?, }, Xcm1::ReceiveTeleportedAsset { assets, effects } => TeleportAsset { - assets: assets.into(), + assets: assets.try_into()?, effects: effects .into_iter() .map(Order::try_from) .collect::>()?, }, Xcm1::QueryResponse { query_id: u64, response } => - QueryResponse { query_id: u64, response: response.into() }, + QueryResponse { query_id: u64, response: response.try_into()? }, Xcm1::TransferAsset { assets, beneficiary } => - TransferAsset { assets: assets.into(), dest: beneficiary.into() }, + TransferAsset { assets: assets.try_into()?, dest: beneficiary.try_into()? }, Xcm1::TransferReserveAsset { assets, dest, effects } => TransferReserveAsset { - assets: assets.into(), - dest: dest.into(), + assets: assets.try_into()?, + dest: dest.try_into()?, effects: effects .into_iter() .map(Order::try_from) @@ -375,7 +376,7 @@ impl TryFrom> for Xcm { Xcm1::Transact { origin_type, require_weight_at_most, call } => Transact { origin_type, require_weight_at_most, call: call.into() }, Xcm1::RelayedFrom { who, message } => RelayedFrom { - who: who.into(), + who: who.try_into()?, message: alloc::boxed::Box::new((*message).try_into()?), }, }) diff --git a/xcm/src/v0/multi_asset.rs b/xcm/src/v0/multi_asset.rs index 3225e38a213a..f3bfb2b2c60f 100644 --- a/xcm/src/v0/multi_asset.rs +++ b/xcm/src/v0/multi_asset.rs @@ -17,8 +17,12 @@ //! Cross-Consensus Message format data structures. use super::MultiLocation; -use crate::v1::{MultiAsset as MultiAsset1, MultiAssetFilter, MultiAssets, WildMultiAsset}; +use crate::v1::{MultiAssetFilter, MultiAssets, WildMultiAsset}; use alloc::{vec, vec::Vec}; +use core::{ + convert::{TryFrom, TryInto}, + result, +}; use parity_scale_codec::{self, Decode, Encode}; pub use crate::v1::AssetInstance; @@ -290,53 +294,64 @@ impl MultiAsset { } } -impl From for MultiAsset { - fn from(a: MultiAsset1) -> MultiAsset { +impl TryFrom for MultiAsset { + type Error = (); + + fn try_from(m: crate::v1::MultiAsset) -> result::Result { use crate::v1::{AssetId::*, Fungibility::*}; use MultiAsset::*; - match (a.id, a.fun) { - (Concrete(id), Fungible(amount)) => ConcreteFungible { id: id.into(), amount }, + Ok(match (m.id, m.fun) { + (Concrete(id), Fungible(amount)) => ConcreteFungible { id: id.try_into()?, amount }, (Concrete(class), NonFungible(instance)) => - ConcreteNonFungible { class: class.into(), instance }, + ConcreteNonFungible { class: class.try_into()?, instance }, (Abstract(id), Fungible(amount)) => AbstractFungible { id, amount }, (Abstract(class), NonFungible(instance)) => AbstractNonFungible { class, instance }, - } + }) } } -impl From for Vec { - fn from(a: MultiAssets) -> Vec { - a.drain().into_iter().map(MultiAsset::from).collect() +impl TryFrom for Vec { + type Error = (); + + fn try_from(m: MultiAssets) -> result::Result, ()> { + m.drain().into_iter().map(MultiAsset::try_from).collect() } } -impl From for MultiAsset { - fn from(a: WildMultiAsset) -> MultiAsset { +impl TryFrom for MultiAsset { + type Error = (); + + fn try_from(m: WildMultiAsset) -> result::Result { use crate::v1::{AssetId::*, WildFungibility::*}; use MultiAsset::*; - match a { + Ok(match m { WildMultiAsset::All => All, WildMultiAsset::AllOf { id, fun } => match (id, fun) { - (Concrete(id), Fungible) => AllConcreteFungible { id: id.into() }, - (Concrete(class), NonFungible) => AllConcreteNonFungible { class: class.into() }, + (Concrete(id), Fungible) => AllConcreteFungible { id: id.try_into()? }, + (Concrete(class), NonFungible) => + AllConcreteNonFungible { class: class.try_into()? }, (Abstract(id), Fungible) => AllAbstractFungible { id }, (Abstract(class), NonFungible) => AllAbstractNonFungible { class }, }, - } + }) } } -impl From for Vec { - fn from(a: WildMultiAsset) -> Vec { - vec![a.into()] +impl TryFrom for Vec { + type Error = (); + + fn try_from(m: WildMultiAsset) -> result::Result, ()> { + Ok(vec![m.try_into()?]) } } -impl From for Vec { - fn from(a: MultiAssetFilter) -> Vec { - match a { - MultiAssetFilter::Definite(assets) => assets.into(), - MultiAssetFilter::Wild(wildcard) => wildcard.into(), +impl TryFrom for Vec { + type Error = (); + + fn try_from(m: MultiAssetFilter) -> result::Result, ()> { + match m { + MultiAssetFilter::Definite(assets) => assets.try_into(), + MultiAssetFilter::Wild(wildcard) => wildcard.try_into(), } } } diff --git a/xcm/src/v0/multi_location.rs b/xcm/src/v0/multi_location.rs index 1426529f2fdb..2aa296a0de9c 100644 --- a/xcm/src/v0/multi_location.rs +++ b/xcm/src/v0/multi_location.rs @@ -16,9 +16,9 @@ //! Cross-Consensus Message format data structures. -use core::{mem, result}; - -use super::{super::v1::MultiLocation as MultiLocation1, Junction}; +use super::Junction; +use crate::v1::MultiLocation as MultiLocation1; +use core::{convert::TryFrom, mem, result}; use parity_scale_codec::{self, Decode, Encode}; /// A relative path between state-bearing consensus systems. @@ -696,20 +696,68 @@ impl MultiLocation { } } -impl From for MultiLocation { - fn from(old: MultiLocation1) -> Self { - use MultiLocation::*; - match old { - MultiLocation1::Here => Null, - MultiLocation1::X1(j0) => X1(j0), - MultiLocation1::X2(j0, j1) => X2(j0, j1), - MultiLocation1::X3(j0, j1, j2) => X3(j0, j1, j2), - MultiLocation1::X4(j0, j1, j2, j3) => X4(j0, j1, j2, j3), - MultiLocation1::X5(j0, j1, j2, j3, j4) => X5(j0, j1, j2, j3, j4), - MultiLocation1::X6(j0, j1, j2, j3, j4, j5) => X6(j0, j1, j2, j3, j4, j5), - MultiLocation1::X7(j0, j1, j2, j3, j4, j5, j6) => X7(j0, j1, j2, j3, j4, j5, j6), - MultiLocation1::X8(j0, j1, j2, j3, j4, j5, j6, j7) => - X8(j0, j1, j2, j3, j4, j5, j6, j7), +impl TryFrom for MultiLocation { + type Error = (); + fn try_from(v1: MultiLocation1) -> result::Result { + use crate::v1::Junctions::*; + let mut res = Self::Null; + + for _ in 0..v1.parents { + res.push(Junction::Parent)?; + } + + match v1.interior { + Here => Ok(res), + X1(j0) => res.pushed_with(Junction::from(j0)).map_err(|_| ()), + X2(j0, j1) => res + .pushed_with(Junction::from(j0)) + .and_then(|res| res.pushed_with(Junction::from(j1))) + .map_err(|_| ()), + X3(j0, j1, j2) => res + .pushed_with(Junction::from(j0)) + .and_then(|res| res.pushed_with(Junction::from(j1))) + .and_then(|res| res.pushed_with(Junction::from(j2))) + .map_err(|_| ()), + X4(j0, j1, j2, j3) => res + .pushed_with(Junction::from(j0)) + .and_then(|res| res.pushed_with(Junction::from(j1))) + .and_then(|res| res.pushed_with(Junction::from(j2))) + .and_then(|res| res.pushed_with(Junction::from(j3))) + .map_err(|_| ()), + X5(j0, j1, j2, j3, j4) => res + .pushed_with(Junction::from(j0)) + .and_then(|res| res.pushed_with(Junction::from(j1))) + .and_then(|res| res.pushed_with(Junction::from(j2))) + .and_then(|res| res.pushed_with(Junction::from(j3))) + .and_then(|res| res.pushed_with(Junction::from(j4))) + .map_err(|_| ()), + X6(j0, j1, j2, j3, j4, j5) => res + .pushed_with(Junction::from(j0)) + .and_then(|res| res.pushed_with(Junction::from(j1))) + .and_then(|res| res.pushed_with(Junction::from(j2))) + .and_then(|res| res.pushed_with(Junction::from(j3))) + .and_then(|res| res.pushed_with(Junction::from(j4))) + .and_then(|res| res.pushed_with(Junction::from(j5))) + .map_err(|_| ()), + X7(j0, j1, j2, j3, j4, j5, j6) => res + .pushed_with(Junction::from(j0)) + .and_then(|res| res.pushed_with(Junction::from(j1))) + .and_then(|res| res.pushed_with(Junction::from(j2))) + .and_then(|res| res.pushed_with(Junction::from(j3))) + .and_then(|res| res.pushed_with(Junction::from(j4))) + .and_then(|res| res.pushed_with(Junction::from(j5))) + .and_then(|res| res.pushed_with(Junction::from(j6))) + .map_err(|_| ()), + X8(j0, j1, j2, j3, j4, j5, j6, j7) => res + .pushed_with(Junction::from(j0)) + .and_then(|res| res.pushed_with(Junction::from(j1))) + .and_then(|res| res.pushed_with(Junction::from(j2))) + .and_then(|res| res.pushed_with(Junction::from(j3))) + .and_then(|res| res.pushed_with(Junction::from(j4))) + .and_then(|res| res.pushed_with(Junction::from(j5))) + .and_then(|res| res.pushed_with(Junction::from(j6))) + .and_then(|res| res.pushed_with(Junction::from(j7))) + .map_err(|_| ()), } } } diff --git a/xcm/src/v0/order.rs b/xcm/src/v0/order.rs index 4674046e2628..08f7edf352cc 100644 --- a/xcm/src/v0/order.rs +++ b/xcm/src/v0/order.rs @@ -18,7 +18,10 @@ use super::{super::v1::Order as Order1, MultiAsset, MultiLocation, Xcm}; use alloc::vec::Vec; -use core::{convert::TryFrom, result}; +use core::{ + convert::{TryFrom, TryInto}, + result, +}; use derivative::Derivative; use parity_scale_codec::{self, Decode, Encode}; @@ -161,36 +164,36 @@ impl TryFrom> for Order { Ok(match old { Order1::Noop => Null, Order1::DepositAsset { assets, beneficiary, .. } => - DepositAsset { assets: assets.into(), dest: beneficiary.into() }, + DepositAsset { assets: assets.try_into()?, dest: beneficiary.try_into()? }, Order1::DepositReserveAsset { assets, dest, effects, .. } => DepositReserveAsset { - assets: assets.into(), - dest: dest.into(), + assets: assets.try_into()?, + dest: dest.try_into()?, effects: effects .into_iter() .map(Order::<()>::try_from) .collect::>()?, }, Order1::ExchangeAsset { give, receive } => - ExchangeAsset { give: give.into(), receive: receive.into() }, + ExchangeAsset { give: give.try_into()?, receive: receive.try_into()? }, Order1::InitiateReserveWithdraw { assets, reserve, effects } => InitiateReserveWithdraw { - assets: assets.into(), - reserve: reserve.into(), + assets: assets.try_into()?, + reserve: reserve.try_into()?, effects: effects .into_iter() .map(Order::<()>::try_from) .collect::>()?, }, Order1::InitiateTeleport { assets, dest, effects } => InitiateTeleport { - assets: assets.into(), - dest: dest.into(), + assets: assets.try_into()?, + dest: dest.try_into()?, effects: effects .into_iter() .map(Order::<()>::try_from) .collect::>()?, }, Order1::QueryHolding { query_id, dest, assets } => - QueryHolding { query_id, dest: dest.into(), assets: assets.into() }, + QueryHolding { query_id, dest: dest.try_into()?, assets: assets.try_into()? }, Order1::BuyExecution { fees, weight, debt, halt_on_error, orders, instructions } => { if !orders.is_empty() { return Err(()) @@ -199,7 +202,7 @@ impl TryFrom> for Order { .into_iter() .map(Xcm::::try_from) .collect::>()?; - BuyExecution { fees: fees.into(), weight, debt, halt_on_error, xcm } + BuyExecution { fees: fees.try_into()?, weight, debt, halt_on_error, xcm } }, }) } diff --git a/xcm/src/v1/junction.rs b/xcm/src/v1/junction.rs new file mode 100644 index 000000000000..df426c65ea04 --- /dev/null +++ b/xcm/src/v1/junction.rs @@ -0,0 +1,114 @@ +// Copyright 2020 Parity Technologies (UK) Ltd. +// This file is part of Cumulus. + +// Substrate 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. + +// Substrate 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 Cumulus. If not, see . + +//! Support data structures for `MultiLocation`, primarily the `Junction` datatype. + +use super::{BodyId, BodyPart, Junctions, MultiLocation, NetworkId}; +use crate::v0::Junction as Junction0; +use alloc::vec::Vec; +use core::convert::TryFrom; +use parity_scale_codec::{self, Decode, Encode}; + +/// A single item in a path to describe the relative location of a consensus system. +/// +/// Each item assumes a pre-existing location as its context and is defined in terms of it. +#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug)] +pub enum Junction { + /// An indexed parachain belonging to and operated by the context. + /// + /// Generally used when the context is a Polkadot Relay-chain. + Parachain(#[codec(compact)] u32), + /// A 32-byte identifier for an account of a specific network that is respected as a sovereign endpoint within + /// the context. + /// + /// Generally used when the context is a Substrate-based chain. + AccountId32 { network: NetworkId, id: [u8; 32] }, + /// An 8-byte index for an account of a specific network that is respected as a sovereign endpoint within + /// the context. + /// + /// May be used when the context is a Frame-based chain and includes e.g. an indices pallet. + AccountIndex64 { + network: NetworkId, + #[codec(compact)] + index: u64, + }, + /// A 20-byte identifier for an account of a specific network that is respected as a sovereign endpoint within + /// the context. + /// + /// May be used when the context is an Ethereum or Bitcoin chain or smart-contract. + AccountKey20 { network: NetworkId, key: [u8; 20] }, + /// An instanced, indexed pallet that forms a constituent part of the context. + /// + /// Generally used when the context is a Frame-based chain. + PalletInstance(u8), + /// A non-descript index within the context location. + /// + /// Usage will vary widely owing to its generality. + /// + /// NOTE: Try to avoid using this and instead use a more specific item. + GeneralIndex(#[codec(compact)] u128), + /// A nondescript datum acting as a key within the context location. + /// + /// Usage will vary widely owing to its generality. + /// + /// NOTE: Try to avoid using this and instead use a more specific item. + GeneralKey(Vec), + /// The unambiguous child. + /// + /// Not currently used except as a fallback when deriving ancestry. + OnlyChild, + /// A pluralistic body existing within consensus. + /// + /// Typical to be used to represent a governance origin of a chain, but could in principle be used to represent + /// things such as multisigs also. + Plurality { id: BodyId, part: BodyPart }, +} + +impl TryFrom for Junction { + type Error = (); + + fn try_from(value: Junction0) -> Result { + match value { + Junction0::Parent => Err(()), + Junction0::Parachain(id) => Ok(Self::Parachain(id)), + Junction0::AccountId32 { network, id } => Ok(Self::AccountId32 { network, id }), + Junction0::AccountIndex64 { network, index } => + Ok(Self::AccountIndex64 { network, index }), + Junction0::AccountKey20 { network, key } => Ok(Self::AccountKey20 { network, key }), + Junction0::PalletInstance(index) => Ok(Self::PalletInstance(index)), + Junction0::GeneralIndex(id) => Ok(Self::GeneralIndex(id)), + Junction0::GeneralKey(key) => Ok(Self::GeneralKey(key)), + Junction0::OnlyChild => Ok(Self::OnlyChild), + Junction0::Plurality { id, part } => Ok(Self::Plurality { id: id.into(), part }), + } + } +} + +impl Junction { + /// Convert `self` into a `MultiLocation` containing 0 parents. + /// + /// Similar to `Into::into`, except that this method can be used in a const evaluation context. + pub const fn into(self) -> MultiLocation { + MultiLocation { parents: 0, interior: Junctions::X1(self) } + } + + /// Convert `self` into a `MultiLocation` containing `n` parents. + /// + /// Similar to `Self::into`, with the added ability to specify the number of parent junctions. + pub const fn into_exterior(self, n: u8) -> MultiLocation { + MultiLocation { parents: n, interior: Junctions::X1(self) } + } +} diff --git a/xcm/src/v1/mod.rs b/xcm/src/v1/mod.rs index 94bdef024af9..acf60252a1f2 100644 --- a/xcm/src/v1/mod.rs +++ b/xcm/src/v1/mod.rs @@ -27,30 +27,32 @@ use core::{ use derivative::Derivative; use parity_scale_codec::{self, Decode, Encode}; +mod junction; pub mod multiasset; mod multilocation; mod order; mod traits; // the new multiasset. +pub use junction::Junction; pub use multiasset::{ AssetId, AssetInstance, Fungibility, MultiAsset, MultiAssetFilter, MultiAssets, WildFungibility, WildMultiAsset, }; -pub use multilocation::MultiLocation; +pub use multilocation::{Ancestor, AncestorThen, Junctions, MultiLocation, Parent, ParentThen}; pub use order::Order; pub use traits::{Error, ExecuteXcm, Outcome, Result, SendXcm}; // These parts of XCM v0 have been unchanged in XCM v1, and are re-imported here. -pub use super::v0::{BodyId, BodyPart, Junction, NetworkId, OriginKind}; +pub use super::v0::{BodyId, BodyPart, NetworkId, OriginKind}; /// A prelude for importing all types typically used when interacting with XCM messages. pub mod prelude { pub use super::{ super::v0::{ BodyId, BodyPart, - Junction::*, NetworkId::{self, *}, }, + junction::Junction::{self, *}, multiasset::{ AssetId::{self, *}, AssetInstance::{self, *}, @@ -61,7 +63,11 @@ pub mod prelude { WildFungibility::{self, Fungible as WildFungible, NonFungible as WildNonFungible}, WildMultiAsset::{self, *}, }, - multilocation::MultiLocation::{self, *}, + multilocation::{ + Ancestor, AncestorThen, + Junctions::{self, *}, + MultiLocation, Parent, ParentThen, + }, opaque, order::Order::{self, *}, traits::{Error as XcmError, ExecuteXcm, Outcome, Result as XcmResult, SendXcm}, @@ -352,10 +358,10 @@ impl TryFrom> for Xcm { Xcm0::QueryResponse { query_id: u64, response } => QueryResponse { query_id: u64, response: response.try_into()? }, Xcm0::TransferAsset { assets, dest } => - TransferAsset { assets: assets.try_into()?, beneficiary: dest.into() }, + TransferAsset { assets: assets.try_into()?, beneficiary: dest.try_into()? }, Xcm0::TransferReserveAsset { assets, dest, effects } => TransferReserveAsset { assets: assets.try_into()?, - dest: dest.into(), + dest: dest.try_into()?, effects: effects .into_iter() .map(Order::try_from) @@ -369,7 +375,7 @@ impl TryFrom> for Xcm { Xcm0::Transact { origin_type, require_weight_at_most, call } => Transact { origin_type, require_weight_at_most, call: call.into() }, Xcm0::RelayedFrom { who, message } => RelayedFrom { - who: who.into(), + who: who.try_into()?, message: alloc::boxed::Box::new((*message).try_into()?), }, }) diff --git a/xcm/src/v1/multiasset.rs b/xcm/src/v1/multiasset.rs index 0bcd78cf2a38..a5dfdc84968c 100644 --- a/xcm/src/v1/multiasset.rs +++ b/xcm/src/v1/multiasset.rs @@ -23,10 +23,7 @@ //! - `MultiAssetFilter`: A combination of `Wild` and `MultiAssets` designed for efficiently filtering an XCM holding //! account. -use super::{ - Junction, - MultiLocation::{self, X1}, -}; +use super::MultiLocation; use alloc::{vec, vec::Vec}; use core::{ cmp::Ordering, @@ -104,15 +101,9 @@ pub enum AssetId { Abstract(Vec), } -impl From for AssetId { - fn from(x: MultiLocation) -> Self { - Self::Concrete(x) - } -} - -impl From for AssetId { - fn from(x: Junction) -> Self { - Self::Concrete(X1(x)) +impl> From for AssetId { + fn from(x: T) -> Self { + Self::Concrete(x.into()) } } @@ -242,9 +233,9 @@ impl TryFrom for MultiAsset { use AssetId::*; use Fungibility::*; let (id, fun) = match old { - V0::ConcreteFungible { id, amount } => (Concrete(id.into()), Fungible(amount)), + V0::ConcreteFungible { id, amount } => (Concrete(id.try_into()?), Fungible(amount)), V0::ConcreteNonFungible { class, instance } => - (Concrete(class.into()), NonFungible(instance)), + (Concrete(class.try_into()?), NonFungible(instance)), V0::AbstractFungible { id, amount } => (Abstract(id), Fungible(amount)), V0::AbstractNonFungible { class, instance } => (Abstract(class), NonFungible(instance)), _ => return Err(()), @@ -456,8 +447,8 @@ impl TryFrom for WildMultiAsset { use WildFungibility::*; let (id, fun) = match old { V0::All => return Ok(WildMultiAsset::All), - V0::AllConcreteFungible { id } => (Concrete(id.into()), Fungible), - V0::AllConcreteNonFungible { class } => (Concrete(class.into()), NonFungible), + V0::AllConcreteFungible { id } => (Concrete(id.try_into()?), Fungible), + V0::AllConcreteNonFungible { class } => (Concrete(class.try_into()?), NonFungible), V0::AllAbstractFungible { id } => (Abstract(id), Fungible), V0::AllAbstractNonFungible { class } => (Abstract(class), NonFungible), _ => return Err(()), diff --git a/xcm/src/v1/multilocation.rs b/xcm/src/v1/multilocation.rs index 57cdda4209d4..165d1941956c 100644 --- a/xcm/src/v1/multilocation.rs +++ b/xcm/src/v1/multilocation.rs @@ -16,9 +16,13 @@ //! Cross-Consensus Message format data structures. -use super::{super::v0::MultiLocation as MultiLocation0, Junction}; -use core::{mem, result}; -use parity_scale_codec::{self, Decode, Encode}; +use super::Junction; +use crate::v0::MultiLocation as MultiLocation0; +use core::{ + convert::{TryFrom, TryInto}, + mem, result, +}; +use parity_scale_codec::{Decode, Encode}; /// A relative path between state-bearing consensus systems. /// @@ -36,83 +40,391 @@ use parity_scale_codec::{self, Decode, Encode}; /// A `MultiLocation` is a *relative identifier*, meaning that it can only be used to define the relative path /// between two locations, and cannot generally be used to refer to a location universally. It is comprised of a /// number of *junctions*, each morphing the previous location, either diving down into one of its internal locations, -/// called a *sub-consensus*, or going up into its parent location. Correct `MultiLocation` values must have all -/// `Parent` junctions as a prefix to all *sub-consensus* junctions. +/// called a *sub-consensus*, or going up into its parent location. /// -/// This specific `MultiLocation` implementation uses a Rust `enum` in order to make pattern matching easier. -/// -/// The `MultiLocation` value of `Here` simply refers to the interpreting consensus system. -#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug)] -pub enum MultiLocation { - /// The interpreting consensus system. - Here, - /// A relative path comprising 1 junction. - X1(Junction), - /// A relative path comprising 2 junctions. - X2(Junction, Junction), - /// A relative path comprising 3 junctions. - X3(Junction, Junction, Junction), - /// A relative path comprising 4 junctions. - X4(Junction, Junction, Junction, Junction), - /// A relative path comprising 5 junctions. - X5(Junction, Junction, Junction, Junction, Junction), - /// A relative path comprising 6 junctions. - X6(Junction, Junction, Junction, Junction, Junction, Junction), - /// A relative path comprising 7 junctions. - X7(Junction, Junction, Junction, Junction, Junction, Junction, Junction), - /// A relative path comprising 8 junctions. - X8(Junction, Junction, Junction, Junction, Junction, Junction, Junction, Junction), +/// The `parents` field of this struct indicates the number of parent junctions that exist at the +/// beginning of this `MultiLocation`. A corollary of such a property is that no parent junctions +/// can be added in the middle or at the end of a `MultiLocation`, thus ensuring well-formedness +/// of each and every `MultiLocation` that can be constructed. +#[derive(Clone, Decode, Encode, Eq, PartialEq, Ord, PartialOrd, Debug)] +pub struct MultiLocation { + /// The number of parent junctions at the beginning of this `MultiLocation`. + pub parents: u8, + /// The interior (i.e. non-parent) junctions that this `MultiLocation` contains. + pub interior: Junctions, +} + +impl Default for MultiLocation { + fn default() -> Self { + Self::here() + } +} + +impl MultiLocation { + /// Creates a new `MultiLocation` with the given number of parents and interior junctions. + pub fn new(parents: u8, junctions: Junctions) -> MultiLocation { + MultiLocation { parents, interior: junctions } + } + + /// Creates a new `MultiLocation` with 0 parents and a `Here` interior. + /// + /// The resulting `MultiLocation` can be interpreted as the "current consensus system". + pub const fn here() -> MultiLocation { + MultiLocation { parents: 0, interior: Junctions::Here } + } + + /// Creates a new `MultiLocation` which evaluates to the parent context. + pub const fn parent() -> MultiLocation { + MultiLocation { parents: 1, interior: Junctions::Here } + } + + /// Creates a new `MultiLocation` which evaluates to the grand parent context. + pub const fn grandparent() -> MultiLocation { + MultiLocation { parents: 2, interior: Junctions::Here } + } + + /// Creates a new `MultiLocation` with `parents` and an empty (`Here`) interior. + pub const fn ancestor(parents: u8) -> MultiLocation { + MultiLocation { parents, interior: Junctions::Here } + } + + /// Whether or not the `MultiLocation` has no parents and has a `Here` interior. + pub const fn is_here(&self) -> bool { + self.parents == 0 && self.interior.len() == 0 + } + + /// Return a reference to the interior field. + pub fn interior(&self) -> &Junctions { + &self.interior + } + + /// Return a mutable reference to the interior field. + pub fn interior_mut(&mut self) -> &mut Junctions { + &mut self.interior + } + + /// Returns the number of `Parent` junctions at the beginning of `self`. + pub const fn parent_count(&self) -> u8 { + self.parents + } + + /// Returns boolean indicating whether or not `self` contains only the specified amount of + /// parents and no interior junctions. + pub const fn contains_parents_only(&self, count: u8) -> bool { + matches!(self.interior, Junctions::Here) && self.parents == count + } + + /// Returns the number of parents and junctions in `self`. + pub const fn len(&self) -> usize { + self.parent_count() as usize + self.interior.len() + } + + /// Returns the first interior junction, or `None` if the location is empty or contains only + /// parents. + pub fn first_interior(&self) -> Option<&Junction> { + self.interior.first() + } + + /// Returns last junction, or `None` if the location is empty or contains only parents. + pub fn last(&self) -> Option<&Junction> { + self.interior.last() + } + + /// Splits off the first interior junction, returning the remaining suffix (first item in tuple) + /// and the first element (second item in tuple) or `None` if it was empty. + pub fn split_first_interior(self) -> (MultiLocation, Option) { + let MultiLocation { parents, interior: junctions } = self; + let (suffix, first) = junctions.split_first(); + let multilocation = MultiLocation { parents, interior: suffix }; + (multilocation, first) + } + + /// Splits off the last interior junction, returning the remaining prefix (first item in tuple) + /// and the last element (second item in tuple) or `None` if it was empty or if `self` only + /// contains parents. + pub fn split_last_interior(self) -> (MultiLocation, Option) { + let MultiLocation { parents, interior: junctions } = self; + let (prefix, last) = junctions.split_last(); + let multilocation = MultiLocation { parents, interior: prefix }; + (multilocation, last) + } + + /// Mutates `self`, suffixing its interior junctions with `new`. Returns `Err` in case of overflow. + pub fn push_interior(&mut self, new: Junction) -> result::Result<(), ()> { + let mut n = Junctions::Here; + mem::swap(&mut self.interior, &mut n); + match n.pushed_with(new) { + Ok(result) => { + self.interior = result; + Ok(()) + }, + Err(old) => { + self.interior = old; + Err(()) + }, + } + } + + /// Mutates `self`, prefixing its interior junctions with `new`. Returns `Err` in case of overflow. + pub fn push_front_interior(&mut self, new: Junction) -> result::Result<(), ()> { + let mut n = Junctions::Here; + mem::swap(&mut self.interior, &mut n); + match n.pushed_front_with(new) { + Ok(result) => { + self.interior = result; + Ok(()) + }, + Err(old) => { + self.interior = old; + Err(()) + }, + } + } + + /// Consumes `self` and returns a `MultiLocation` suffixed with `new`, or an `Err` with the original value of + /// `self` in case of overflow. + pub fn pushed_with_interior(self, new: Junction) -> result::Result { + match self.interior.pushed_with(new) { + Ok(i) => Ok(MultiLocation { interior: i, parents: self.parents }), + Err(i) => Err(MultiLocation { interior: i, parents: self.parents }), + } + } + + /// Consumes `self` and returns a `MultiLocation` prefixed with `new`, or an `Err` with the original value of + /// `self` in case of overflow. + pub fn pushed_front_with_interior(self, new: Junction) -> result::Result { + match self.interior.pushed_front_with(new) { + Ok(i) => Ok(MultiLocation { interior: i, parents: self.parents }), + Err(i) => Err(MultiLocation { interior: i, parents: self.parents }), + } + } + + /// Returns the junction at index `i`, or `None` if the location is a parent or if the location + /// does not contain that many elements. + pub fn at(&self, i: usize) -> Option<&Junction> { + let num_parents = self.parents as usize; + if i < num_parents { + return None + } + self.interior.at(i - num_parents) + } + + /// Returns a mutable reference to the junction at index `i`, or `None` if the location is a + /// parent or if it doesn't contain that many elements. + pub fn at_mut(&mut self, i: usize) -> Option<&mut Junction> { + let num_parents = self.parents as usize; + if i < num_parents { + return None + } + self.interior.at_mut(i - num_parents) + } + + /// Decrements the parent count by 1. + pub fn dec_parent(&mut self) { + self.parents = self.parents.saturating_sub(1); + } + + /// Removes the first interior junction from `self`, returning it + /// (or `None` if it was empty or if `self` contains only parents). + pub fn take_first_interior(&mut self) -> Option { + self.interior.take_first() + } + + /// Removes the last element from `interior`, returning it (or `None` if it was empty or if + /// `self` only contains parents). + pub fn take_last(&mut self) -> Option { + self.interior.take_last() + } + + /// Ensures that `self` has the same number of parents as `prefix`, its junctions begins with + /// the junctions of `prefix` and that it has a single `Junction` item following. + /// If so, returns a reference to this `Junction` item. + /// + /// # Example + /// ```rust + /// # use xcm::v1::{Junctions::*, Junction::*, MultiLocation}; + /// # fn main() { + /// let mut m = MultiLocation::new(1, X2(PalletInstance(3), OnlyChild)); + /// assert_eq!( + /// m.match_and_split(&MultiLocation::new(1, X1(PalletInstance(3)))), + /// Some(&OnlyChild), + /// ); + /// assert_eq!(m.match_and_split(&MultiLocation::new(1, Here)), None); + /// # } + /// ``` + pub fn match_and_split(&self, prefix: &MultiLocation) -> Option<&Junction> { + if self.parents != prefix.parents { + return None + } + self.interior.match_and_split(&prefix.interior) + } + + /// Mutate `self` so that it is suffixed with `suffix`. The correct normalized form is returned, + /// removing any internal [Non-Parent, `Parent`] combinations. + /// + /// Does not modify `self` and returns `Err` with `suffix` in case of overflow. + /// + /// # Example + /// ```rust + /// # use xcm::v1::{Junctions::*, Junction::*, MultiLocation}; + /// # fn main() { + /// let mut m = MultiLocation::new(1, X2(Parachain(21), OnlyChild)); + /// assert_eq!(m.append_with(MultiLocation::new(1, X1(PalletInstance(3)))), Ok(())); + /// assert_eq!(m, MultiLocation::new(1, X2(Parachain(21), PalletInstance(3)))); + /// # } + /// ``` + pub fn append_with(&mut self, suffix: MultiLocation) -> Result<(), MultiLocation> { + let mut prefix = suffix; + core::mem::swap(self, &mut prefix); + match self.prepend_with(prefix) { + Ok(()) => Ok(()), + Err(prefix) => { + let mut suffix = prefix; + core::mem::swap(self, &mut suffix); + Err(suffix) + }, + } + } + + /// Mutate `self` so that it is prefixed with `prefix`. + /// + /// Does not modify `self` and returns `Err` with `prefix` in case of overflow. + /// + /// # Example + /// ```rust + /// # use xcm::v1::{Junctions::*, Junction::*, MultiLocation}; + /// # fn main() { + /// let mut m = MultiLocation::new(2, X1(PalletInstance(3))); + /// assert_eq!(m.prepend_with(MultiLocation::new(1, X2(Parachain(21), OnlyChild))), Ok(())); + /// assert_eq!(m, MultiLocation::new(1, X1(PalletInstance(3)))); + /// # } + /// ``` + pub fn prepend_with(&mut self, mut prefix: MultiLocation) -> Result<(), MultiLocation> { + // prefix self (suffix) + // P .. P I .. I p .. p i .. i + let prepend_interior = prefix.interior.len().saturating_sub(self.parents as usize); + let final_interior = self.interior.len().saturating_add(prepend_interior); + if final_interior > MAX_JUNCTIONS { + return Err(prefix) + } + let suffix_parents = (self.parents as usize).saturating_sub(prefix.interior.len()); + let final_parents = (prefix.parents as usize).saturating_add(suffix_parents); + if final_parents > 255 { + return Err(prefix) + } + + // cancel out the final item on the prefix interior for one of the suffix's parents. + while self.parents > 0 && prefix.take_last().is_some() { + self.dec_parent(); + } + + // now we have either removed all suffix's parents or prefix interior. + // this means we can combine the prefix's and suffix's remaining parents/interior since + // we know that with at least one empty, the overall order will be respected: + // prefix self (suffix) + // P .. P (I) p .. p i .. i => P + p .. (no I) i + // -- or -- + // P .. P I .. I (p) i .. i => P (no p) .. I + i + + self.parents = self.parents.saturating_add(prefix.parents); + for j in prefix.interior.into_iter().rev() { + self.push_front_interior(j) + .expect("final_interior no greater than MAX_JUNCTIONS; qed"); + } + Ok(()) + } +} + +/// A unit struct which can be converted into a `MultiLocation` of `parents` value 1. +pub struct Parent; +impl From for MultiLocation { + fn from(_: Parent) -> Self { + MultiLocation { parents: 1, interior: Junctions::Here } + } } -/// Maximum number of junctions a `MultiLocation` can contain. -pub const MAX_MULTILOCATION_LENGTH: usize = 8; +/// A tuple struct which can be converted into a `MultiLocation` of `parents` value 1 with the inner interior. +pub struct ParentThen(Junctions); +impl From for MultiLocation { + fn from(x: ParentThen) -> Self { + MultiLocation { parents: 1, interior: x.0 } + } +} + +/// A unit struct which can be converted into a `MultiLocation` of the inner `parents` value. +pub struct Ancestor(u8); +impl From for MultiLocation { + fn from(x: Ancestor) -> Self { + MultiLocation { parents: x.0, interior: Junctions::Here } + } +} + +/// A unit struct which can be converted into a `MultiLocation` of the inner `parents` value and the inner interior. +pub struct AncestorThen(u8, Junctions); +impl From for MultiLocation { + fn from(x: AncestorThen) -> Self { + MultiLocation { parents: x.0, interior: x.1 } + } +} + +impl From for MultiLocation { + fn from(junctions: Junctions) -> Self { + MultiLocation { parents: 0, interior: junctions } + } +} + +impl From<(u8, Junctions)> for MultiLocation { + fn from((parents, interior): (u8, Junctions)) -> Self { + MultiLocation { parents, interior } + } +} impl From for MultiLocation { fn from(x: Junction) -> Self { - MultiLocation::X1(x) + MultiLocation { parents: 0, interior: Junctions::X1(x) } } } impl From<()> for MultiLocation { fn from(_: ()) -> Self { - MultiLocation::Here + MultiLocation { parents: 0, interior: Junctions::Here } } } impl From<(Junction,)> for MultiLocation { fn from(x: (Junction,)) -> Self { - MultiLocation::X1(x.0) + MultiLocation { parents: 0, interior: Junctions::X1(x.0) } } } impl From<(Junction, Junction)> for MultiLocation { fn from(x: (Junction, Junction)) -> Self { - MultiLocation::X2(x.0, x.1) + MultiLocation { parents: 0, interior: Junctions::X2(x.0, x.1) } } } impl From<(Junction, Junction, Junction)> for MultiLocation { fn from(x: (Junction, Junction, Junction)) -> Self { - MultiLocation::X3(x.0, x.1, x.2) + MultiLocation { parents: 0, interior: Junctions::X3(x.0, x.1, x.2) } } } impl From<(Junction, Junction, Junction, Junction)> for MultiLocation { fn from(x: (Junction, Junction, Junction, Junction)) -> Self { - MultiLocation::X4(x.0, x.1, x.2, x.3) + MultiLocation { parents: 0, interior: Junctions::X4(x.0, x.1, x.2, x.3) } } } impl From<(Junction, Junction, Junction, Junction, Junction)> for MultiLocation { fn from(x: (Junction, Junction, Junction, Junction, Junction)) -> Self { - MultiLocation::X5(x.0, x.1, x.2, x.3, x.4) + MultiLocation { parents: 0, interior: Junctions::X5(x.0, x.1, x.2, x.3, x.4) } } } impl From<(Junction, Junction, Junction, Junction, Junction, Junction)> for MultiLocation { fn from(x: (Junction, Junction, Junction, Junction, Junction, Junction)) -> Self { - MultiLocation::X6(x.0, x.1, x.2, x.3, x.4, x.5) + MultiLocation { parents: 0, interior: Junctions::X6(x.0, x.1, x.2, x.3, x.4, x.5) } } } impl From<(Junction, Junction, Junction, Junction, Junction, Junction, Junction)> for MultiLocation { fn from(x: (Junction, Junction, Junction, Junction, Junction, Junction, Junction)) -> Self { - MultiLocation::X7(x.0, x.1, x.2, x.3, x.4, x.5, x.6) + MultiLocation { parents: 0, interior: Junctions::X7(x.0, x.1, x.2, x.3, x.4, x.5, x.6) } } } impl From<(Junction, Junction, Junction, Junction, Junction, Junction, Junction, Junction)> @@ -121,169 +433,325 @@ impl From<(Junction, Junction, Junction, Junction, Junction, Junction, Junction, fn from( x: (Junction, Junction, Junction, Junction, Junction, Junction, Junction, Junction), ) -> Self { - MultiLocation::X8(x.0, x.1, x.2, x.3, x.4, x.5, x.6, x.7) + MultiLocation { + parents: 0, + interior: Junctions::X8(x.0, x.1, x.2, x.3, x.4, x.5, x.6, x.7), + } + } +} + +impl From<(u8,)> for MultiLocation { + fn from((parents,): (u8,)) -> Self { + MultiLocation { parents, interior: Junctions::Here } + } +} +impl From<(u8, Junction)> for MultiLocation { + fn from((parents, j0): (u8, Junction)) -> Self { + MultiLocation { parents, interior: Junctions::X1(j0) } + } +} +impl From<(u8, Junction, Junction)> for MultiLocation { + fn from((parents, j0, j1): (u8, Junction, Junction)) -> Self { + MultiLocation { parents, interior: Junctions::X2(j0, j1) } + } +} +impl From<(u8, Junction, Junction, Junction)> for MultiLocation { + fn from((parents, j0, j1, j2): (u8, Junction, Junction, Junction)) -> Self { + MultiLocation { parents, interior: Junctions::X3(j0, j1, j2) } + } +} +impl From<(u8, Junction, Junction, Junction, Junction)> for MultiLocation { + fn from((parents, j0, j1, j2, j3): (u8, Junction, Junction, Junction, Junction)) -> Self { + MultiLocation { parents, interior: Junctions::X4(j0, j1, j2, j3) } + } +} +impl From<(u8, Junction, Junction, Junction, Junction, Junction)> for MultiLocation { + fn from( + (parents, j0, j1, j2, j3, j4): (u8, Junction, Junction, Junction, Junction, Junction), + ) -> Self { + MultiLocation { parents, interior: Junctions::X5(j0, j1, j2, j3, j4) } + } +} +impl From<(u8, Junction, Junction, Junction, Junction, Junction, Junction)> for MultiLocation { + fn from( + (parents, j0, j1, j2, j3, j4, j5): ( + u8, + Junction, + Junction, + Junction, + Junction, + Junction, + Junction, + ), + ) -> Self { + MultiLocation { parents, interior: Junctions::X6(j0, j1, j2, j3, j4, j5) } + } +} +impl From<(u8, Junction, Junction, Junction, Junction, Junction, Junction, Junction)> + for MultiLocation +{ + fn from( + (parents, j0, j1, j2, j3, j4, j5, j6): ( + u8, + Junction, + Junction, + Junction, + Junction, + Junction, + Junction, + Junction, + ), + ) -> Self { + MultiLocation { parents, interior: Junctions::X7(j0, j1, j2, j3, j4, j5, j6) } + } +} +impl From<(u8, Junction, Junction, Junction, Junction, Junction, Junction, Junction, Junction)> + for MultiLocation +{ + fn from( + (parents, j0, j1, j2, j3, j4, j5, j6, j7): ( + u8, + Junction, + Junction, + Junction, + Junction, + Junction, + Junction, + Junction, + Junction, + ), + ) -> Self { + MultiLocation { parents, interior: Junctions::X8(j0, j1, j2, j3, j4, j5, j6, j7) } } } impl From<[Junction; 0]> for MultiLocation { fn from(_: [Junction; 0]) -> Self { - MultiLocation::Here + MultiLocation { parents: 0, interior: Junctions::Here } } } impl From<[Junction; 1]> for MultiLocation { fn from(x: [Junction; 1]) -> Self { let [x0] = x; - MultiLocation::X1(x0) + MultiLocation { parents: 0, interior: Junctions::X1(x0) } } } impl From<[Junction; 2]> for MultiLocation { fn from(x: [Junction; 2]) -> Self { let [x0, x1] = x; - MultiLocation::X2(x0, x1) + MultiLocation { parents: 0, interior: Junctions::X2(x0, x1) } } } impl From<[Junction; 3]> for MultiLocation { fn from(x: [Junction; 3]) -> Self { let [x0, x1, x2] = x; - MultiLocation::X3(x0, x1, x2) + MultiLocation { parents: 0, interior: Junctions::X3(x0, x1, x2) } } } impl From<[Junction; 4]> for MultiLocation { fn from(x: [Junction; 4]) -> Self { let [x0, x1, x2, x3] = x; - MultiLocation::X4(x0, x1, x2, x3) + MultiLocation { parents: 0, interior: Junctions::X4(x0, x1, x2, x3) } } } impl From<[Junction; 5]> for MultiLocation { fn from(x: [Junction; 5]) -> Self { let [x0, x1, x2, x3, x4] = x; - MultiLocation::X5(x0, x1, x2, x3, x4) + MultiLocation { parents: 0, interior: Junctions::X5(x0, x1, x2, x3, x4) } } } impl From<[Junction; 6]> for MultiLocation { fn from(x: [Junction; 6]) -> Self { let [x0, x1, x2, x3, x4, x5] = x; - MultiLocation::X6(x0, x1, x2, x3, x4, x5) + MultiLocation { parents: 0, interior: Junctions::X6(x0, x1, x2, x3, x4, x5) } } } impl From<[Junction; 7]> for MultiLocation { fn from(x: [Junction; 7]) -> Self { let [x0, x1, x2, x3, x4, x5, x6] = x; - MultiLocation::X7(x0, x1, x2, x3, x4, x5, x6) + MultiLocation { parents: 0, interior: Junctions::X7(x0, x1, x2, x3, x4, x5, x6) } } } impl From<[Junction; 8]> for MultiLocation { fn from(x: [Junction; 8]) -> Self { let [x0, x1, x2, x3, x4, x5, x6, x7] = x; - MultiLocation::X8(x0, x1, x2, x3, x4, x5, x6, x7) + MultiLocation { parents: 0, interior: Junctions::X8(x0, x1, x2, x3, x4, x5, x6, x7) } } } -pub struct MultiLocationIterator(MultiLocation); -impl Iterator for MultiLocationIterator { +/// Maximum number of `Junction`s that a `Junctions` can contain. +const MAX_JUNCTIONS: usize = 8; + +/// Non-parent junctions that can be constructed, up to the length of 8. This specific `Junctions` +/// implementation uses a Rust `enum` in order to make pattern matching easier. +/// +/// Parent junctions cannot be constructed with this type. Refer to `MultiLocation` for +/// instructions on constructing parent junctions. +#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug)] +pub enum Junctions { + /// The interpreting consensus system. + Here, + /// A relative path comprising 1 junction. + X1(Junction), + /// A relative path comprising 2 junctions. + X2(Junction, Junction), + /// A relative path comprising 3 junctions. + X3(Junction, Junction, Junction), + /// A relative path comprising 4 junctions. + X4(Junction, Junction, Junction, Junction), + /// A relative path comprising 5 junctions. + X5(Junction, Junction, Junction, Junction, Junction), + /// A relative path comprising 6 junctions. + X6(Junction, Junction, Junction, Junction, Junction, Junction), + /// A relative path comprising 7 junctions. + X7(Junction, Junction, Junction, Junction, Junction, Junction, Junction), + /// A relative path comprising 8 junctions. + X8(Junction, Junction, Junction, Junction, Junction, Junction, Junction, Junction), +} + +pub struct JunctionsIterator(Junctions); +impl Iterator for JunctionsIterator { type Item = Junction; fn next(&mut self) -> Option { self.0.take_first() } } -pub struct MultiLocationReverseIterator(MultiLocation); -impl Iterator for MultiLocationReverseIterator { - type Item = Junction; - fn next(&mut self) -> Option { +impl DoubleEndedIterator for JunctionsIterator { + fn next_back(&mut self) -> Option { self.0.take_last() } } -pub struct MultiLocationRefIterator<'a>(&'a MultiLocation, usize); -impl<'a> Iterator for MultiLocationRefIterator<'a> { +pub struct JunctionsRefIterator<'a> { + junctions: &'a Junctions, + next: usize, + back: usize, +} + +impl<'a> Iterator for JunctionsRefIterator<'a> { type Item = &'a Junction; fn next(&mut self) -> Option<&'a Junction> { - let result = self.0.at(self.1); - self.1 += 1; + if self.next.saturating_add(self.back) >= self.junctions.len() { + return None + } + + let result = self.junctions.at(self.next); + self.next += 1; result } } -pub struct MultiLocationReverseRefIterator<'a>(&'a MultiLocation, usize); -impl<'a> Iterator for MultiLocationReverseRefIterator<'a> { +impl<'a> DoubleEndedIterator for JunctionsRefIterator<'a> { + fn next_back(&mut self) -> Option<&'a Junction> { + let next_back = self.back.saturating_add(1); + // checked_sub here, because if the result is less than 0, we end iteration + let index = self.junctions.len().checked_sub(next_back)?; + if self.next > index { + return None + } + self.back = next_back; + + self.junctions.at(index) + } +} + +impl<'a> IntoIterator for &'a Junctions { type Item = &'a Junction; - fn next(&mut self) -> Option<&'a Junction> { - self.1 += 1; - self.0.at(self.0.len().checked_sub(self.1)?) + type IntoIter = JunctionsRefIterator<'a>; + fn into_iter(self) -> Self::IntoIter { + JunctionsRefIterator { junctions: self, next: 0, back: 0 } } } -impl MultiLocation { +impl IntoIterator for Junctions { + type Item = Junction; + type IntoIter = JunctionsIterator; + fn into_iter(self) -> Self::IntoIter { + JunctionsIterator(self) + } +} + +impl Junctions { + /// Convert `self` into a `MultiLocation` containing 0 parents. + /// + /// Similar to `Into::into`, except that this method can be used in a const evaluation context. + pub const fn into(self) -> MultiLocation { + MultiLocation { parents: 0, interior: self } + } + + /// Convert `self` into a `MultiLocation` containing `n` parents. + /// + /// Similar to `Self::into`, with the added ability to specify the number of parent junctions. + pub const fn into_exterior(self, n: u8) -> MultiLocation { + MultiLocation { parents: n, interior: self } + } + /// Returns first junction, or `None` if the location is empty. pub fn first(&self) -> Option<&Junction> { match &self { - MultiLocation::Here => None, - MultiLocation::X1(ref a) => Some(a), - MultiLocation::X2(ref a, ..) => Some(a), - MultiLocation::X3(ref a, ..) => Some(a), - MultiLocation::X4(ref a, ..) => Some(a), - MultiLocation::X5(ref a, ..) => Some(a), - MultiLocation::X6(ref a, ..) => Some(a), - MultiLocation::X7(ref a, ..) => Some(a), - MultiLocation::X8(ref a, ..) => Some(a), + Junctions::Here => None, + Junctions::X1(ref a) => Some(a), + Junctions::X2(ref a, ..) => Some(a), + Junctions::X3(ref a, ..) => Some(a), + Junctions::X4(ref a, ..) => Some(a), + Junctions::X5(ref a, ..) => Some(a), + Junctions::X6(ref a, ..) => Some(a), + Junctions::X7(ref a, ..) => Some(a), + Junctions::X8(ref a, ..) => Some(a), } } /// Returns last junction, or `None` if the location is empty. pub fn last(&self) -> Option<&Junction> { match &self { - MultiLocation::Here => None, - MultiLocation::X1(ref a) => Some(a), - MultiLocation::X2(.., ref a) => Some(a), - MultiLocation::X3(.., ref a) => Some(a), - MultiLocation::X4(.., ref a) => Some(a), - MultiLocation::X5(.., ref a) => Some(a), - MultiLocation::X6(.., ref a) => Some(a), - MultiLocation::X7(.., ref a) => Some(a), - MultiLocation::X8(.., ref a) => Some(a), + Junctions::Here => None, + Junctions::X1(ref a) => Some(a), + Junctions::X2(.., ref a) => Some(a), + Junctions::X3(.., ref a) => Some(a), + Junctions::X4(.., ref a) => Some(a), + Junctions::X5(.., ref a) => Some(a), + Junctions::X6(.., ref a) => Some(a), + Junctions::X7(.., ref a) => Some(a), + Junctions::X8(.., ref a) => Some(a), } } /// Splits off the first junction, returning the remaining suffix (first item in tuple) and the first element /// (second item in tuple) or `None` if it was empty. - pub fn split_first(self) -> (MultiLocation, Option) { + pub fn split_first(self) -> (Junctions, Option) { match self { - MultiLocation::Here => (MultiLocation::Here, None), - MultiLocation::X1(a) => (MultiLocation::Here, Some(a)), - MultiLocation::X2(a, b) => (MultiLocation::X1(b), Some(a)), - MultiLocation::X3(a, b, c) => (MultiLocation::X2(b, c), Some(a)), - MultiLocation::X4(a, b, c, d) => (MultiLocation::X3(b, c, d), Some(a)), - MultiLocation::X5(a, b, c, d, e) => (MultiLocation::X4(b, c, d, e), Some(a)), - MultiLocation::X6(a, b, c, d, e, f) => (MultiLocation::X5(b, c, d, e, f), Some(a)), - MultiLocation::X7(a, b, c, d, e, f, g) => - (MultiLocation::X6(b, c, d, e, f, g), Some(a)), - MultiLocation::X8(a, b, c, d, e, f, g, h) => - (MultiLocation::X7(b, c, d, e, f, g, h), Some(a)), + Junctions::Here => (Junctions::Here, None), + Junctions::X1(a) => (Junctions::Here, Some(a)), + Junctions::X2(a, b) => (Junctions::X1(b), Some(a)), + Junctions::X3(a, b, c) => (Junctions::X2(b, c), Some(a)), + Junctions::X4(a, b, c, d) => (Junctions::X3(b, c, d), Some(a)), + Junctions::X5(a, b, c, d, e) => (Junctions::X4(b, c, d, e), Some(a)), + Junctions::X6(a, b, c, d, e, f) => (Junctions::X5(b, c, d, e, f), Some(a)), + Junctions::X7(a, b, c, d, e, f, g) => (Junctions::X6(b, c, d, e, f, g), Some(a)), + Junctions::X8(a, b, c, d, e, f, g, h) => (Junctions::X7(b, c, d, e, f, g, h), Some(a)), } } /// Splits off the last junction, returning the remaining prefix (first item in tuple) and the last element /// (second item in tuple) or `None` if it was empty. - pub fn split_last(self) -> (MultiLocation, Option) { + pub fn split_last(self) -> (Junctions, Option) { match self { - MultiLocation::Here => (MultiLocation::Here, None), - MultiLocation::X1(a) => (MultiLocation::Here, Some(a)), - MultiLocation::X2(a, b) => (MultiLocation::X1(a), Some(b)), - MultiLocation::X3(a, b, c) => (MultiLocation::X2(a, b), Some(c)), - MultiLocation::X4(a, b, c, d) => (MultiLocation::X3(a, b, c), Some(d)), - MultiLocation::X5(a, b, c, d, e) => (MultiLocation::X4(a, b, c, d), Some(e)), - MultiLocation::X6(a, b, c, d, e, f) => (MultiLocation::X5(a, b, c, d, e), Some(f)), - MultiLocation::X7(a, b, c, d, e, f, g) => - (MultiLocation::X6(a, b, c, d, e, f), Some(g)), - MultiLocation::X8(a, b, c, d, e, f, g, h) => - (MultiLocation::X7(a, b, c, d, e, f, g), Some(h)), + Junctions::Here => (Junctions::Here, None), + Junctions::X1(a) => (Junctions::Here, Some(a)), + Junctions::X2(a, b) => (Junctions::X1(a), Some(b)), + Junctions::X3(a, b, c) => (Junctions::X2(a, b), Some(c)), + Junctions::X4(a, b, c, d) => (Junctions::X3(a, b, c), Some(d)), + Junctions::X5(a, b, c, d, e) => (Junctions::X4(a, b, c, d), Some(e)), + Junctions::X6(a, b, c, d, e, f) => (Junctions::X5(a, b, c, d, e), Some(f)), + Junctions::X7(a, b, c, d, e, f, g) => (Junctions::X6(a, b, c, d, e, f), Some(g)), + Junctions::X8(a, b, c, d, e, f, g, h) => (Junctions::X7(a, b, c, d, e, f, g), Some(h)), } } /// Removes the first element from `self`, returning it (or `None` if it was empty). pub fn take_first(&mut self) -> Option { - let mut d = MultiLocation::Here; + let mut d = Junctions::Here; mem::swap(&mut *self, &mut d); let (tail, head) = d.split_first(); *self = tail; @@ -292,99 +760,99 @@ impl MultiLocation { /// Removes the last element from `self`, returning it (or `None` if it was empty). pub fn take_last(&mut self) -> Option { - let mut d = MultiLocation::Here; + let mut d = Junctions::Here; mem::swap(&mut *self, &mut d); let (head, tail) = d.split_last(); *self = head; tail } - /// Consumes `self` and returns a `MultiLocation` suffixed with `new`, or an `Err` with the original value of + /// Consumes `self` and returns a `Junctions` suffixed with `new`, or an `Err` with the original value of /// `self` in case of overflow. pub fn pushed_with(self, new: Junction) -> result::Result { Ok(match self { - MultiLocation::Here => MultiLocation::X1(new), - MultiLocation::X1(a) => MultiLocation::X2(a, new), - MultiLocation::X2(a, b) => MultiLocation::X3(a, b, new), - MultiLocation::X3(a, b, c) => MultiLocation::X4(a, b, c, new), - MultiLocation::X4(a, b, c, d) => MultiLocation::X5(a, b, c, d, new), - MultiLocation::X5(a, b, c, d, e) => MultiLocation::X6(a, b, c, d, e, new), - MultiLocation::X6(a, b, c, d, e, f) => MultiLocation::X7(a, b, c, d, e, f, new), - MultiLocation::X7(a, b, c, d, e, f, g) => MultiLocation::X8(a, b, c, d, e, f, g, new), + Junctions::Here => Junctions::X1(new), + Junctions::X1(a) => Junctions::X2(a, new), + Junctions::X2(a, b) => Junctions::X3(a, b, new), + Junctions::X3(a, b, c) => Junctions::X4(a, b, c, new), + Junctions::X4(a, b, c, d) => Junctions::X5(a, b, c, d, new), + Junctions::X5(a, b, c, d, e) => Junctions::X6(a, b, c, d, e, new), + Junctions::X6(a, b, c, d, e, f) => Junctions::X7(a, b, c, d, e, f, new), + Junctions::X7(a, b, c, d, e, f, g) => Junctions::X8(a, b, c, d, e, f, g, new), s => Err(s)?, }) } - /// Consumes `self` and returns a `MultiLocation` prefixed with `new`, or an `Err` with the original value of + /// Consumes `self` and returns a `Junctions` prefixed with `new`, or an `Err` with the original value of /// `self` in case of overflow. pub fn pushed_front_with(self, new: Junction) -> result::Result { Ok(match self { - MultiLocation::Here => MultiLocation::X1(new), - MultiLocation::X1(a) => MultiLocation::X2(new, a), - MultiLocation::X2(a, b) => MultiLocation::X3(new, a, b), - MultiLocation::X3(a, b, c) => MultiLocation::X4(new, a, b, c), - MultiLocation::X4(a, b, c, d) => MultiLocation::X5(new, a, b, c, d), - MultiLocation::X5(a, b, c, d, e) => MultiLocation::X6(new, a, b, c, d, e), - MultiLocation::X6(a, b, c, d, e, f) => MultiLocation::X7(new, a, b, c, d, e, f), - MultiLocation::X7(a, b, c, d, e, f, g) => MultiLocation::X8(new, a, b, c, d, e, f, g), + Junctions::Here => Junctions::X1(new), + Junctions::X1(a) => Junctions::X2(new, a), + Junctions::X2(a, b) => Junctions::X3(new, a, b), + Junctions::X3(a, b, c) => Junctions::X4(new, a, b, c), + Junctions::X4(a, b, c, d) => Junctions::X5(new, a, b, c, d), + Junctions::X5(a, b, c, d, e) => Junctions::X6(new, a, b, c, d, e), + Junctions::X6(a, b, c, d, e, f) => Junctions::X7(new, a, b, c, d, e, f), + Junctions::X7(a, b, c, d, e, f, g) => Junctions::X8(new, a, b, c, d, e, f, g), s => Err(s)?, }) } /// Returns the number of junctions in `self`. - pub fn len(&self) -> usize { + pub const fn len(&self) -> usize { match &self { - MultiLocation::Here => 0, - MultiLocation::X1(..) => 1, - MultiLocation::X2(..) => 2, - MultiLocation::X3(..) => 3, - MultiLocation::X4(..) => 4, - MultiLocation::X5(..) => 5, - MultiLocation::X6(..) => 6, - MultiLocation::X7(..) => 7, - MultiLocation::X8(..) => 8, + Junctions::Here => 0, + Junctions::X1(..) => 1, + Junctions::X2(..) => 2, + Junctions::X3(..) => 3, + Junctions::X4(..) => 4, + Junctions::X5(..) => 5, + Junctions::X6(..) => 6, + Junctions::X7(..) => 7, + Junctions::X8(..) => 8, } } /// Returns the junction at index `i`, or `None` if the location doesn't contain that many elements. pub fn at(&self, i: usize) -> Option<&Junction> { - Some(match (i, &self) { - (0, MultiLocation::X1(ref a)) => a, - (0, MultiLocation::X2(ref a, ..)) => a, - (0, MultiLocation::X3(ref a, ..)) => a, - (0, MultiLocation::X4(ref a, ..)) => a, - (0, MultiLocation::X5(ref a, ..)) => a, - (0, MultiLocation::X6(ref a, ..)) => a, - (0, MultiLocation::X7(ref a, ..)) => a, - (0, MultiLocation::X8(ref a, ..)) => a, - (1, MultiLocation::X2(_, ref a)) => a, - (1, MultiLocation::X3(_, ref a, ..)) => a, - (1, MultiLocation::X4(_, ref a, ..)) => a, - (1, MultiLocation::X5(_, ref a, ..)) => a, - (1, MultiLocation::X6(_, ref a, ..)) => a, - (1, MultiLocation::X7(_, ref a, ..)) => a, - (1, MultiLocation::X8(_, ref a, ..)) => a, - (2, MultiLocation::X3(_, _, ref a)) => a, - (2, MultiLocation::X4(_, _, ref a, ..)) => a, - (2, MultiLocation::X5(_, _, ref a, ..)) => a, - (2, MultiLocation::X6(_, _, ref a, ..)) => a, - (2, MultiLocation::X7(_, _, ref a, ..)) => a, - (2, MultiLocation::X8(_, _, ref a, ..)) => a, - (3, MultiLocation::X4(_, _, _, ref a)) => a, - (3, MultiLocation::X5(_, _, _, ref a, ..)) => a, - (3, MultiLocation::X6(_, _, _, ref a, ..)) => a, - (3, MultiLocation::X7(_, _, _, ref a, ..)) => a, - (3, MultiLocation::X8(_, _, _, ref a, ..)) => a, - (4, MultiLocation::X5(_, _, _, _, ref a)) => a, - (4, MultiLocation::X6(_, _, _, _, ref a, ..)) => a, - (4, MultiLocation::X7(_, _, _, _, ref a, ..)) => a, - (4, MultiLocation::X8(_, _, _, _, ref a, ..)) => a, - (5, MultiLocation::X6(_, _, _, _, _, ref a)) => a, - (5, MultiLocation::X7(_, _, _, _, _, ref a, ..)) => a, - (5, MultiLocation::X8(_, _, _, _, _, ref a, ..)) => a, - (6, MultiLocation::X7(_, _, _, _, _, _, ref a)) => a, - (6, MultiLocation::X8(_, _, _, _, _, _, ref a, ..)) => a, - (7, MultiLocation::X8(_, _, _, _, _, _, _, ref a)) => a, + Some(match (i, self) { + (0, Junctions::X1(ref a)) => a, + (0, Junctions::X2(ref a, ..)) => a, + (0, Junctions::X3(ref a, ..)) => a, + (0, Junctions::X4(ref a, ..)) => a, + (0, Junctions::X5(ref a, ..)) => a, + (0, Junctions::X6(ref a, ..)) => a, + (0, Junctions::X7(ref a, ..)) => a, + (0, Junctions::X8(ref a, ..)) => a, + (1, Junctions::X2(_, ref a)) => a, + (1, Junctions::X3(_, ref a, ..)) => a, + (1, Junctions::X4(_, ref a, ..)) => a, + (1, Junctions::X5(_, ref a, ..)) => a, + (1, Junctions::X6(_, ref a, ..)) => a, + (1, Junctions::X7(_, ref a, ..)) => a, + (1, Junctions::X8(_, ref a, ..)) => a, + (2, Junctions::X3(_, _, ref a)) => a, + (2, Junctions::X4(_, _, ref a, ..)) => a, + (2, Junctions::X5(_, _, ref a, ..)) => a, + (2, Junctions::X6(_, _, ref a, ..)) => a, + (2, Junctions::X7(_, _, ref a, ..)) => a, + (2, Junctions::X8(_, _, ref a, ..)) => a, + (3, Junctions::X4(_, _, _, ref a)) => a, + (3, Junctions::X5(_, _, _, ref a, ..)) => a, + (3, Junctions::X6(_, _, _, ref a, ..)) => a, + (3, Junctions::X7(_, _, _, ref a, ..)) => a, + (3, Junctions::X8(_, _, _, ref a, ..)) => a, + (4, Junctions::X5(_, _, _, _, ref a)) => a, + (4, Junctions::X6(_, _, _, _, ref a, ..)) => a, + (4, Junctions::X7(_, _, _, _, ref a, ..)) => a, + (4, Junctions::X8(_, _, _, _, ref a, ..)) => a, + (5, Junctions::X6(_, _, _, _, _, ref a)) => a, + (5, Junctions::X7(_, _, _, _, _, ref a, ..)) => a, + (5, Junctions::X8(_, _, _, _, _, ref a, ..)) => a, + (6, Junctions::X7(_, _, _, _, _, _, ref a)) => a, + (6, Junctions::X8(_, _, _, _, _, _, ref a, ..)) => a, + (7, Junctions::X8(_, _, _, _, _, _, _, ref a)) => a, _ => return None, }) } @@ -393,64 +861,61 @@ impl MultiLocation { /// elements. pub fn at_mut(&mut self, i: usize) -> Option<&mut Junction> { Some(match (i, self) { - (0, MultiLocation::X1(ref mut a)) => a, - (0, MultiLocation::X2(ref mut a, ..)) => a, - (0, MultiLocation::X3(ref mut a, ..)) => a, - (0, MultiLocation::X4(ref mut a, ..)) => a, - (0, MultiLocation::X5(ref mut a, ..)) => a, - (0, MultiLocation::X6(ref mut a, ..)) => a, - (0, MultiLocation::X7(ref mut a, ..)) => a, - (0, MultiLocation::X8(ref mut a, ..)) => a, - (1, MultiLocation::X2(_, ref mut a)) => a, - (1, MultiLocation::X3(_, ref mut a, ..)) => a, - (1, MultiLocation::X4(_, ref mut a, ..)) => a, - (1, MultiLocation::X5(_, ref mut a, ..)) => a, - (1, MultiLocation::X6(_, ref mut a, ..)) => a, - (1, MultiLocation::X7(_, ref mut a, ..)) => a, - (1, MultiLocation::X8(_, ref mut a, ..)) => a, - (2, MultiLocation::X3(_, _, ref mut a)) => a, - (2, MultiLocation::X4(_, _, ref mut a, ..)) => a, - (2, MultiLocation::X5(_, _, ref mut a, ..)) => a, - (2, MultiLocation::X6(_, _, ref mut a, ..)) => a, - (2, MultiLocation::X7(_, _, ref mut a, ..)) => a, - (2, MultiLocation::X8(_, _, ref mut a, ..)) => a, - (3, MultiLocation::X4(_, _, _, ref mut a)) => a, - (3, MultiLocation::X5(_, _, _, ref mut a, ..)) => a, - (3, MultiLocation::X6(_, _, _, ref mut a, ..)) => a, - (3, MultiLocation::X7(_, _, _, ref mut a, ..)) => a, - (3, MultiLocation::X8(_, _, _, ref mut a, ..)) => a, - (4, MultiLocation::X5(_, _, _, _, ref mut a)) => a, - (4, MultiLocation::X6(_, _, _, _, ref mut a, ..)) => a, - (4, MultiLocation::X7(_, _, _, _, ref mut a, ..)) => a, - (4, MultiLocation::X8(_, _, _, _, ref mut a, ..)) => a, - (5, MultiLocation::X6(_, _, _, _, _, ref mut a)) => a, - (5, MultiLocation::X7(_, _, _, _, _, ref mut a, ..)) => a, - (5, MultiLocation::X8(_, _, _, _, _, ref mut a, ..)) => a, - (6, MultiLocation::X7(_, _, _, _, _, _, ref mut a)) => a, - (6, MultiLocation::X8(_, _, _, _, _, _, ref mut a, ..)) => a, - (7, MultiLocation::X8(_, _, _, _, _, _, _, ref mut a)) => a, + (0, Junctions::X1(ref mut a)) => a, + (0, Junctions::X2(ref mut a, ..)) => a, + (0, Junctions::X3(ref mut a, ..)) => a, + (0, Junctions::X4(ref mut a, ..)) => a, + (0, Junctions::X5(ref mut a, ..)) => a, + (0, Junctions::X6(ref mut a, ..)) => a, + (0, Junctions::X7(ref mut a, ..)) => a, + (0, Junctions::X8(ref mut a, ..)) => a, + (1, Junctions::X2(_, ref mut a)) => a, + (1, Junctions::X3(_, ref mut a, ..)) => a, + (1, Junctions::X4(_, ref mut a, ..)) => a, + (1, Junctions::X5(_, ref mut a, ..)) => a, + (1, Junctions::X6(_, ref mut a, ..)) => a, + (1, Junctions::X7(_, ref mut a, ..)) => a, + (1, Junctions::X8(_, ref mut a, ..)) => a, + (2, Junctions::X3(_, _, ref mut a)) => a, + (2, Junctions::X4(_, _, ref mut a, ..)) => a, + (2, Junctions::X5(_, _, ref mut a, ..)) => a, + (2, Junctions::X6(_, _, ref mut a, ..)) => a, + (2, Junctions::X7(_, _, ref mut a, ..)) => a, + (2, Junctions::X8(_, _, ref mut a, ..)) => a, + (3, Junctions::X4(_, _, _, ref mut a)) => a, + (3, Junctions::X5(_, _, _, ref mut a, ..)) => a, + (3, Junctions::X6(_, _, _, ref mut a, ..)) => a, + (3, Junctions::X7(_, _, _, ref mut a, ..)) => a, + (3, Junctions::X8(_, _, _, ref mut a, ..)) => a, + (4, Junctions::X5(_, _, _, _, ref mut a)) => a, + (4, Junctions::X6(_, _, _, _, ref mut a, ..)) => a, + (4, Junctions::X7(_, _, _, _, ref mut a, ..)) => a, + (4, Junctions::X8(_, _, _, _, ref mut a, ..)) => a, + (5, Junctions::X6(_, _, _, _, _, ref mut a)) => a, + (5, Junctions::X7(_, _, _, _, _, ref mut a, ..)) => a, + (5, Junctions::X8(_, _, _, _, _, ref mut a, ..)) => a, + (6, Junctions::X7(_, _, _, _, _, _, ref mut a)) => a, + (6, Junctions::X8(_, _, _, _, _, _, ref mut a, ..)) => a, + (7, Junctions::X8(_, _, _, _, _, _, _, ref mut a)) => a, _ => return None, }) } /// Returns a reference iterator over the junctions. - pub fn iter(&self) -> MultiLocationRefIterator { - MultiLocationRefIterator(&self, 0) + pub fn iter(&self) -> JunctionsRefIterator { + JunctionsRefIterator { junctions: self, next: 0, back: 0 } } /// Returns a reference iterator over the junctions in reverse. - pub fn iter_rev(&self) -> MultiLocationReverseRefIterator { - MultiLocationReverseRefIterator(&self, 0) - } - - /// Consumes `self` and returns an iterator over the junctions. - pub fn into_iter(self) -> MultiLocationIterator { - MultiLocationIterator(self) + #[deprecated(note = "Please use iter().rev()")] + pub fn iter_rev(&self) -> impl Iterator + '_ { + self.iter().rev() } /// Consumes `self` and returns an iterator over the junctions in reverse. - pub fn into_iter_rev(self) -> MultiLocationReverseIterator { - MultiLocationReverseIterator(self) + #[deprecated(note = "Please use into_iter().rev()")] + pub fn into_iter_rev(self) -> impl Iterator { + self.into_iter().rev() } /// Ensures that self begins with `prefix` and that it has a single `Junction` item following. @@ -458,14 +923,14 @@ impl MultiLocation { /// /// # Example /// ```rust - /// # use xcm::latest::{MultiLocation::*, Junction::*}; + /// # use xcm::latest::{Junctions::*, Junction::*}; /// # fn main() { - /// let mut m = X3(Parent, PalletInstance(3), OnlyChild); - /// assert_eq!(m.match_and_split(&X2(Parent, PalletInstance(3))), Some(&OnlyChild)); - /// assert_eq!(m.match_and_split(&X1(Parent)), None); + /// let mut m = X3(Parachain(2), PalletInstance(3), OnlyChild); + /// assert_eq!(m.match_and_split(&X2(Parachain(2), PalletInstance(3))), Some(&OnlyChild)); + /// assert_eq!(m.match_and_split(&X1(Parachain(2))), None); /// # } /// ``` - pub fn match_and_split(&self, prefix: &MultiLocation) -> Option<&Junction> { + pub fn match_and_split(&self, prefix: &Junctions) -> Option<&Junction> { if prefix.len() + 1 != self.len() { return None } @@ -476,254 +941,301 @@ impl MultiLocation { } return self.at(prefix.len()) } +} - /// Mutates `self`, suffixing it with `new`. Returns `Err` in case of overflow. - pub fn push(&mut self, new: Junction) -> result::Result<(), ()> { - let mut n = MultiLocation::Here; - mem::swap(&mut *self, &mut n); - match n.pushed_with(new) { - Ok(result) => { - *self = result; - Ok(()) - }, - Err(old) => { - *self = old; - Err(()) - }, - } - } - - /// Mutates `self`, prefixing it with `new`. Returns `Err` in case of overflow. - pub fn push_front(&mut self, new: Junction) -> result::Result<(), ()> { - let mut n = MultiLocation::Here; - mem::swap(&mut *self, &mut n); - match n.pushed_front_with(new) { - Ok(result) => { - *self = result; - Ok(()) - }, - Err(old) => { - *self = old; - Err(()) - }, - } - } - - /// Returns the number of `Parent` junctions at the beginning of `self`. - pub fn leading_parent_count(&self) -> usize { - use Junction::Parent; - match self { - MultiLocation::X8(Parent, Parent, Parent, Parent, Parent, Parent, Parent, Parent) => 8, - - MultiLocation::X8(Parent, Parent, Parent, Parent, Parent, Parent, Parent, ..) => 7, - MultiLocation::X7(Parent, Parent, Parent, Parent, Parent, Parent, Parent) => 7, - - MultiLocation::X8(Parent, Parent, Parent, Parent, Parent, Parent, ..) => 6, - MultiLocation::X7(Parent, Parent, Parent, Parent, Parent, Parent, ..) => 6, - MultiLocation::X6(Parent, Parent, Parent, Parent, Parent, Parent) => 6, - - MultiLocation::X8(Parent, Parent, Parent, Parent, Parent, ..) => 5, - MultiLocation::X7(Parent, Parent, Parent, Parent, Parent, ..) => 5, - MultiLocation::X6(Parent, Parent, Parent, Parent, Parent, ..) => 5, - MultiLocation::X5(Parent, Parent, Parent, Parent, Parent) => 5, - - MultiLocation::X8(Parent, Parent, Parent, Parent, ..) => 4, - MultiLocation::X7(Parent, Parent, Parent, Parent, ..) => 4, - MultiLocation::X6(Parent, Parent, Parent, Parent, ..) => 4, - MultiLocation::X5(Parent, Parent, Parent, Parent, ..) => 4, - MultiLocation::X4(Parent, Parent, Parent, Parent) => 4, - - MultiLocation::X8(Parent, Parent, Parent, ..) => 3, - MultiLocation::X7(Parent, Parent, Parent, ..) => 3, - MultiLocation::X6(Parent, Parent, Parent, ..) => 3, - MultiLocation::X5(Parent, Parent, Parent, ..) => 3, - MultiLocation::X4(Parent, Parent, Parent, ..) => 3, - MultiLocation::X3(Parent, Parent, Parent) => 3, - - MultiLocation::X8(Parent, Parent, ..) => 2, - MultiLocation::X7(Parent, Parent, ..) => 2, - MultiLocation::X6(Parent, Parent, ..) => 2, - MultiLocation::X5(Parent, Parent, ..) => 2, - MultiLocation::X4(Parent, Parent, ..) => 2, - MultiLocation::X3(Parent, Parent, ..) => 2, - MultiLocation::X2(Parent, Parent) => 2, - - MultiLocation::X8(Parent, ..) => 1, - MultiLocation::X7(Parent, ..) => 1, - MultiLocation::X6(Parent, ..) => 1, - MultiLocation::X5(Parent, ..) => 1, - MultiLocation::X4(Parent, ..) => 1, - MultiLocation::X3(Parent, ..) => 1, - MultiLocation::X2(Parent, ..) => 1, - MultiLocation::X1(Parent) => 1, - _ => 0, - } - } - - /// This function ensures a multi-junction is in its canonicalized/normalized form, removing - /// any internal `[Non-Parent, Parent]` combinations. - pub fn canonicalize(&mut self) { - let mut normalized = MultiLocation::Here; - let mut iter = self.iter(); - // We build up the the new normalized path by taking items from the original multi-location. - // When the next item we would add is `Parent`, we instead remove the last item assuming - // it is non-parent. - const EXPECT_MESSAGE: &'static str = - "`self` is a well formed multi-location with N junctions; \ - this loop iterates over the junctions of `self`; \ - the loop can push to the new multi-location at most one time; \ - thus the size of the new multi-location is at most N junctions; \ - qed"; - while let Some(j) = iter.next() { - if j == &Junction::Parent { - match normalized.last() { - None | Some(Junction::Parent) => {}, - Some(_) => { - normalized.take_last(); - continue - }, - } - } - - normalized.push(j.clone()).expect(EXPECT_MESSAGE); - } - - core::mem::swap(self, &mut normalized); - } - - /// Mutate `self` so that it is suffixed with `suffix`. The correct normalized form is returned, - /// removing any internal `[Non-Parent, Parent]` combinations. - /// - /// In the case of overflow, `self` is unmodified and we return `Err` with `suffix`. - /// - /// # Example - /// ```rust - /// # use xcm::latest::{MultiLocation::*, Junction::*}; - /// # fn main() { - /// let mut m = X3(Parent, Parachain(21), OnlyChild); - /// assert_eq!(m.append_with(X2(Parent, PalletInstance(3))), Ok(())); - /// assert_eq!(m, X3(Parent, Parachain(21), PalletInstance(3))); - /// # } - /// ``` - pub fn append_with(&mut self, suffix: MultiLocation) -> Result<(), MultiLocation> { - let mut prefix = suffix; - core::mem::swap(self, &mut prefix); - match self.prepend_with(prefix) { - Ok(()) => Ok(()), - Err(prefix) => { - let mut suffix = prefix; - core::mem::swap(self, &mut suffix); - Err(suffix) - }, - } - } - - /// Mutate `self` so that it is prefixed with `prefix`. The correct normalized form is returned, - /// removing any internal [Non-Parent, `Parent`] combinations. - /// - /// In the case of overflow, `self` is unmodified and we return `Err` with `prefix`. - /// - /// # Example - /// ```rust - /// # use xcm::latest::{MultiLocation::*, Junction::*, NetworkId::Any}; - /// # fn main() { - /// let mut m = X3(Parent, Parent, PalletInstance(3)); - /// assert_eq!(m.prepend_with(X3(Parent, Parachain(21), OnlyChild)), Ok(())); - /// assert_eq!(m, X2(Parent, PalletInstance(3))); - /// # } - /// ``` - pub fn prepend_with(&mut self, prefix: MultiLocation) -> Result<(), MultiLocation> { - let mut prefix = prefix; - - // This will guarantee that all `Parent` junctions in the prefix are leading, which is - // important for calculating the `skipped` items below. - prefix.canonicalize(); - - let self_leading_parents = self.leading_parent_count(); - // These are the number of `non-parent` items in the prefix that we can - // potentially remove if the original location leads with parents. - let prefix_rest = prefix.len() - prefix.leading_parent_count(); - // 2 * skipped items will be removed when performing the normalization below. - let skipped = self_leading_parents.min(prefix_rest); - - // Pre-pending this prefix would create a multi-location with too many junctions. - if self.len() + prefix.len() - 2 * skipped > MAX_MULTILOCATION_LENGTH { - return Err(prefix) - } - - // Here we cancel out `[Non-Parent, Parent]` items (normalization), where - // the non-parent item comes from the end of the prefix, and the parent item - // comes from the front of the original location. - // - // We calculated already how many of these there should be above. - for _ in 0..skipped { - let _non_parent = prefix.take_last(); - let _parent = self.take_first(); - debug_assert!( - _non_parent.is_some() && _non_parent != Some(Junction::Parent), - "prepend_with should always remove a non-parent from the end of the prefix", - ); - debug_assert!( - _parent == Some(Junction::Parent), - "prepend_with should always remove a parent from the front of the location", - ); - } - - for j in prefix.into_iter_rev() { - self.push_front(j) - .expect("len + prefix minus 2*skipped is less than max length; qed"); +impl TryFrom for Junctions { + type Error = (); + fn try_from(x: MultiLocation) -> result::Result { + if x.parents > 0 { + Err(()) + } else { + Ok(x.interior) } - Ok(()) - } - - /// Returns true iff `self` is an interior location. For this it may not contain any `Junction`s - /// for which `Junction::is_interior` returns `false`. This is generally true, except for the - /// `Parent` item. - /// - /// # Example - /// ```rust - /// # use xcm::latest::{MultiLocation::*, Junction::*, NetworkId::Any}; - /// # fn main() { - /// let parent = X1(Parent); - /// assert_eq!(parent.is_interior(), false); - /// let m = X2(PalletInstance(12), AccountIndex64 { network: Any, index: 23 }); - /// assert_eq!(m.is_interior(), true); - /// # } - /// ``` - pub fn is_interior(&self) -> bool { - self.iter().all(Junction::is_interior) } } -impl From for MultiLocation { - fn from(old: MultiLocation0) -> Self { - use MultiLocation::*; +impl TryFrom for MultiLocation { + type Error = (); + fn try_from(old: MultiLocation0) -> result::Result { + use Junctions::*; match old { - MultiLocation0::Null => Here, - MultiLocation0::X1(j0) => X1(j0), - MultiLocation0::X2(j0, j1) => X2(j0, j1), - MultiLocation0::X3(j0, j1, j2) => X3(j0, j1, j2), - MultiLocation0::X4(j0, j1, j2, j3) => X4(j0, j1, j2, j3), - MultiLocation0::X5(j0, j1, j2, j3, j4) => X5(j0, j1, j2, j3, j4), - MultiLocation0::X6(j0, j1, j2, j3, j4, j5) => X6(j0, j1, j2, j3, j4, j5), - MultiLocation0::X7(j0, j1, j2, j3, j4, j5, j6) => X7(j0, j1, j2, j3, j4, j5, j6), - MultiLocation0::X8(j0, j1, j2, j3, j4, j5, j6, j7) => - X8(j0, j1, j2, j3, j4, j5, j6, j7), + MultiLocation0::Null => Ok(Here.into()), + MultiLocation0::X1(j0) if j0.is_parent() => Ok(Parent.into()), + MultiLocation0::X1(j0) => Ok(X1(j0.try_into()?).into()), + MultiLocation0::X2(j0, j1) if j0.is_parent() && j1.is_parent() => + Ok(MultiLocation::grandparent()), + MultiLocation0::X2(j0, j1) if j0.is_parent() => + Ok(MultiLocation { parents: 1, interior: X1(j1.try_into()?) }), + MultiLocation0::X2(j0, j1) => Ok(X2(j0.try_into()?, j1.try_into()?).into()), + MultiLocation0::X3(j0, j1, j2) + if j0.is_parent() && j1.is_parent() && j2.is_parent() => + Ok(MultiLocation::ancestor(3)), + MultiLocation0::X3(j0, j1, j2) if j0.is_parent() && j1.is_parent() => + Ok(MultiLocation { parents: 2, interior: X1(j2.try_into()?) }), + MultiLocation0::X3(j0, j1, j2) if j0.is_parent() => + Ok(MultiLocation { parents: 1, interior: X2(j1.try_into()?, j2.try_into()?) }), + MultiLocation0::X3(j0, j1, j2) => + Ok(X3(j0.try_into()?, j1.try_into()?, j2.try_into()?).into()), + MultiLocation0::X4(j0, j1, j2, j3) + if j0.is_parent() && j1.is_parent() && j2.is_parent() && j3.is_parent() => + Ok(MultiLocation::ancestor(4)), + MultiLocation0::X4(j0, j1, j2, j3) + if j0.is_parent() && j1.is_parent() && j2.is_parent() => + Ok(MultiLocation { parents: 3, interior: X1(j3.try_into()?) }), + MultiLocation0::X4(j0, j1, j2, j3) if j0.is_parent() && j1.is_parent() => + Ok(MultiLocation { parents: 2, interior: X2(j2.try_into()?, j3.try_into()?) }), + MultiLocation0::X4(j0, j1, j2, j3) if j0.is_parent() => Ok(MultiLocation { + parents: 1, + interior: X3(j1.try_into()?, j2.try_into()?, j3.try_into()?), + }), + MultiLocation0::X4(j0, j1, j2, j3) => + Ok(X4(j0.try_into()?, j1.try_into()?, j2.try_into()?, j3.try_into()?).into()), + MultiLocation0::X5(j0, j1, j2, j3, j4) + if j0.is_parent() && + j1.is_parent() && j2.is_parent() && + j3.is_parent() && j4.is_parent() => + Ok(MultiLocation::ancestor(5)), + MultiLocation0::X5(j0, j1, j2, j3, j4) + if j0.is_parent() && j1.is_parent() && j2.is_parent() && j3.is_parent() => + Ok(MultiLocation { parents: 4, interior: X1(j4.try_into()?) }), + MultiLocation0::X5(j0, j1, j2, j3, j4) + if j0.is_parent() && j1.is_parent() && j2.is_parent() => + Ok(MultiLocation { parents: 3, interior: X2(j3.try_into()?, j4.try_into()?) }), + MultiLocation0::X5(j0, j1, j2, j3, j4) if j0.is_parent() && j1.is_parent() => + Ok(MultiLocation { + parents: 2, + interior: X3(j2.try_into()?, j3.try_into()?, j4.try_into()?), + }), + MultiLocation0::X5(j0, j1, j2, j3, j4) if j0.is_parent() => Ok(MultiLocation { + parents: 1, + interior: X4(j1.try_into()?, j2.try_into()?, j3.try_into()?, j4.try_into()?), + }), + MultiLocation0::X5(j0, j1, j2, j3, j4) => Ok(X5( + j0.try_into()?, + j1.try_into()?, + j2.try_into()?, + j3.try_into()?, + j4.try_into()?, + ) + .into()), + MultiLocation0::X6(j0, j1, j2, j3, j4, j5) + if j0.is_parent() && + j1.is_parent() && j2.is_parent() && + j3.is_parent() && j4.is_parent() && + j5.is_parent() => + Ok(MultiLocation::ancestor(6)), + MultiLocation0::X6(j0, j1, j2, j3, j4, j5) + if j0.is_parent() && + j1.is_parent() && j2.is_parent() && + j3.is_parent() && j4.is_parent() => + Ok(MultiLocation { parents: 5, interior: X1(j5.try_into()?) }), + MultiLocation0::X6(j0, j1, j2, j3, j4, j5) + if j0.is_parent() && j1.is_parent() && j2.is_parent() && j3.is_parent() => + Ok(MultiLocation { parents: 4, interior: X2(j4.try_into()?, j5.try_into()?) }), + MultiLocation0::X6(j0, j1, j2, j3, j4, j5) + if j0.is_parent() && j1.is_parent() && j2.is_parent() => + Ok(MultiLocation { + parents: 3, + interior: X3(j3.try_into()?, j4.try_into()?, j5.try_into()?), + }), + MultiLocation0::X6(j0, j1, j2, j3, j4, j5) if j0.is_parent() && j1.is_parent() => + Ok(MultiLocation { + parents: 2, + interior: X4(j2.try_into()?, j3.try_into()?, j4.try_into()?, j5.try_into()?), + }), + MultiLocation0::X6(j0, j1, j2, j3, j4, j5) if j0.is_parent() => Ok(MultiLocation { + parents: 1, + interior: X5( + j1.try_into()?, + j2.try_into()?, + j3.try_into()?, + j4.try_into()?, + j5.try_into()?, + ), + }), + MultiLocation0::X6(j0, j1, j2, j3, j4, j5) => Ok(X6( + j0.try_into()?, + j1.try_into()?, + j2.try_into()?, + j3.try_into()?, + j4.try_into()?, + j5.try_into()?, + ) + .into()), + MultiLocation0::X7(j0, j1, j2, j3, j4, j5, j6) + if j0.is_parent() && + j1.is_parent() && j2.is_parent() && + j3.is_parent() && j4.is_parent() && + j5.is_parent() && j6.is_parent() => + Ok(MultiLocation::ancestor(7)), + MultiLocation0::X7(j0, j1, j2, j3, j4, j5, j6) + if j0.is_parent() && + j1.is_parent() && j2.is_parent() && + j3.is_parent() && j4.is_parent() && + j5.is_parent() => + Ok(MultiLocation { parents: 6, interior: X1(j6.try_into()?) }), + MultiLocation0::X7(j0, j1, j2, j3, j4, j5, j6) + if j0.is_parent() && + j1.is_parent() && j2.is_parent() && + j3.is_parent() && j4.is_parent() => + Ok(MultiLocation { parents: 5, interior: X2(j5.try_into()?, j6.try_into()?) }), + MultiLocation0::X7(j0, j1, j2, j3, j4, j5, j6) + if j0.is_parent() && j1.is_parent() && j2.is_parent() && j3.is_parent() => + Ok(MultiLocation { + parents: 4, + interior: X3(j4.try_into()?, j5.try_into()?, j6.try_into()?), + }), + MultiLocation0::X7(j0, j1, j2, j3, j4, j5, j6) + if j0.is_parent() && j1.is_parent() && j2.is_parent() => + Ok(MultiLocation { + parents: 3, + interior: X4(j3.try_into()?, j4.try_into()?, j5.try_into()?, j6.try_into()?), + }), + MultiLocation0::X7(j0, j1, j2, j3, j4, j5, j6) if j0.is_parent() && j1.is_parent() => + Ok(MultiLocation { + parents: 2, + interior: X5( + j2.try_into()?, + j3.try_into()?, + j4.try_into()?, + j5.try_into()?, + j6.try_into()?, + ), + }), + MultiLocation0::X7(j0, j1, j2, j3, j4, j5, j6) if j0.is_parent() => Ok(MultiLocation { + parents: 1, + interior: X6( + j1.try_into()?, + j2.try_into()?, + j3.try_into()?, + j4.try_into()?, + j5.try_into()?, + j6.try_into()?, + ), + }), + MultiLocation0::X7(j0, j1, j2, j3, j4, j5, j6) => Ok(X7( + j0.try_into()?, + j1.try_into()?, + j2.try_into()?, + j3.try_into()?, + j4.try_into()?, + j5.try_into()?, + j6.try_into()?, + ) + .into()), + MultiLocation0::X8(j0, j1, j2, j3, j4, j5, j6, j7) + if j0.is_parent() && + j1.is_parent() && j2.is_parent() && + j3.is_parent() && j4.is_parent() && + j5.is_parent() && j6.is_parent() && + j7.is_parent() => + Ok(MultiLocation::ancestor(8)), + MultiLocation0::X8(j0, j1, j2, j3, j4, j5, j6, j7) + if j0.is_parent() && + j1.is_parent() && j2.is_parent() && + j3.is_parent() && j4.is_parent() && + j5.is_parent() && j6.is_parent() => + Ok(MultiLocation { parents: 7, interior: X1(j7.try_into()?) }), + MultiLocation0::X8(j0, j1, j2, j3, j4, j5, j6, j7) + if j0.is_parent() && + j1.is_parent() && j2.is_parent() && + j3.is_parent() && j4.is_parent() && + j5.is_parent() => + Ok(MultiLocation { parents: 6, interior: X2(j6.try_into()?, j7.try_into()?) }), + MultiLocation0::X8(j0, j1, j2, j3, j4, j5, j6, j7) + if j0.is_parent() && + j1.is_parent() && j2.is_parent() && + j3.is_parent() && j4.is_parent() => + Ok(MultiLocation { + parents: 5, + interior: X3(j5.try_into()?, j6.try_into()?, j7.try_into()?), + }), + MultiLocation0::X8(j0, j1, j2, j3, j4, j5, j6, j7) + if j0.is_parent() && j1.is_parent() && j2.is_parent() && j3.is_parent() => + Ok(MultiLocation { + parents: 4, + interior: X4(j4.try_into()?, j5.try_into()?, j6.try_into()?, j7.try_into()?), + }), + MultiLocation0::X8(j0, j1, j2, j3, j4, j5, j6, j7) + if j0.is_parent() && j1.is_parent() && j2.is_parent() => + Ok(MultiLocation { + parents: 3, + interior: X5( + j3.try_into()?, + j4.try_into()?, + j5.try_into()?, + j6.try_into()?, + j7.try_into()?, + ), + }), + MultiLocation0::X8(j0, j1, j2, j3, j4, j5, j6, j7) + if j0.is_parent() && j1.is_parent() => + Ok(MultiLocation { + parents: 2, + interior: X6( + j2.try_into()?, + j3.try_into()?, + j4.try_into()?, + j5.try_into()?, + j6.try_into()?, + j7.try_into()?, + ), + }), + MultiLocation0::X8(j0, j1, j2, j3, j4, j5, j6, j7) if j0.is_parent() => + Ok(MultiLocation { + parents: 1, + interior: X7( + j1.try_into()?, + j2.try_into()?, + j3.try_into()?, + j4.try_into()?, + j5.try_into()?, + j6.try_into()?, + j7.try_into()?, + ), + }), + MultiLocation0::X8(j0, j1, j2, j3, j4, j5, j6, j7) => Ok(X8( + j0.try_into()?, + j1.try_into()?, + j2.try_into()?, + j3.try_into()?, + j4.try_into()?, + j5.try_into()?, + j6.try_into()?, + j7.try_into()?, + ) + .into()), } } } #[cfg(test)] mod tests { - use super::MultiLocation::*; + use super::{Junctions::*, MultiLocation}; use crate::opaque::v1::{Junction::*, NetworkId::Any}; + use parity_scale_codec::{Decode, Encode}; + + #[test] + fn encode_and_decode_works() { + let m = MultiLocation { + parents: 1, + interior: X2(Parachain(42), AccountIndex64 { network: Any, index: 23 }), + }; + let encoded = m.encode(); + assert_eq!(encoded, [1, 2, 0, 168, 2, 0, 92].to_vec()); + let decoded = MultiLocation::decode(&mut &encoded[..]); + assert_eq!(decoded, Ok(m)); + } #[test] fn match_and_split_works() { - let m = X3(Parent, Parachain(42), AccountIndex64 { network: Any, index: 23 }); - assert_eq!(m.match_and_split(&X1(Parent)), None); + let m = MultiLocation { + parents: 1, + interior: X2(Parachain(42), AccountIndex64 { network: Any, index: 23 }), + }; + assert_eq!(m.match_and_split(&MultiLocation { parents: 1, interior: Here }), None); assert_eq!( - m.match_and_split(&X2(Parent, Parachain(42))), + m.match_and_split(&MultiLocation { parents: 1, interior: X1(Parachain(42)) }), Some(&AccountIndex64 { network: Any, index: 23 }) ); assert_eq!(m.match_and_split(&m), None); @@ -732,90 +1244,79 @@ mod tests { #[test] fn append_with_works() { let acc = AccountIndex64 { network: Any, index: 23 }; - let mut m = X2(Parent, Parachain(42)); - assert_eq!(m.append_with(X2(PalletInstance(3), acc.clone())), Ok(())); - assert_eq!(m, X4(Parent, Parachain(42), PalletInstance(3), acc.clone())); + let mut m = MultiLocation { parents: 1, interior: X1(Parachain(42)) }; + assert_eq!(m.append_with(MultiLocation::from(X2(PalletInstance(3), acc.clone()))), Ok(())); + assert_eq!( + m, + MultiLocation { + parents: 1, + interior: X3(Parachain(42), PalletInstance(3), acc.clone()) + } + ); // cannot append to create overly long multilocation let acc = AccountIndex64 { network: Any, index: 23 }; - let mut m = X7(Parent, Parent, Parent, Parent, Parent, Parent, Parachain(42)); - let suffix = X2(PalletInstance(3), acc.clone()); + let mut m = MultiLocation { + parents: 254, + interior: X5(Parachain(42), OnlyChild, OnlyChild, OnlyChild, OnlyChild), + }; + let suffix = MultiLocation::from(X4(PalletInstance(3), acc.clone(), OnlyChild, OnlyChild)); assert_eq!(m.append_with(suffix.clone()), Err(suffix)); } #[test] fn prepend_with_works() { - let mut m = X3(Parent, Parachain(42), AccountIndex64 { network: Any, index: 23 }); - assert_eq!(m.prepend_with(X2(Parent, OnlyChild)), Ok(())); - assert_eq!(m, X3(Parent, Parachain(42), AccountIndex64 { network: Any, index: 23 })); - - // cannot prepend to create overly long multilocation - let mut m = X7(Parent, Parent, Parent, Parent, Parent, Parent, Parachain(42)); - let prefix = X2(Parent, Parent); - assert_eq!(m.prepend_with(prefix.clone()), Err(prefix)); - - // Can handle shared prefix and resizing correctly. - let mut m = X1(Parent); - let prefix = X8( - Parachain(100), - OnlyChild, - OnlyChild, - OnlyChild, - OnlyChild, - OnlyChild, - OnlyChild, - Parent, + let mut m = MultiLocation { + parents: 1, + interior: X2(Parachain(42), AccountIndex64 { network: Any, index: 23 }), + }; + assert_eq!(m.prepend_with(MultiLocation { parents: 1, interior: X1(OnlyChild) }), Ok(())); + assert_eq!( + m, + MultiLocation { + parents: 1, + interior: X2(Parachain(42), AccountIndex64 { network: Any, index: 23 }) + } ); - assert_eq!(m.prepend_with(prefix.clone()), Ok(())); - assert_eq!(m, X5(Parachain(100), OnlyChild, OnlyChild, OnlyChild, OnlyChild)); - let mut m = X1(Parent); - let prefix = X8(Parent, Parent, Parent, Parent, Parent, Parent, Parent, Parent); + // cannot prepend to create overly long multilocation + let mut m = MultiLocation { parents: 254, interior: X1(Parachain(42)) }; + let prefix = MultiLocation { parents: 2, interior: Here }; assert_eq!(m.prepend_with(prefix.clone()), Err(prefix)); - let mut m = X1(Parent); - let prefix = X7(Parent, Parent, Parent, Parent, Parent, Parent, Parent); - assert_eq!(m.prepend_with(prefix.clone()), Ok(())); - assert_eq!(m, X8(Parent, Parent, Parent, Parent, Parent, Parent, Parent, Parent)); - - let mut m = X1(Parent); - let prefix = X8(Parent, Parent, Parent, Parent, OnlyChild, Parent, Parent, Parent); - assert_eq!(m.prepend_with(prefix.clone()), Ok(())); - assert_eq!(m, X7(Parent, Parent, Parent, Parent, Parent, Parent, Parent)); + let prefix = MultiLocation { parents: 1, interior: Here }; + assert_eq!(m.prepend_with(prefix), Ok(())); + assert_eq!(m, MultiLocation { parents: 255, interior: X1(Parachain(42)) }); } #[test] - fn canonicalize_works() { - let mut m = X1(Parent); - m.canonicalize(); - assert_eq!(m, X1(Parent)); - - let mut m = X1(Parachain(1)); - m.canonicalize(); - assert_eq!(m, X1(Parachain(1))); - - let mut m = X6(Parent, Parachain(1), Parent, Parachain(2), Parent, Parachain(3)); - m.canonicalize(); - assert_eq!(m, X2(Parent, Parachain(3))); - - let mut m = X5(Parachain(1), Parent, Parachain(2), Parent, Parachain(3)); - m.canonicalize(); - assert_eq!(m, X1(Parachain(3))); - - let mut m = X6(Parachain(1), Parent, Parachain(2), Parent, Parachain(3), Parent); - m.canonicalize(); - assert_eq!(m, Here); - - let mut m = X5(Parachain(1), Parent, Parent, Parent, Parachain(3)); - m.canonicalize(); - assert_eq!(m, X3(Parent, Parent, Parachain(3))); - - let mut m = X4(Parachain(1), Parachain(2), Parent, Parent); - m.canonicalize(); - assert_eq!(m, Here); - - let mut m = X4(Parent, Parent, Parachain(1), Parachain(2)); - m.canonicalize(); - assert_eq!(m, X4(Parent, Parent, Parachain(1), Parachain(2))); + fn double_ended_ref_iteration_works() { + let m = X3(Parachain(1000), Parachain(3), PalletInstance(5)); + let mut iter = m.iter(); + + let first = iter.next().unwrap(); + assert_eq!(first, &Parachain(1000)); + let third = iter.next_back().unwrap(); + assert_eq!(third, &PalletInstance(5)); + let second = iter.next_back().unwrap(); + assert_eq!(iter.next(), None); + assert_eq!(iter.next_back(), None); + assert_eq!(second, &Parachain(3)); + + let res = Here + .pushed_with(first.clone()) + .unwrap() + .pushed_with(second.clone()) + .unwrap() + .pushed_with(third.clone()) + .unwrap(); + assert_eq!(m, res); + + // make sure there's no funny business with the 0 indexing + let m = Here; + let mut iter = m.iter(); + + assert_eq!(iter.next(), None); + assert_eq!(iter.next_back(), None); } } diff --git a/xcm/src/v1/order.rs b/xcm/src/v1/order.rs index 06363c39ce83..c29bff83c41b 100644 --- a/xcm/src/v1/order.rs +++ b/xcm/src/v1/order.rs @@ -194,12 +194,15 @@ impl TryFrom> for Order { use Order::*; Ok(match old { Order0::Null => Noop, - Order0::DepositAsset { assets, dest } => - DepositAsset { assets: assets.try_into()?, max_assets: 1, beneficiary: dest.into() }, + Order0::DepositAsset { assets, dest } => DepositAsset { + assets: assets.try_into()?, + max_assets: 1, + beneficiary: dest.try_into()?, + }, Order0::DepositReserveAsset { assets, dest, effects } => DepositReserveAsset { assets: assets.try_into()?, max_assets: 1, - dest: dest.into(), + dest: dest.try_into()?, effects: effects .into_iter() .map(Order::<()>::try_from) @@ -210,7 +213,7 @@ impl TryFrom> for Order { Order0::InitiateReserveWithdraw { assets, reserve, effects } => InitiateReserveWithdraw { assets: assets.try_into()?, - reserve: reserve.into(), + reserve: reserve.try_into()?, effects: effects .into_iter() .map(Order::<()>::try_from) @@ -218,14 +221,14 @@ impl TryFrom> for Order { }, Order0::InitiateTeleport { assets, dest, effects } => InitiateTeleport { assets: assets.try_into()?, - dest: dest.into(), + dest: dest.try_into()?, effects: effects .into_iter() .map(Order::<()>::try_from) .collect::>()?, }, Order0::QueryHolding { query_id, dest, assets } => - QueryHolding { query_id, dest: dest.into(), assets: assets.try_into()? }, + QueryHolding { query_id, dest: dest.try_into()?, assets: assets.try_into()? }, Order0::BuyExecution { fees, weight, debt, halt_on_error, xcm } => { let instructions = xcm.into_iter().map(Xcm::::try_from).collect::>()?; diff --git a/xcm/src/v1/traits.rs b/xcm/src/v1/traits.rs index a029d2cc64ee..419c6ec43416 100644 --- a/xcm/src/v1/traits.rs +++ b/xcm/src/v1/traits.rs @@ -188,7 +188,7 @@ impl ExecuteXcm for () { /// /// # Example /// ```rust -/// # use xcm::v1::{MultiLocation, Xcm, Junction, Error, OriginKind, SendXcm, Result}; +/// # use xcm::v1::{MultiLocation, Xcm, Junction, Junctions, Error, OriginKind, SendXcm, Result, Parent}; /// # use parity_scale_codec::Encode; /// /// /// A sender that only passes the message through and does nothing. @@ -203,7 +203,9 @@ impl ExecuteXcm for () { /// struct Sender2; /// impl SendXcm for Sender2 { /// fn send_xcm(destination: MultiLocation, message: Xcm<()>) -> Result { -/// if let MultiLocation::X2(j1, j2) = destination { +/// if matches!(destination.interior(), Junctions::X2(j1, j2)) +/// && destination.parent_count() == 0 +/// { /// Ok(()) /// } else { /// Err(Error::Undefined) @@ -215,9 +217,12 @@ impl ExecuteXcm for () { /// struct Sender3; /// impl SendXcm for Sender3 { /// fn send_xcm(destination: MultiLocation, message: Xcm<()>) -> Result { -/// match destination { -/// MultiLocation::X1(j) if j == Junction::Parent => Ok(()), -/// _ => Err(Error::CannotReachDestination(destination, message)), +/// if matches!(destination.interior(), Junctions::Here) +/// && destination.parent_count() == 1 +/// { +/// Ok(()) +/// } else { +/// Err(Error::CannotReachDestination(destination, message)) /// } /// } /// } @@ -226,7 +231,7 @@ impl ExecuteXcm for () { /// # fn main() { /// let call: Vec = ().encode(); /// let message = Xcm::Transact { origin_type: OriginKind::Superuser, require_weight_at_most: 0, call: call.into() }; -/// let destination = MultiLocation::X1(Junction::Parent); +/// let destination: MultiLocation = Parent.into(); /// /// assert!( /// // Sender2 will block this. diff --git a/xcm/xcm-builder/src/barriers.rs b/xcm/xcm-builder/src/barriers.rs index 3e412af629da..fc58c2bd21f3 100644 --- a/xcm/xcm-builder/src/barriers.rs +++ b/xcm/xcm-builder/src/barriers.rs @@ -19,7 +19,7 @@ use frame_support::{ensure, traits::Contains, weights::Weight}; use polkadot_parachain::primitives::IsSystem; use sp_std::{marker::PhantomData, result::Result}; -use xcm::latest::{Junction, MultiLocation, Order, Xcm}; +use xcm::latest::{Junction, Junctions, MultiLocation, Order, Xcm}; use xcm_executor::traits::{OnResponse, ShouldExecute}; /// Execution barrier that just takes `shallow_weight` from `weight_credit`. @@ -84,7 +84,11 @@ impl> ShouldExecute for AllowUnpaidExecutionFrom { pub struct IsChildSystemParachain(PhantomData); impl> Contains for IsChildSystemParachain { fn contains(l: &MultiLocation) -> bool { - matches!(l, MultiLocation::X1(Junction::Parachain(id)) if ParaId::from(*id).is_system()) + matches!( + l.interior(), + Junctions::X1(Junction::Parachain(id)) + if ParaId::from(*id).is_system() && l.parent_count() == 0, + ) } } diff --git a/xcm/xcm-builder/src/currency_adapter.rs b/xcm/xcm-builder/src/currency_adapter.rs index 9742d035c78a..074ae91c244a 100644 --- a/xcm/xcm-builder/src/currency_adapter.rs +++ b/xcm/xcm-builder/src/currency_adapter.rs @@ -53,7 +53,7 @@ impl From for XcmError { /// # Example /// ``` /// use frame_support::parameter_types; -/// use xcm::latest::{MultiLocation, Junction}; +/// use xcm::latest::prelude::*; /// use xcm_builder::{ParentIsDefault, CurrencyAdapter, IsConcrete}; /// /// /// Our chain's account id. @@ -61,7 +61,7 @@ impl From for XcmError { /// /// /// Our relay chain's location. /// parameter_types! { -/// RelayChain: MultiLocation = MultiLocation::X1(Junction::Parent); +/// RelayChain: MultiLocation = Parent.into(); /// CheckingAccount: AccountId = Default::default(); /// } /// diff --git a/xcm/xcm-builder/src/fungibles_adapter.rs b/xcm/xcm-builder/src/fungibles_adapter.rs index d9f1e026ee0b..2107acdb4a36 100644 --- a/xcm/xcm-builder/src/fungibles_adapter.rs +++ b/xcm/xcm-builder/src/fungibles_adapter.rs @@ -38,18 +38,24 @@ impl, AssetId: Clone, ConvertAssetId: Convert) -> result::Result { let prefix = Prefix::get(); let id = id.borrow(); - if !prefix.iter().enumerate().all(|(index, item)| id.at(index) == Some(item)) { + if prefix.parent_count() != id.parent_count() || + prefix + .interior() + .iter() + .enumerate() + .any(|(index, junction)| id.interior().at(index) != Some(junction)) + { return Err(()) } - match id.at(prefix.len()) { - Some(Junction::GeneralIndex { id }) => ConvertAssetId::convert_ref(id), + match id.interior().at(prefix.interior().len()) { + Some(Junction::GeneralIndex(id)) => ConvertAssetId::convert_ref(id), _ => Err(()), } } fn reverse_ref(what: impl Borrow) -> result::Result { let mut location = Prefix::get(); let id = ConvertAssetId::reverse_ref(what)?; - location.push(Junction::GeneralIndex { id }).map_err(|_| ())?; + location.push_interior(Junction::GeneralIndex(id))?; Ok(location) } } diff --git a/xcm/xcm-builder/src/location_conversion.rs b/xcm/xcm-builder/src/location_conversion.rs index 5daaf11d4b81..b067d98b8ede 100644 --- a/xcm/xcm-builder/src/location_conversion.rs +++ b/xcm/xcm-builder/src/location_conversion.rs @@ -19,7 +19,7 @@ use parity_scale_codec::Encode; use sp_io::hashing::blake2_256; use sp_runtime::traits::AccountIdConversion; use sp_std::{borrow::Borrow, marker::PhantomData}; -use xcm::latest::{Junction, MultiLocation, NetworkId}; +use xcm::latest::{Junction::*, Junctions::*, MultiLocation, NetworkId, Parent}; use xcm_executor::traits::{Convert, InvertLocation}; pub struct Account32Hash(PhantomData<(Network, AccountId)>); @@ -42,7 +42,7 @@ impl Convert for ParentIsDefault { fn convert_ref(location: impl Borrow) -> Result { - if let &MultiLocation::X1(Junction::Parent) = location.borrow() { + if location.borrow().contains_parents_only(1) { Ok(AccountId::default()) } else { Err(()) @@ -51,7 +51,7 @@ impl Convert fn reverse_ref(who: impl Borrow) -> Result { if who.borrow() == &AccountId::default() { - Ok(Junction::Parent.into()) + Ok(Parent.into()) } else { Err(()) } @@ -63,16 +63,16 @@ impl + Into + AccountIdConversion, AccountId: Convert for ChildParachainConvertsVia { fn convert_ref(location: impl Borrow) -> Result { - if let &MultiLocation::X1(Junction::Parachain(id)) = location.borrow() { - Ok(ParaId::from(id).into_account()) - } else { - Err(()) + match location.borrow() { + MultiLocation { parents: 0, interior: X1(Parachain(id)) } => + Ok(ParaId::from(*id).into_account()), + _ => Err(()), } } fn reverse_ref(who: impl Borrow) -> Result { if let Some(id) = ParaId::try_from_account(who.borrow()) { - Ok(Junction::Parachain(id.into()).into()) + Ok(Parachain(id.into()).into()) } else { Err(()) } @@ -84,16 +84,16 @@ impl + Into + AccountIdConversion, AccountId: Convert for SiblingParachainConvertsVia { fn convert_ref(location: impl Borrow) -> Result { - if let &MultiLocation::X2(Junction::Parent, Junction::Parachain(id)) = location.borrow() { - Ok(ParaId::from(id).into_account()) - } else { - Err(()) + match location.borrow() { + MultiLocation { parents: 1, interior: X1(Parachain(id)) } => + Ok(ParaId::from(*id).into_account()), + _ => Err(()), } } fn reverse_ref(who: impl Borrow) -> Result { if let Some(id) = ParaId::try_from_account(who.borrow()) { - Ok([Junction::Parent, Junction::Parachain(id.into())].into()) + Ok(MultiLocation::new(1, X1(Parachain(id.into())))) } else { Err(()) } @@ -107,17 +107,20 @@ impl, AccountId: From<[u8; 32]> + Into<[u8; 32]> + Clone { fn convert(location: MultiLocation) -> Result { let id = match location { - MultiLocation::X1(Junction::AccountId32 { id, network: NetworkId::Any }) => id, - MultiLocation::X1(Junction::AccountId32 { id, network }) - if &network == &Network::get() => + MultiLocation { + parents: 0, + interior: X1(AccountId32 { id, network: NetworkId::Any }), + } => id, + MultiLocation { parents: 0, interior: X1(AccountId32 { id, network }) } + if network == Network::get() => id, - l => return Err(l), + _ => return Err(location), }; Ok(id.into()) } fn reverse(who: AccountId) -> Result { - Ok(Junction::AccountId32 { id: who.into(), network: Network::get() }.into()) + Ok(AccountId32 { id: who.into(), network: Network::get() }.into()) } } @@ -127,17 +130,20 @@ impl, AccountId: From<[u8; 20]> + Into<[u8; 20]> + Clone { fn convert(location: MultiLocation) -> Result { let key = match location { - MultiLocation::X1(Junction::AccountKey20 { key, network: NetworkId::Any }) => key, - MultiLocation::X1(Junction::AccountKey20 { key, network }) - if &network == &Network::get() => + MultiLocation { + parents: 0, + interior: X1(AccountKey20 { key, network: NetworkId::Any }), + } => key, + MultiLocation { parents: 0, interior: X1(AccountKey20 { key, network }) } + if network == Network::get() => key, - l => return Err(l), + _ => return Err(location), }; Ok(key.into()) } fn reverse(who: AccountId) -> Result { - let j = Junction::AccountKey20 { key: who.into(), network: Network::get() }; + let j = AccountKey20 { key: who.into(), network: Network::get() }; Ok(j.into()) } } @@ -155,7 +161,7 @@ impl, AccountId: From<[u8; 20]> + Into<[u8; 20]> + Clone /// ``` /// ```rust /// # use frame_support::parameter_types; -/// # use xcm::latest::{MultiLocation::{self, *}, Junction::*, NetworkId::Any}; +/// # use xcm::latest::{MultiLocation, Junction::*, Junctions::{self, *}, NetworkId::Any}; /// # use xcm_builder::LocationInverter; /// # use xcm_executor::traits::InvertLocation; /// # fn main() { @@ -163,16 +169,14 @@ impl, AccountId: From<[u8; 20]> + Into<[u8; 20]> + Clone /// pub Ancestry: MultiLocation = X2( /// Parachain(1), /// AccountKey20 { network: Any, key: Default::default() }, -/// ); +/// ).into(); /// } /// -/// let input = X4(Parent, Parent, Parachain(2), AccountId32 { network: Any, id: Default::default() }); +/// let input = MultiLocation::new(2, X2(Parachain(2), AccountId32 { network: Any, id: Default::default() })); /// let inverted = LocationInverter::::invert_location(&input); -/// assert_eq!(inverted, X4( -/// Parent, -/// Parent, -/// Parachain(1), -/// AccountKey20 { network: Any, key: Default::default() }, +/// assert_eq!(inverted, MultiLocation::new( +/// 2, +/// X2(Parachain(1), AccountKey20 { network: Any, key: Default::default() }), /// )); /// # } /// ``` @@ -180,18 +184,14 @@ pub struct LocationInverter(PhantomData); impl> InvertLocation for LocationInverter { fn invert_location(location: &MultiLocation) -> MultiLocation { let mut ancestry = Ancestry::get(); - let mut result = location.clone(); - for (i, j) in location - .iter_rev() - .map(|j| match j { - Junction::Parent => ancestry.take_first().unwrap_or(Junction::OnlyChild), - _ => Junction::Parent, - }) - .enumerate() - { - *result.at_mut(i).expect("location and result begin equal; same size; qed") = j; + let mut junctions = Here; + for _ in 0..location.parent_count() { + junctions = junctions + .pushed_with(ancestry.take_first_interior().unwrap_or(OnlyChild)) + .expect("ancestry is well-formed and has less than 8 non-parent junctions; qed"); } - result + let parents = location.interior().len() as u8; + MultiLocation::new(parents, junctions) } } @@ -200,7 +200,7 @@ mod tests { use super::*; use frame_support::parameter_types; - use xcm::latest::{Junction::*, MultiLocation::*, NetworkId::Any}; + use xcm::latest::{Junction, NetworkId::Any}; fn account20() -> Junction { AccountKey20 { network: Any, key: Default::default() } @@ -225,12 +225,12 @@ mod tests { #[test] fn inverter_works_in_tree() { parameter_types! { - pub Ancestry: MultiLocation = X3(Parachain(1), account20(), account20()); + pub Ancestry: MultiLocation = X3(Parachain(1), account20(), account20()).into(); } - let input = X5(Parent, Parent, Parent, Parachain(2), account32()); + let input = MultiLocation::new(3, X2(Parachain(2), account32())); let inverted = LocationInverter::::invert_location(&input); - assert_eq!(inverted, X5(Parent, Parent, Parachain(1), account20(), account20())); + assert_eq!(inverted, MultiLocation::new(2, X3(Parachain(1), account20(), account20()))); } // Network Topology @@ -240,12 +240,12 @@ mod tests { #[test] fn inverter_uses_ancestry_as_inverted_location() { parameter_types! { - pub Ancestry: MultiLocation = X2(account20(), account20()); + pub Ancestry: MultiLocation = X2(account20(), account20()).into(); } - let input = X2(Parent, Parent); + let input = MultiLocation::grandparent(); let inverted = LocationInverter::::invert_location(&input); - assert_eq!(inverted, X2(account20(), account20())); + assert_eq!(inverted, X2(account20(), account20()).into()); } // Network Topology @@ -255,11 +255,11 @@ mod tests { #[test] fn inverter_uses_only_child_on_missing_ancestry() { parameter_types! { - pub Ancestry: MultiLocation = X1(PalletInstance(5)); + pub Ancestry: MultiLocation = X1(PalletInstance(5)).into(); } - let input = X2(Parent, Parent); + let input = MultiLocation::grandparent(); let inverted = LocationInverter::::invert_location(&input); - assert_eq!(inverted, X2(PalletInstance(5), OnlyChild)); + assert_eq!(inverted, X2(PalletInstance(5), OnlyChild).into()); } } diff --git a/xcm/xcm-builder/src/matches_fungible.rs b/xcm/xcm-builder/src/matches_fungible.rs index f1e619c97068..6c33e18fe97c 100644 --- a/xcm/xcm-builder/src/matches_fungible.rs +++ b/xcm/xcm-builder/src/matches_fungible.rs @@ -32,16 +32,16 @@ use xcm_executor::traits::MatchesFungible; /// # Example /// /// ``` -/// use xcm::latest::prelude::*; +/// use xcm::latest::{MultiLocation, Parent}; /// use xcm_builder::IsConcrete; /// use xcm_executor::traits::MatchesFungible; /// /// frame_support::parameter_types! { -/// pub TargetLocation: MultiLocation = X1(Parent); +/// pub TargetLocation: MultiLocation = Parent.into(); /// } /// /// # fn main() { -/// let asset = (X1(Parent), 999).into(); +/// let asset = (Parent, 999).into(); /// // match `asset` if it is a concrete asset in `TargetLocation`. /// assert_eq!( as MatchesFungible>::matches_fungible(&asset), Some(999)); /// # } diff --git a/xcm/xcm-builder/src/mock.rs b/xcm/xcm-builder/src/mock.rs index 21835dd39b1e..7c1e93a2b9dd 100644 --- a/xcm/xcm-builder/src/mock.rs +++ b/xcm/xcm-builder/src/mock.rs @@ -146,16 +146,16 @@ impl TransactAsset for TestAssetTransactor { pub fn to_account(l: MultiLocation) -> Result { Ok(match l { // Siblings at 2000+id - X2(Parent, Parachain(id)) => 2000 + id as u64, + MultiLocation { parents: 1, interior: X1(Parachain(id)) } => 2000 + id as u64, // Accounts are their number - X1(AccountIndex64 { index, .. }) => index, + MultiLocation { parents: 0, interior: X1(AccountIndex64 { index, .. }) } => index, // Children at 1000+id - X1(Parachain(id)) => 1000 + id as u64, + MultiLocation { parents: 0, interior: X1(Parachain(id)) } => 1000 + id as u64, // Self at 3000 - Here => 3000, + MultiLocation { parents: 0, interior: Here } => 3000, // Parent at 3001 - X1(Parent) => 3001, - l => return Err(l), + MultiLocation { parents: 1, interior: Here } => 3001, + _ => return Err(l), }) } @@ -169,9 +169,11 @@ impl ConvertOrigin for TestOriginConverter { match (kind, origin) { (Superuser, _) => Ok(TestOrigin::Root), (SovereignAccount, l) => Ok(TestOrigin::Signed(to_account(l)?)), - (Native, X1(Parachain(id))) => Ok(TestOrigin::Parachain(id)), - (Native, X1(Parent)) => Ok(TestOrigin::Relay), - (Native, X1(AccountIndex64 { index, .. })) => Ok(TestOrigin::Signed(index)), + (Native, MultiLocation { parents: 0, interior: X1(Parachain(id)) }) => + Ok(TestOrigin::Parachain(id)), + (Native, MultiLocation { parents: 1, interior: Here }) => Ok(TestOrigin::Relay), + (Native, MultiLocation { parents: 0, interior: X1(AccountIndex64 { index, .. }) }) => + Ok(TestOrigin::Signed(index)), (_, origin) => Err(origin), } } @@ -247,7 +249,7 @@ pub fn response(query_id: u64) -> Option { } parameter_types! { - pub TestAncestry: MultiLocation = X1(Parachain(42)); + pub TestAncestry: MultiLocation = X1(Parachain(42)).into(); pub UnitWeightCost: Weight = 10; } parameter_types! { @@ -255,7 +257,7 @@ parameter_types! { pub static AllowUnpaidFrom: Vec = vec![]; pub static AllowPaidFrom: Vec = vec![]; // 1_000_000_000_000 => 1 unit of asset for 1 unit of Weight. - pub static WeightPrice: (AssetId, u128) = (Here.into(), 1_000_000_000_000); + pub static WeightPrice: (AssetId, u128) = (From::from(Here), 1_000_000_000_000); } pub type TestBarrier = ( diff --git a/xcm/xcm-builder/src/origin_conversion.rs b/xcm/xcm-builder/src/origin_conversion.rs index 08a6de91c648..b1800de2c6c8 100644 --- a/xcm/xcm-builder/src/origin_conversion.rs +++ b/xcm/xcm-builder/src/origin_conversion.rs @@ -20,7 +20,7 @@ use frame_support::traits::{EnsureOrigin, Get, GetBacking, OriginTrait}; use frame_system::RawOrigin as SystemRawOrigin; use polkadot_parachain::primitives::IsSystem; use sp_std::{convert::TryInto, marker::PhantomData}; -use xcm::latest::{BodyId, BodyPart, Junction, MultiLocation, NetworkId, OriginKind}; +use xcm::latest::{BodyId, BodyPart, Junction, Junctions::*, MultiLocation, NetworkId, OriginKind}; use xcm_executor::traits::{Convert, ConvertOrigin}; /// Sovereign accounts use the system's `Signed` origin with an account ID derived from the `LocationConverter`. @@ -45,9 +45,10 @@ where pub struct ParentAsSuperuser(PhantomData); impl ConvertOrigin for ParentAsSuperuser { fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result { - match (kind, origin) { - (OriginKind::Superuser, MultiLocation::X1(Junction::Parent)) => Ok(Origin::root()), - (_, origin) => Err(origin), + if kind == OriginKind::Superuser && origin.contains_parents_only(1) { + Ok(Origin::root()) + } else { + Err(origin) } } } @@ -58,9 +59,10 @@ impl, Origin: OriginTrait> ConvertOrigin { fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result { match (kind, origin) { - (OriginKind::Superuser, MultiLocation::X1(Junction::Parachain(id))) - if ParaId::from(id).is_system() => - Ok(Origin::root()), + ( + OriginKind::Superuser, + MultiLocation { parents: 0, interior: X1(Junction::Parachain(id)) }, + ) if ParaId::from(id).is_system() => Ok(Origin::root()), (_, origin) => Err(origin), } } @@ -74,7 +76,7 @@ impl, Origin: OriginTrait> ConvertOrigin match (kind, origin) { ( OriginKind::Superuser, - MultiLocation::X2(Junction::Parent, Junction::Parachain(id)), + MultiLocation { parents: 1, interior: X1(Junction::Parachain(id)) }, ) if ParaId::from(id).is_system() => Ok(Origin::root()), (_, origin) => Err(origin), } @@ -87,8 +89,10 @@ impl, Origin: From> ConvertOrigin Result { match (kind, origin) { - (OriginKind::Native, MultiLocation::X1(Junction::Parachain(id))) => - Ok(Origin::from(ParachainOrigin::from(id))), + ( + OriginKind::Native, + MultiLocation { parents: 0, interior: X1(Junction::Parachain(id)) }, + ) => Ok(Origin::from(ParachainOrigin::from(id))), (_, origin) => Err(origin), } } @@ -102,8 +106,10 @@ impl, Origin: From> ConvertOrigin Result { match (kind, origin) { - (OriginKind::Native, MultiLocation::X2(Junction::Parent, Junction::Parachain(id))) => - Ok(Origin::from(ParachainOrigin::from(id))), + ( + OriginKind::Native, + MultiLocation { parents: 1, interior: X1(Junction::Parachain(id)) }, + ) => Ok(Origin::from(ParachainOrigin::from(id))), (_, origin) => Err(origin), } } @@ -115,9 +121,10 @@ impl, Origin> ConvertOrigin for RelayChainAsNative { fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result { - match (kind, origin) { - (OriginKind::Native, MultiLocation::X1(Junction::Parent)) => Ok(RelayOrigin::get()), - (_, origin) => Err(origin), + if kind == OriginKind::Native && origin.contains_parents_only(1) { + Ok(RelayOrigin::get()) + } else { + Err(origin) } } } @@ -130,8 +137,10 @@ where { fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result { match (kind, origin) { - (OriginKind::Native, MultiLocation::X1(Junction::AccountId32 { id, network })) - if matches!(network, NetworkId::Any) || network == Network::get() => + ( + OriginKind::Native, + MultiLocation { parents: 0, interior: X1(Junction::AccountId32 { id, network }) }, + ) if matches!(network, NetworkId::Any) || network == Network::get() => Ok(Origin::signed(id.into())), (_, origin) => Err(origin), } @@ -146,8 +155,10 @@ where { fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result { match (kind, origin) { - (OriginKind::Native, MultiLocation::X1(Junction::AccountKey20 { key, network })) - if matches!(network, NetworkId::Any) || network == Network::get() => + ( + OriginKind::Native, + MultiLocation { parents: 0, interior: X1(Junction::AccountKey20 { key, network }) }, + ) if (matches!(network, NetworkId::Any) || network == Network::get()) => Ok(Origin::signed(key.into())), (_, origin) => Err(origin), } @@ -170,7 +181,7 @@ where // We institute a root fallback so root can always represent the context. This // guarantees that `successful_origin` will work. if o.caller() == Origin::root().caller() { - Ok(MultiLocation::Here) + Ok(Here.into()) } else { Err(o) } diff --git a/xcm/xcm-builder/src/tests.rs b/xcm/xcm-builder/src/tests.rs index 31f141ab68be..5ed3d3c49600 100644 --- a/xcm/xcm-builder/src/tests.rs +++ b/xcm/xcm-builder/src/tests.rs @@ -20,35 +20,41 @@ use xcm_executor::{traits::*, Config, XcmExecutor}; #[test] fn basic_setup_works() { - add_reserve(X1(Parent), Wild((X1(Parent), WildFungible).into())); + add_reserve(Parent.into(), Wild((Parent, WildFungible).into())); assert!(::IsReserve::filter_asset_location( - &(X1(Parent), 100).into(), - &X1(Parent), + &(Parent, 100).into(), + &Parent.into(), )); - assert_eq!(to_account(X1(Parachain(1))), Ok(1001)); - assert_eq!(to_account(X1(Parachain(50))), Ok(1050)); - assert_eq!(to_account(X2(Parent, Parachain(1))), Ok(2001)); - assert_eq!(to_account(X2(Parent, Parachain(50))), Ok(2050)); - assert_eq!(to_account(X1(AccountIndex64 { index: 1, network: Any })), Ok(1)); - assert_eq!(to_account(X1(AccountIndex64 { index: 42, network: Any })), Ok(42)); - assert_eq!(to_account(Here), Ok(3000)); + assert_eq!(to_account(X1(Parachain(1)).into()), Ok(1001)); + assert_eq!(to_account(X1(Parachain(50)).into()), Ok(1050)); + assert_eq!(to_account(MultiLocation::new(1, X1(Parachain(1)))), Ok(2001)); + assert_eq!(to_account(MultiLocation::new(1, X1(Parachain(50)))), Ok(2050)); + assert_eq!( + to_account(MultiLocation::new(0, X1(AccountIndex64 { index: 1, network: Any }))), + Ok(1), + ); + assert_eq!( + to_account(MultiLocation::new(0, X1(AccountIndex64 { index: 42, network: Any }))), + Ok(42), + ); + assert_eq!(to_account(Here.into()), Ok(3000)); } #[test] fn weigher_should_work() { let mut message = opaque::Xcm::ReserveAssetDeposited { - assets: (X1(Parent), 100).into(), + assets: (Parent, 100).into(), effects: vec![ Order::BuyExecution { - fees: (X1(Parent), 1).into(), + fees: (Parent, 1).into(), weight: 0, debt: 30, halt_on_error: true, orders: vec![], instructions: vec![], }, - Order::DepositAsset { assets: All.into(), max_assets: 1, beneficiary: Here }, + Order::DepositAsset { assets: All.into(), max_assets: 1, beneficiary: Here.into() }, ], } .into(); @@ -58,16 +64,26 @@ fn weigher_should_work() { #[test] fn take_weight_credit_barrier_should_work() { let mut message = - opaque::Xcm::TransferAsset { assets: (X1(Parent), 100).into(), beneficiary: Here }; + opaque::Xcm::TransferAsset { assets: (Parent, 100).into(), beneficiary: Here.into() }; let mut weight_credit = 10; - let r = - TakeWeightCredit::should_execute(&X1(Parent), true, &mut message, 10, &mut weight_credit); + let r = TakeWeightCredit::should_execute( + &Parent.into(), + true, + &mut message, + 10, + &mut weight_credit, + ); assert_eq!(r, Ok(())); assert_eq!(weight_credit, 0); - let r = - TakeWeightCredit::should_execute(&X1(Parent), true, &mut message, 10, &mut weight_credit); + let r = TakeWeightCredit::should_execute( + &Parent.into(), + true, + &mut message, + 10, + &mut weight_credit, + ); assert_eq!(r, Err(())); assert_eq!(weight_credit, 0); } @@ -75,12 +91,12 @@ fn take_weight_credit_barrier_should_work() { #[test] fn allow_unpaid_should_work() { let mut message = - opaque::Xcm::TransferAsset { assets: (X1(Parent), 100).into(), beneficiary: Here }; + opaque::Xcm::TransferAsset { assets: (Parent, 100).into(), beneficiary: Here.into() }; - AllowUnpaidFrom::set(vec![X1(Parent)]); + AllowUnpaidFrom::set(vec![Parent.into()]); let r = AllowUnpaidExecutionFrom::>::should_execute( - &X1(Parachain(1)), + &Parachain(1).into(), true, &mut message, 10, @@ -89,7 +105,7 @@ fn allow_unpaid_should_work() { assert_eq!(r, Err(())); let r = AllowUnpaidExecutionFrom::>::should_execute( - &X1(Parent), + &Parent.into(), true, &mut message, 10, @@ -100,13 +116,13 @@ fn allow_unpaid_should_work() { #[test] fn allow_paid_should_work() { - AllowPaidFrom::set(vec![X1(Parent)]); + AllowPaidFrom::set(vec![Parent.into()]); let mut message = - opaque::Xcm::TransferAsset { assets: (X1(Parent), 100).into(), beneficiary: Here }; + opaque::Xcm::TransferAsset { assets: (Parent, 100).into(), beneficiary: Here.into() }; let r = AllowTopLevelPaidExecutionFrom::>::should_execute( - &X1(Parachain(1)), + &Parachain(1).into(), true, &mut message, 10, @@ -114,9 +130,9 @@ fn allow_paid_should_work() { ); assert_eq!(r, Err(())); - let fees = (X1(Parent), 1).into(); + let fees = (Parent, 1).into(); let mut underpaying_message = opaque::Xcm::ReserveAssetDeposited { - assets: (X1(Parent), 100).into(), + assets: (Parent, 100).into(), effects: vec![ Order::BuyExecution { fees, @@ -126,12 +142,12 @@ fn allow_paid_should_work() { orders: vec![], instructions: vec![], }, - Order::DepositAsset { assets: All.into(), max_assets: 1, beneficiary: Here }, + Order::DepositAsset { assets: All.into(), max_assets: 1, beneficiary: Here.into() }, ], }; let r = AllowTopLevelPaidExecutionFrom::>::should_execute( - &X1(Parent), + &Parent.into(), true, &mut underpaying_message, 30, @@ -139,9 +155,9 @@ fn allow_paid_should_work() { ); assert_eq!(r, Err(())); - let fees = (X1(Parent), 1).into(); + let fees = (Parent, 1).into(); let mut paying_message = opaque::Xcm::ReserveAssetDeposited { - assets: (X1(Parent), 100).into(), + assets: (Parent, 100).into(), effects: vec![ Order::BuyExecution { fees, @@ -151,12 +167,12 @@ fn allow_paid_should_work() { orders: vec![], instructions: vec![], }, - Order::DepositAsset { assets: All.into(), max_assets: 1, beneficiary: Here }, + Order::DepositAsset { assets: All.into(), max_assets: 1, beneficiary: Here.into() }, ], }; let r = AllowTopLevelPaidExecutionFrom::>::should_execute( - &X1(Parachain(1)), + &Parachain(1).into(), true, &mut paying_message, 30, @@ -165,7 +181,7 @@ fn allow_paid_should_work() { assert_eq!(r, Err(())); let r = AllowTopLevelPaidExecutionFrom::>::should_execute( - &X1(Parent), + &Parent.into(), true, &mut paying_message, 30, @@ -176,14 +192,14 @@ fn allow_paid_should_work() { #[test] fn paying_reserve_deposit_should_work() { - AllowPaidFrom::set(vec![X1(Parent)]); - add_reserve(X1(Parent), (Parent, WildFungible).into()); + AllowPaidFrom::set(vec![Parent.into()]); + add_reserve(Parent.into(), (Parent, WildFungible).into()); WeightPrice::set((Parent.into(), 1_000_000_000_000)); - let origin = X1(Parent); - let fees = (X1(Parent), 30).into(); + let origin = Parent.into(); + let fees = (Parent, 30).into(); let message = Xcm::::ReserveAssetDeposited { - assets: (X1(Parent), 100).into(), + assets: (Parent, 100).into(), effects: vec![ Order::::BuyExecution { fees, @@ -196,28 +212,28 @@ fn paying_reserve_deposit_should_work() { Order::::DepositAsset { assets: All.into(), max_assets: 1, - beneficiary: Here, + beneficiary: Here.into(), }, ], }; let weight_limit = 50; let r = XcmExecutor::::execute_xcm(origin, message, weight_limit); assert_eq!(r, Outcome::Complete(30)); - assert_eq!(assets(3000), vec![(X1(Parent), 70).into()]); + assert_eq!(assets(3000), vec![(Parent, 70).into()]); } #[test] fn transfer_should_work() { // we'll let them have message execution for free. - AllowUnpaidFrom::set(vec![X1(Parachain(1))]); + AllowUnpaidFrom::set(vec![X1(Parachain(1)).into()]); // Child parachain #1 owns 1000 tokens held by us in reserve. add_asset(1001, (Here, 1000).into()); // They want to transfer 100 of them to their sibling parachain #2 let r = XcmExecutor::::execute_xcm( - X1(Parachain(1)), + Parachain(1).into(), Xcm::TransferAsset { assets: (Here, 100).into(), - beneficiary: X1(AccountIndex64 { index: 3, network: Any }), + beneficiary: X1(AccountIndex64 { index: 3, network: Any }).into(), }, 50, ); @@ -229,19 +245,19 @@ fn transfer_should_work() { #[test] fn reserve_transfer_should_work() { - AllowUnpaidFrom::set(vec![X1(Parachain(1))]); + AllowUnpaidFrom::set(vec![X1(Parachain(1)).into()]); // Child parachain #1 owns 1000 tokens held by us in reserve. add_asset(1001, (Here, 1000).into()); // The remote account owned by gav. - let three = X1(AccountIndex64 { index: 3, network: Any }); + let three: MultiLocation = X1(AccountIndex64 { index: 3, network: Any }).into(); // They want to transfer 100 of our native asset from sovereign account of parachain #1 into #2 // and let them know to hand it to account #3. let r = XcmExecutor::::execute_xcm( - X1(Parachain(1)), + Parachain(1).into(), Xcm::TransferReserveAsset { assets: (Here, 100).into(), - dest: X1(Parachain(2)), + dest: Parachain(2).into(), effects: vec![Order::DepositAsset { assets: All.into(), max_assets: 1, @@ -256,9 +272,9 @@ fn reserve_transfer_should_work() { assert_eq!( sent_xcm(), vec![( - X1(Parachain(2)), + Parachain(2).into(), Xcm::ReserveAssetDeposited { - assets: (X1(Parent), 100).into(), + assets: (Parent, 100).into(), effects: vec![Order::DepositAsset { assets: All.into(), max_assets: 1, @@ -271,9 +287,9 @@ fn reserve_transfer_should_work() { #[test] fn transacting_should_work() { - AllowUnpaidFrom::set(vec![X1(Parent)]); + AllowUnpaidFrom::set(vec![Parent.into()]); - let origin = X1(Parent); + let origin = Parent.into(); let message = Xcm::::Transact { origin_type: OriginKind::Native, require_weight_at_most: 50, @@ -286,9 +302,9 @@ fn transacting_should_work() { #[test] fn transacting_should_respect_max_weight_requirement() { - AllowUnpaidFrom::set(vec![X1(Parent)]); + AllowUnpaidFrom::set(vec![Parent.into()]); - let origin = X1(Parent); + let origin = Parent.into(); let message = Xcm::::Transact { origin_type: OriginKind::Native, require_weight_at_most: 40, @@ -301,9 +317,9 @@ fn transacting_should_respect_max_weight_requirement() { #[test] fn transacting_should_refund_weight() { - AllowUnpaidFrom::set(vec![X1(Parent)]); + AllowUnpaidFrom::set(vec![Parent.into()]); - let origin = X1(Parent); + let origin = Parent.into(); let message = Xcm::::Transact { origin_type: OriginKind::Native, require_weight_at_most: 50, @@ -316,15 +332,15 @@ fn transacting_should_refund_weight() { #[test] fn paid_transacting_should_refund_payment_for_unused_weight() { - let one = X1(AccountIndex64 { index: 1, network: Any }); + let one: MultiLocation = X1(AccountIndex64 { index: 1, network: Any }).into(); AllowPaidFrom::set(vec![one.clone()]); add_asset(1, (Parent, 100).into()); WeightPrice::set((Parent.into(), 1_000_000_000_000)); let origin = one.clone(); - let fees = (X1(Parent), 100).into(); + let fees = (Parent, 100).into(); let message = Xcm::::WithdrawAsset { - assets: (X1(Parent), 100).into(), // enough for 100 units of weight. + assets: (Parent, 100).into(), // enough for 100 units of weight. effects: vec![ Order::::BuyExecution { fees, @@ -349,17 +365,17 @@ fn paid_transacting_should_refund_payment_for_unused_weight() { let weight_limit = 100; let r = XcmExecutor::::execute_xcm(origin, message, weight_limit); assert_eq!(r, Outcome::Complete(50)); - assert_eq!(assets(1), vec![(X1(Parent), 50).into()]); + assert_eq!(assets(1), vec![(Parent, 50).into()]); } #[test] fn prepaid_result_of_query_should_get_free_execution() { let query_id = 33; - let origin = X1(Parent); + let origin: MultiLocation = Parent.into(); // We put this in manually here, but normally this would be done at the point of crafting the message. expect_response(query_id, origin.clone()); - let the_response = Response::Assets((X1(Parent), 100).into()); + let the_response = Response::Assets((Parent, 100).into()); let message = Xcm::::QueryResponse { query_id, response: the_response.clone() }; let weight_limit = 10; diff --git a/xcm/xcm-executor/integration-tests/src/lib.rs b/xcm/xcm-executor/integration-tests/src/lib.rs index 209b44b8981e..4b4c9d499525 100644 --- a/xcm/xcm-executor/integration-tests/src/lib.rs +++ b/xcm/xcm-executor/integration-tests/src/lib.rs @@ -24,7 +24,7 @@ use polkadot_test_client::{ use polkadot_test_service::construct_extrinsic; use sp_runtime::{generic::BlockId, traits::Block}; use sp_state_machine::InspectState; -use xcm::latest::{Error as XcmError, Junction::*, MultiLocation::*, Order, Outcome, Xcm::*}; +use xcm::latest::prelude::*; use xcm_executor::MAX_RECURSION_LIMIT; // This is the inflection point where the test should either fail or pass. @@ -37,12 +37,12 @@ fn execute_within_recursion_limit() { .set_execution_strategy(ExecutionStrategy::AlwaysWasm) .build(); - let mut msg = WithdrawAsset { assets: (X1(Parent), 100).into(), effects: vec![] }; + let mut msg = WithdrawAsset { assets: (Parent, 100).into(), effects: vec![] }; for _ in 0..MAX_RECURSION_CHECK { msg = WithdrawAsset { - assets: (X1(Parent), 100).into(), + assets: (Parent, 100).into(), effects: vec![Order::BuyExecution { - fees: (X1(Parent), 1).into(), + fees: (Parent, 1).into(), weight: 0, debt: 0, halt_on_error: true, @@ -92,12 +92,12 @@ fn exceed_recursion_limit() { .set_execution_strategy(ExecutionStrategy::AlwaysWasm) .build(); - let mut msg = WithdrawAsset { assets: (X1(Parent), 100).into(), effects: vec![] }; + let mut msg = WithdrawAsset { assets: (Parent, 100).into(), effects: vec![] }; for _ in 0..(MAX_RECURSION_CHECK + 1) { msg = WithdrawAsset { - assets: (X1(Parent), 100).into(), + assets: (Parent, 100).into(), effects: vec![Order::BuyExecution { - fees: (X1(Parent), 1).into(), + fees: (Parent, 1).into(), weight: 0, debt: 0, halt_on_error: true, diff --git a/xcm/xcm-executor/src/assets.rs b/xcm/xcm-executor/src/assets.rs index 4c241471a793..8b87cc7ca5c4 100644 --- a/xcm/xcm-executor/src/assets.rs +++ b/xcm/xcm-executor/src/assets.rs @@ -430,7 +430,6 @@ impl Assets { mod tests { use super::*; use xcm::latest::prelude::*; - use MultiLocation::Here; #[allow(non_snake_case)] /// Abstract fungible constructor fn AF(id: u8, amount: u128) -> MultiAsset { diff --git a/xcm/xcm-executor/src/lib.rs b/xcm/xcm-executor/src/lib.rs index 1ba86fd3343d..68bca5518afa 100644 --- a/xcm/xcm-executor/src/lib.rs +++ b/xcm/xcm-executor/src/lib.rs @@ -244,7 +244,7 @@ impl XcmExecutor { None }, (origin, Xcm::RelayedFrom { who, message }) => { - ensure!(who.is_interior(), XcmError::EscalationOfPrivilege); + ensure!(who.parent_count() == 0, XcmError::EscalationOfPrivilege); let mut origin = origin; origin.append_with(who).map_err(|_| XcmError::MultiLocationFull)?; let surplus = Self::do_execute_xcm( diff --git a/xcm/xcm-executor/src/traits/conversion.rs b/xcm/xcm-executor/src/traits/conversion.rs index 4342fc5002e5..edfa1a96029f 100644 --- a/xcm/xcm-executor/src/traits/conversion.rs +++ b/xcm/xcm-executor/src/traits/conversion.rs @@ -139,15 +139,15 @@ impl Convert, T> for Decoded { /// which is passed to the next convert item. /// /// ```rust -/// # use xcm::latest::{MultiLocation, Junction, OriginKind}; +/// # use xcm::latest::{MultiLocation, Junctions, Junction, OriginKind}; /// # use xcm_executor::traits::ConvertOrigin; /// // A convertor that will bump the para id and pass it to the next one. /// struct BumpParaId; /// impl ConvertOrigin for BumpParaId { /// fn convert_origin(origin: MultiLocation, _: OriginKind) -> Result { -/// match origin { -/// MultiLocation::X1(Junction::Parachain(id)) => { -/// Err(MultiLocation::X1(Junction::Parachain(id + 1))) +/// match origin.interior() { +/// Junctions::X1(Junction::Parachain(id)) if origin.parent_count() == 0 => { +/// Err(Junctions::X1(Junction::Parachain(id + 1)).into()) /// } /// _ => unreachable!() /// } @@ -157,8 +157,8 @@ impl Convert, T> for Decoded { /// struct AcceptPara7; /// impl ConvertOrigin for AcceptPara7 { /// fn convert_origin(origin: MultiLocation, _: OriginKind) -> Result { -/// match origin { -/// MultiLocation::X1(Junction::Parachain(id)) if id == 7 => { +/// match origin.interior() { +/// Junctions::X1(Junction::Parachain(id)) if id == &7 && origin.parent_count() == 0 => { /// Ok(7) /// } /// _ => Err(origin) @@ -166,7 +166,7 @@ impl Convert, T> for Decoded { /// } /// } /// # fn main() { -/// let origin = MultiLocation::X1(Junction::Parachain(6)); +/// let origin: MultiLocation = Junctions::X1(Junction::Parachain(6)).into(); /// assert!( /// <(BumpParaId, AcceptPara7) as ConvertOrigin>::convert_origin(origin, OriginKind::Native) /// .is_ok() diff --git a/xcm/xcm-executor/src/traits/transact_asset.rs b/xcm/xcm-executor/src/traits/transact_asset.rs index e261d9c9c963..80ee2de660c3 100644 --- a/xcm/xcm-executor/src/traits/transact_asset.rs +++ b/xcm/xcm-executor/src/traits/transact_asset.rs @@ -193,7 +193,7 @@ impl TransactAsset for Tuple { #[cfg(test)] mod tests { use super::*; - use MultiLocation::Here; + use xcm::latest::Junctions::Here; pub struct UnimplementedTransactor; impl TransactAsset for UnimplementedTransactor {} @@ -273,7 +273,7 @@ mod tests { (UnimplementedTransactor, NotFoundTransactor, UnimplementedTransactor); assert_eq!( - MultiTransactor::deposit_asset(&(Here, 1).into(), &Here), + MultiTransactor::deposit_asset(&(Here, 1).into(), &Here.into()), Err(XcmError::AssetNotFound) ); } @@ -282,7 +282,7 @@ mod tests { fn unimplemented_and_not_found_continue_iteration() { type MultiTransactor = (UnimplementedTransactor, NotFoundTransactor, SuccessfulTransactor); - assert_eq!(MultiTransactor::deposit_asset(&(Here, 1).into(), &Here), Ok(())); + assert_eq!(MultiTransactor::deposit_asset(&(Here, 1).into(), &Here.into()), Ok(()),); } #[test] @@ -290,7 +290,7 @@ mod tests { type MultiTransactor = (OverflowTransactor, SuccessfulTransactor); assert_eq!( - MultiTransactor::deposit_asset(&(Here, 1).into(), &Here), + MultiTransactor::deposit_asset(&(Here, 1).into(), &Here.into()), Err(XcmError::Overflow) ); } @@ -299,6 +299,6 @@ mod tests { fn success_stops_iteration() { type MultiTransactor = (SuccessfulTransactor, OverflowTransactor); - assert_eq!(MultiTransactor::deposit_asset(&(Here, 1).into(), &Here), Ok(())); + assert_eq!(MultiTransactor::deposit_asset(&(Here, 1).into(), &Here.into()), Ok(()),); } } diff --git a/xcm/xcm-simulator/example/src/lib.rs b/xcm/xcm-simulator/example/src/lib.rs index 4218203cf2a6..547c6f1858be 100644 --- a/xcm/xcm-simulator/example/src/lib.rs +++ b/xcm/xcm-simulator/example/src/lib.rs @@ -111,8 +111,8 @@ mod tests { ); Relay::execute_with(|| { assert_ok!(RelayChainPalletXcm::send_xcm( - Here, - X1(Parachain(1)), + Here.into(), + Parachain(1).into(), Transact { origin_type: OriginKind::SovereignAccount, require_weight_at_most: INITIAL_BALANCE as u64, @@ -138,8 +138,8 @@ mod tests { ); ParaA::execute_with(|| { assert_ok!(ParachainPalletXcm::send_xcm( - Here, - X1(Parent), + Here.into(), + Parent.into(), Transact { origin_type: OriginKind::SovereignAccount, require_weight_at_most: INITIAL_BALANCE as u64, @@ -165,8 +165,8 @@ mod tests { ); ParaA::execute_with(|| { assert_ok!(ParachainPalletXcm::send_xcm( - Here, - X2(Parent, Parachain(2)), + Here.into(), + MultiLocation::new(1, X1(Parachain(2))), Transact { origin_type: OriginKind::SovereignAccount, require_weight_at_most: INITIAL_BALANCE as u64, @@ -190,8 +190,8 @@ mod tests { Relay::execute_with(|| { assert_ok!(RelayChainPalletXcm::reserve_transfer_assets( relay_chain::Origin::signed(ALICE), - Box::new(X1(Parachain(1))), - Box::new(X1(AccountId32 { network: Any, id: ALICE.into() })), + Box::new(X1(Parachain(1)).into()), + Box::new(X1(AccountId32 { network: Any, id: ALICE.into() }).into()), (Here, 123).into(), 0, 3, diff --git a/xcm/xcm-simulator/example/src/parachain.rs b/xcm/xcm-simulator/example/src/parachain.rs index b5146122d6fe..79c2f6e2947d 100644 --- a/xcm/xcm-simulator/example/src/parachain.rs +++ b/xcm/xcm-simulator/example/src/parachain.rs @@ -101,7 +101,7 @@ parameter_types! { } parameter_types! { - pub const KsmLocation: MultiLocation = MultiLocation::X1(Parent); + pub const KsmLocation: MultiLocation = MultiLocation::parent(); pub const RelayNetwork: NetworkId = NetworkId::Kusama; pub Ancestry: MultiLocation = Parachain(MsgQueue::parachain_id().into()).into(); } @@ -120,7 +120,7 @@ pub type XcmOriginToCallOrigin = ( parameter_types! { pub const UnitWeightCost: Weight = 1; - pub KsmPerSecond: (AssetId, u128) = (Concrete(X1(Parent)), 1); + pub KsmPerSecond: (AssetId, u128) = (Concrete(Parent.into()), 1); } pub type LocalAssetTransactor = @@ -210,8 +210,8 @@ pub mod mock_msg_queue { let hash = Encode::using_encoded(&xcm, T::Hashing::hash); let (result, event) = match Xcm::::try_from(xcm) { Ok(xcm) => { - let location = (Parent, Parachain(sender.into())); - match T::XcmExecutor::execute_xcm(location.into(), xcm, max_weight) { + let location = MultiLocation::new(1, X1(Parachain(sender.into()))); + match T::XcmExecutor::execute_xcm(location, xcm, max_weight) { Outcome::Error(e) => (Err(e.clone()), Event::Fail(Some(hash), e)), Outcome::Complete(w) => (Ok(w), Event::Success(Some(hash))), // As far as the caller is concerned, this was dispatched without error, so diff --git a/xcm/xcm-simulator/example/src/relay_chain.rs b/xcm/xcm-simulator/example/src/relay_chain.rs index 75a727b614e6..8dd543d428fd 100644 --- a/xcm/xcm-simulator/example/src/relay_chain.rs +++ b/xcm/xcm-simulator/example/src/relay_chain.rs @@ -87,10 +87,10 @@ impl shared::Config for Runtime {} impl configuration::Config for Runtime {} parameter_types! { - pub const KsmLocation: MultiLocation = MultiLocation::Here; + pub const KsmLocation: MultiLocation = Here.into(); pub const KusamaNetwork: NetworkId = NetworkId::Kusama; pub const AnyNetwork: NetworkId = NetworkId::Any; - pub Ancestry: MultiLocation = MultiLocation::Here; + pub Ancestry: MultiLocation = Here.into(); pub UnitWeightCost: Weight = 1_000; } diff --git a/xcm/xcm-simulator/src/lib.rs b/xcm/xcm-simulator/src/lib.rs index 7a3ad25d1555..aed9635cff7f 100644 --- a/xcm/xcm-simulator/src/lib.rs +++ b/xcm/xcm-simulator/src/lib.rs @@ -195,8 +195,8 @@ macro_rules! decl_test_network { fn send_xcm(destination: $crate::MultiLocation, message: $crate::Xcm<()>) -> $crate::XcmResult { use $crate::{UmpSink, XcmpMessageHandlerT}; - match destination { - $crate::X1($crate::Parent) => { + match destination.interior() { + $crate::Junctions::Here if destination.parent_count() == 1 => { let encoded = $crate::encode_xcm(message, $crate::MessageKind::Ump); let _ = <$relay_chain>::process_upward_message( T::get(), &encoded[..], @@ -205,7 +205,7 @@ macro_rules! decl_test_network { Ok(()) }, $( - $crate::X2($crate::Parent, $crate::Parachain(id)) if id == $para_id => { + $crate::X1($crate::Parachain(id)) if *id == $para_id && destination.parent_count() == 1 => { let encoded = $crate::encode_xcm(message, $crate::MessageKind::Xcmp); let messages = vec![(T::get(), 1, &encoded[..])]; let _ = <$parachain>::handle_xcmp_messages( @@ -226,9 +226,9 @@ macro_rules! decl_test_network { fn send_xcm(destination: $crate::MultiLocation, message: $crate::Xcm<()>) -> $crate::XcmResult { use $crate::DmpMessageHandlerT; - match destination { + match destination.interior() { $( - $crate::X1($crate::Parachain(id)) if id == $para_id => { + $crate::X1($crate::Parachain(id)) if *id == $para_id && destination.parent_count() == 0 => { let encoded = $crate::encode_xcm(message, $crate::MessageKind::Dmp); let messages = vec![(1, encoded)]; let _ = <$parachain>::handle_dmp_messages(