From 3e15173b17ef4b7c99963fbc818344ff9878884f Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Sun, 4 Apr 2021 17:51:31 +0200 Subject: [PATCH 001/166] MultiAsset TWO --- xcm/src/v0/mod.rs | 2 + xcm/src/v0/multiasset.rs | 128 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 130 insertions(+) create mode 100644 xcm/src/v0/multiasset.rs diff --git a/xcm/src/v0/mod.rs b/xcm/src/v0/mod.rs index c69093d4f851..7fef83987d94 100644 --- a/xcm/src/v0/mod.rs +++ b/xcm/src/v0/mod.rs @@ -27,6 +27,8 @@ mod multi_asset; mod multi_location; mod order; mod traits; +pub mod multiasset; // the new multiasset. + pub use junction::{Junction, NetworkId}; pub use multi_asset::{MultiAsset, AssetInstance}; pub use multi_location::MultiLocation; diff --git a/xcm/src/v0/multiasset.rs b/xcm/src/v0/multiasset.rs new file mode 100644 index 000000000000..8e1839719f09 --- /dev/null +++ b/xcm/src/v0/multiasset.rs @@ -0,0 +1,128 @@ +// 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 <http://www.gnu.org/licenses/>. + +//! Cross-Consensus Message format asset data structure. + +use alloc::vec::Vec; +use parity_scale_codec::{self as codec, Encode, Decode}; +use super::{MultiLocation, multi_asset::{AssetInstance, MultiAsset as OldMultiAsset}}; + +/// Classification of an asset being concrete or abstract. +#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)] +pub enum AssetId { + Concrete(MultiLocation), + Abstract(Vec<u8>), +} + +impl AssetId { + /// Prepend a MultiLocation to a concrete asset, giving it a new root location. + pub fn reanchor(&mut self, prepend: &MultiLocation) -> Result<(), ()> { + if let AssetId::Concrete(ref mut l) = self { + l.prepend_with(prepend.clone()).map_err(|_| ())?; + } + Ok(()) + } +} + +/// Classification of whether an asset is fungible or not, along with an optional amount or instance. +#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)] +pub enum Fungibility { + Fungible(Option<u128>), + NonFungible(Option<AssetInstance>), +} + +#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)] +pub enum MultiAsset { + None, + Asset(Fungibility, Option<AssetId>), + All, +} + +impl From<(AssetId, Fungibility)> for MultiAsset { + fn from((asset_id, fungibility): (AssetId, Fungibility)) -> MultiAsset { + MultiAsset::Asset(fungibility, Some(asset_id)) + } +} + +impl From<Fungibility> for MultiAsset { + fn from(fungibility: Fungibility) -> MultiAsset { + MultiAsset::Asset(fungibility, None) + } +} + +impl From<()> for MultiAsset { + fn from(_: ()) -> MultiAsset { + MultiAsset::None + } +} + +impl Encode for MultiAsset { + fn encode(&self) -> Vec<u8> { + OldMultiAsset::from(self.clone()).encode() + } +} + +impl Decode for MultiAsset { + fn decode<I: codec::Input>(input: &mut I) -> Result<Self, parity_scale_codec::Error> { + OldMultiAsset::decode(input).map(Into::into) + } +} + +impl From<MultiAsset> for OldMultiAsset { + fn from(a: MultiAsset) -> Self { + use {AssetId::*, Fungibility::*, OldMultiAsset::*, MultiAsset::Asset}; + match a { + MultiAsset::None => OldMultiAsset::None, + MultiAsset::All => All, + + Asset(Fungible(_), Option::None) => AllFungible, + Asset(NonFungible(_), Option::None) => AllNonFungible, + + Asset(Fungible(Option::None), Some(Concrete(id))) => AllConcreteFungible { id }, + Asset(Fungible(Option::None), Some(Abstract(id))) => AllAbstractFungible { id }, + Asset(NonFungible(Option::None), Some(Concrete(class))) => AllConcreteNonFungible { class }, + Asset(NonFungible(Option::None), Some(Abstract(class))) => AllAbstractNonFungible { class }, + + Asset(Fungible(Some(amount)), Some(Concrete(id))) => ConcreteFungible { id, amount }, + Asset(Fungible(Some(amount)), Some(Abstract(id))) => AbstractFungible { id, amount }, + Asset(NonFungible(Some(instance)), Some(Concrete(class))) => ConcreteNonFungible { class, instance }, + Asset(NonFungible(Some(instance)), Some(Abstract(class))) => AbstractNonFungible { class, instance }, + } + } +} + +impl From<OldMultiAsset> for MultiAsset { + fn from(a: OldMultiAsset) -> Self { + use {AssetId::*, Fungibility::*, OldMultiAsset::*, MultiAsset::Asset}; + match a { + None => MultiAsset::None, + All => MultiAsset::All, + + AllFungible => Asset(Fungible(Option::None), Option::None), + AllNonFungible => Asset(NonFungible(Option::None), Option::None), + + AllConcreteFungible { id } => Asset(Fungible(Option::None), Some(Concrete(id))), + AllAbstractFungible { id } => Asset(Fungible(Option::None), Some(Abstract(id))), + AllConcreteNonFungible { class } => Asset(NonFungible(Option::None), Some(Concrete(class))), + AllAbstractNonFungible { class } => Asset(NonFungible(Option::None), Some(Abstract(class))), + + ConcreteFungible { id, amount } => Asset(Fungible(Some(amount)), Some(Concrete(id))), + AbstractFungible { id, amount } => Asset(Fungible(Some(amount)), Some(Abstract(id))), + ConcreteNonFungible { class, instance } => Asset(NonFungible(Some(instance)), Some(Concrete(class))), + AbstractNonFungible { class, instance } => Asset(NonFungible(Some(instance)), Some(Abstract(class))), + } + } +} From a7c51a89b3bb89e5643f74185b15970553472077 Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Sat, 3 Jul 2021 21:34:36 -0700 Subject: [PATCH 002/166] Ensure MultiLocation always has a canonical representation --- xcm/src/lib.rs | 11 + xcm/src/v0/mod.rs | 1 + xcm/src/v0/multi_asset.rs | 1 + xcm/src/v0/multi_location.rs | 1 + xcm/src/v1/junction.rs | 133 ++++++ xcm/src/v1/mod.rs | 317 +++++++++++++ xcm/src/v1/multi_asset.rs | 380 +++++++++++++++ xcm/src/v1/multi_location.rs | 867 +++++++++++++++++++++++++++++++++++ xcm/src/v1/order.rs | 140 ++++++ xcm/src/v1/traits.rs | 246 ++++++++++ 10 files changed, 2097 insertions(+) create mode 100644 xcm/src/v1/junction.rs create mode 100644 xcm/src/v1/mod.rs create mode 100644 xcm/src/v1/multi_asset.rs create mode 100644 xcm/src/v1/multi_location.rs create mode 100644 xcm/src/v1/order.rs create mode 100644 xcm/src/v1/traits.rs diff --git a/xcm/src/lib.rs b/xcm/src/lib.rs index 9768be8dacaa..35a53b2ac1dd 100644 --- a/xcm/src/lib.rs +++ b/xcm/src/lib.rs @@ -27,6 +27,7 @@ use parity_scale_codec::{Encode, Decode}; use derivative::Derivative; pub mod v0; +pub mod v1; mod double_encoded; pub use double_encoded::DoubleEncoded; @@ -38,6 +39,7 @@ pub use double_encoded::DoubleEncoded; #[codec(decode_bound())] pub enum VersionedXcm<Call> { V0(v0::Xcm<Call>), + V1(v1::Xcm<Call>), } pub mod opaque { @@ -48,6 +50,13 @@ pub mod opaque { pub use crate::v0::opaque::{Xcm, Order}; } + pub mod v1 { + // Everything from v1 + pub use crate::v1::*; + // Then override with the opaque types in v1 + pub use crate::v1::opaque::{Xcm, Order}; + } + /// The basic VersionedXcm type which just uses the `Vec<u8>` as an encoded call. pub type VersionedXcm = super::VersionedXcm<()>; } @@ -56,10 +65,12 @@ pub mod opaque { #[derive(Clone, Eq, PartialEq, Encode, Decode, Debug)] pub enum VersionedMultiLocation { V0(v0::MultiLocation), + V1(v1::MultiLocation), } /// A versioned multi-asset, an identifier for an asset within a consensus system. #[derive(Clone, Eq, PartialEq, Encode, Decode, Debug)] pub enum VersionedMultiAsset { V0(v0::MultiAsset), + V1(v1::MultiAsset), } diff --git a/xcm/src/v0/mod.rs b/xcm/src/v0/mod.rs index 368353f2d82a..6dfe54c79322 100644 --- a/xcm/src/v0/mod.rs +++ b/xcm/src/v0/mod.rs @@ -272,6 +272,7 @@ impl<Call> TryFrom<VersionedXcm<Call>> for Xcm<Call> { fn try_from(x: VersionedXcm<Call>) -> result::Result<Self, ()> { match x { VersionedXcm::V0(x) => Ok(x), + _ => Err(()), } } } diff --git a/xcm/src/v0/multi_asset.rs b/xcm/src/v0/multi_asset.rs index 20032e7169a4..2d65d2912088 100644 --- a/xcm/src/v0/multi_asset.rs +++ b/xcm/src/v0/multi_asset.rs @@ -317,6 +317,7 @@ impl TryFrom<VersionedMultiAsset> for MultiAsset { fn try_from(x: VersionedMultiAsset) -> result::Result<Self, ()> { match x { VersionedMultiAsset::V0(x) => Ok(x), + _ => Err(()), } } } diff --git a/xcm/src/v0/multi_location.rs b/xcm/src/v0/multi_location.rs index 17df340eca07..851ef90cf226 100644 --- a/xcm/src/v0/multi_location.rs +++ b/xcm/src/v0/multi_location.rs @@ -636,6 +636,7 @@ impl TryFrom<VersionedMultiLocation> for MultiLocation { fn try_from(x: VersionedMultiLocation) -> result::Result<Self, ()> { match x { VersionedMultiLocation::V0(x) => Ok(x), + _ => Err(()), } } } diff --git a/xcm/src/v1/junction.rs b/xcm/src/v1/junction.rs new file mode 100644 index 000000000000..5375f286d44d --- /dev/null +++ b/xcm/src/v1/junction.rs @@ -0,0 +1,133 @@ +// Copyright 2021 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 <http://www.gnu.org/licenses/>. + +//! Support datastructures for `MultiLocation`, primarily the `Junction` datatype. + +use alloc::vec::Vec; +use parity_scale_codec::{self, Encode, Decode}; + +/// A global identifier of an account-bearing consensus system. +#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug)] +pub enum NetworkId { + /// Unidentified/any. + Any, + /// Some named network. + Named(Vec<u8>), + /// The Polkadot Relay chain + Polkadot, + /// Kusama. + Kusama, +} + +/// An identifier of a pluralistic body. +#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug)] +pub enum BodyId { + /// The only body in its context. + Unit, + /// A named body. + Named(Vec<u8>), + /// An indexed body. + // TODO: parity-scale-codec#262: Change to be a tuple. + Index { #[codec(compact)] id: u32 }, + /// The unambiguous executive body (for Polkadot, this would be the Polkadot council). + Executive, + /// The unambiguous technical body (for Polkadot, this would be the Technical Committee). + Technical, + /// The unambiguous legislative body (for Polkadot, this could be considered the opinion of a majority of + /// lock-voters). + Legislative, + /// The unambiguous judicial body (this doesn't exist on Polkadot, but if it were to get a "grand oracle", it + /// may be considered as that). + Judicial, +} + +/// A part of a pluralistic body. +#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug)] +pub enum BodyPart { + /// The body's declaration, under whatever means it decides. + Voice, + /// A given number of members of the body. + Members { #[codec(compact)] count: u32 }, + /// A given number of members of the body, out of some larger caucus. + Fraction { #[codec(compact)] nom: u32, #[codec(compact)] denom: u32 }, + /// No less than the given proportion of members of the body. + AtLeastProportion { #[codec(compact)] nom: u32, #[codec(compact)] denom: u32 }, + /// More than than the given proportion of members of the body. + MoreThanProportion { #[codec(compact)] nom: u32, #[codec(compact)] denom: u32 }, +} + +impl BodyPart { + /// Returns `true` if the part represents a strict majority (> 50%) of the body in question. + pub fn is_majority(&self) -> bool { + match self { + BodyPart::Fraction { nom, denom } if *nom * 2 > *denom => true, + BodyPart::AtLeastProportion { nom, denom } if *nom * 2 > *denom => true, + BodyPart::MoreThanProportion { nom, denom } if *nom * 2 >= *denom => true, + _ => false, + } + } +} + +/// 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)] id: 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<u8>), + /// 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 }, +} diff --git a/xcm/src/v1/mod.rs b/xcm/src/v1/mod.rs new file mode 100644 index 000000000000..7be850a087c6 --- /dev/null +++ b/xcm/src/v1/mod.rs @@ -0,0 +1,317 @@ +// Copyright 2021 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 <http://www.gnu.org/licenses/>. + +//! Version 1 of the Cross-Consensus Message format data structures. + +use core::{result, convert::TryFrom, fmt::Debug}; +use derivative::Derivative; +use alloc::vec::Vec; +use parity_scale_codec::{self, Encode, Decode}; +use crate::{VersionedMultiAsset, DoubleEncoded, VersionedXcm}; + +mod junction; +mod multi_asset; +mod multi_location; +mod order; +mod traits; +pub use junction::{Junction, NetworkId, BodyId, BodyPart}; +pub use multi_asset::{MultiAsset, AssetInstance}; +pub use multi_location::{Junctions, MultiLocation}; +pub use order::Order; +pub use traits::{Error, Result, SendXcm, ExecuteXcm, Outcome}; + +/// A prelude for importing all types typically used when interacting with XCM messages. +pub mod prelude { + pub use super::junction::{Junction::*, NetworkId, BodyId, BodyPart}; + pub use super::multi_asset::{MultiAsset::{self, *}, AssetInstance::{self, *}}; + pub use super::multi_location::{Junctions::{self, *}, MultiLocation}; + pub use super::order::Order::{self, *}; + pub use super::traits::{Error as XcmError, Result as XcmResult, SendXcm, ExecuteXcm, Outcome}; + pub use super::{Xcm::{self, *}, OriginKind}; +} + +// TODO: #2841 #XCMENCODE Efficient encodings for Vec<MultiAsset>, Vec<Order>, using initial byte values 128+ to encode +// the number of items in the vector. + +/// Basically just the XCM (more general) version of `ParachainDispatchOrigin`. +#[derive(Copy, Clone, Eq, PartialEq, Encode, Decode, Debug)] +pub enum OriginKind { + /// Origin should just be the native dispatch origin representation for the sender in the + /// local runtime framework. For Cumulus/Frame chains this is the `Parachain` or `Relay` origin + /// if coming from a chain, though there may be others if the `MultiLocation` XCM origin has a + /// primary/native dispatch origin form. + Native, + + /// Origin should just be the standard account-based origin with the sovereign account of + /// the sender. For Cumulus/Frame chains, this is the `Signed` origin. + SovereignAccount, + + /// Origin should be the super-user. For Cumulus/Frame chains, this is the `Root` origin. + /// This will not usually be an available option. + Superuser, + + /// Origin should be interpreted as an XCM native origin and the `MultiLocation` should be + /// encoded directly in the dispatch origin unchanged. For Cumulus/Frame chains, this will be + /// the `pallet_xcm::Origin::Xcm` type. + Xcm, +} + +/// Response data to a query. +#[derive(Clone, Eq, PartialEq, Encode, Decode, Debug)] +pub enum Response { + /// Some assets. + Assets(Vec<MultiAsset>), +} + +/// Cross-Consensus Message: A message from one consensus system to another. +/// +/// Consensus systems that may send and receive messages include blockchains and smart contracts. +/// +/// All messages are delivered from a known *origin*, expressed as a `MultiLocation`. +/// +/// This is the inner XCM format and is version-sensitive. Messages are typically passed using the outer +/// XCM format, known as `VersionedXcm`. +#[derive(Derivative, Encode, Decode)] +#[derivative(Clone(bound = ""), Eq(bound = ""), PartialEq(bound = ""), Debug(bound = ""))] +#[codec(encode_bound())] +#[codec(decode_bound())] +pub enum Xcm<Call> { + /// Withdraw asset(s) (`assets`) from the ownership of `origin` and place them into `holding`. Execute the + /// orders (`effects`). + /// + /// - `assets`: The asset(s) to be withdrawn into holding. + /// - `effects`: The order(s) to execute on the holding account. + /// + /// Kind: *Instruction*. + /// + /// Errors: + #[codec(index = 0)] + WithdrawAsset { assets: Vec<MultiAsset>, effects: Vec<Order<Call>> }, + + /// Asset(s) (`assets`) have been received into the ownership of this system on the `origin` system. + /// + /// Some orders are given (`effects`) which should be executed once the corresponding derivative assets have + /// been placed into `holding`. + /// + /// - `assets`: The asset(s) that are minted into holding. + /// - `effects`: The order(s) to execute on the holding account. + /// + /// Safety: `origin` must be trusted to have received and be storing `assets` such that they may later be + /// withdrawn should this system send a corresponding message. + /// + /// Kind: *Trusted Indication*. + /// + /// Errors: + #[codec(index = 1)] + ReserveAssetDeposit { assets: Vec<MultiAsset>, effects: Vec<Order<Call>> }, + + /// Asset(s) (`assets`) have been destroyed on the `origin` system and equivalent assets should be + /// created on this system. + /// + /// Some orders are given (`effects`) which should be executed once the corresponding derivative assets have + /// been placed into `holding`. + /// + /// - `assets`: The asset(s) that are minted into holding. + /// - `effects`: The order(s) to execute on the holding account. + /// + /// Safety: `origin` must be trusted to have irrevocably destroyed the `assets` prior as a consequence of + /// sending this message. + /// + /// Kind: *Trusted Indication*. + /// + /// Errors: + #[codec(index = 2)] + TeleportAsset { assets: Vec<MultiAsset>, effects: Vec<Order<Call>> }, + + /// Indication of the contents of the holding account corresponding to the `QueryHolding` order of `query_id`. + /// + /// - `query_id`: The identifier of the query that resulted in this message being sent. + /// - `assets`: The message content. + /// + /// Safety: No concerns. + /// + /// Kind: *Information*. + /// + /// Errors: + #[codec(index = 3)] + QueryResponse { #[codec(compact)] query_id: u64, response: Response }, + + /// Withdraw asset(s) (`assets`) from the ownership of `origin` and place equivalent assets under the + /// ownership of `dest` within this consensus system. + /// + /// - `assets`: The asset(s) to be withdrawn. + /// - `dest`: The new owner for the assets. + /// + /// Safety: No concerns. + /// + /// Kind: *Instruction*. + /// + /// Errors: + #[codec(index = 4)] + TransferAsset { assets: Vec<MultiAsset>, dest: MultiLocation }, + + /// Withdraw asset(s) (`assets`) from the ownership of `origin` and place equivalent assets under the + /// ownership of `dest` within this consensus system. + /// + /// Send an onward XCM message to `dest` of `ReserveAssetDeposit` with the given `effects`. + /// + /// - `assets`: The asset(s) to be withdrawn. + /// - `dest`: The new owner for the assets. + /// - `effects`: The orders that should be contained in the `ReserveAssetDeposit` which is sent onwards to + /// `dest. + /// + /// Safety: No concerns. + /// + /// Kind: *Instruction*. + /// + /// Errors: + #[codec(index = 5)] + TransferReserveAsset { assets: Vec<MultiAsset>, dest: MultiLocation, effects: Vec<Order<()>> }, + + /// Apply the encoded transaction `call`, whose dispatch-origin should be `origin` as expressed by the kind + /// of origin `origin_type`. + /// + /// - `origin_type`: The means of expressing the message origin as a dispatch origin. + /// - `max_weight`: The weight of `call`; this should be at least the chain's calculated weight and will + /// be used in the weight determination arithmetic. + /// - `call`: The encoded transaction to be applied. + /// + /// Safety: No concerns. + /// + /// Kind: *Instruction*. + /// + /// Errors: + #[codec(index = 6)] + Transact { origin_type: OriginKind, require_weight_at_most: u64, call: DoubleEncoded<Call> }, + + /// A message to notify about a new incoming HRMP channel. This message is meant to be sent by the + /// relay-chain to a para. + /// + /// - `sender`: The sender in the to-be opened channel. Also, the initiator of the channel opening. + /// - `max_message_size`: The maximum size of a message proposed by the sender. + /// - `max_capacity`: The maximum number of messages that can be queued in the channel. + /// + /// Safety: The message should originate directly from the relay-chain. + /// + /// Kind: *System Notification* + #[codec(index = 7)] + HrmpNewChannelOpenRequest { + #[codec(compact)] sender: u32, + #[codec(compact)] max_message_size: u32, + #[codec(compact)] max_capacity: u32, + }, + + /// A message to notify about that a previously sent open channel request has been accepted by + /// the recipient. That means that the channel will be opened during the next relay-chain session + /// change. This message is meant to be sent by the relay-chain to a para. + /// + /// Safety: The message should originate directly from the relay-chain. + /// + /// Kind: *System Notification* + /// + /// Errors: + #[codec(index = 8)] + HrmpChannelAccepted { + #[codec(compact)] recipient: u32, + }, + + /// A message to notify that the other party in an open channel decided to close it. In particular, + /// `initiator` is going to close the channel opened from `sender` to the `recipient`. The close + /// will be enacted at the next relay-chain session change. This message is meant to be sent by + /// the relay-chain to a para. + /// + /// Safety: The message should originate directly from the relay-chain. + /// + /// Kind: *System Notification* + /// + /// Errors: + #[codec(index = 9)] + HrmpChannelClosing { + #[codec(compact)] initiator: u32, + #[codec(compact)] sender: u32, + #[codec(compact)] recipient: u32, + }, + + /// A message to indicate that the embedded XCM is actually arriving on behalf of some consensus + /// location within the origin. + /// + /// Safety: `who` must be an interior location of the context. This basically means that no `Parent` + /// junctions are allowed in it. This should be verified at the time of XCM execution. + /// + /// Kind: *Instruction* + /// + /// Errors: + #[codec(index = 10)] + RelayedFrom { + who: MultiLocation, + message: alloc::boxed::Box<Xcm<Call>>, + }, +} + +impl<Call> From<Xcm<Call>> for VersionedXcm<Call> { + fn from(x: Xcm<Call>) -> Self { + VersionedXcm::V1(x) + } +} + +impl<Call> TryFrom<VersionedXcm<Call>> for Xcm<Call> { + type Error = (); + fn try_from(x: VersionedXcm<Call>) -> result::Result<Self, ()> { + match x { + VersionedXcm::V1(x) => Ok(x), + _ => Err(()), + } + } +} + +impl<Call> Xcm<Call> { + pub fn into<C>(self) -> Xcm<C> { Xcm::from(self) } + pub fn from<C>(xcm: Xcm<C>) -> Self { + use Xcm::*; + match xcm { + WithdrawAsset { assets, effects } + => WithdrawAsset { assets, effects: effects.into_iter().map(Order::into).collect() }, + ReserveAssetDeposit { assets, effects } + => ReserveAssetDeposit { assets, effects: effects.into_iter().map(Order::into).collect() }, + TeleportAsset { assets, effects } + => TeleportAsset { assets, effects: effects.into_iter().map(Order::into).collect() }, + QueryResponse { query_id: u64, response } + => QueryResponse { query_id: u64, response }, + TransferAsset { assets, dest } + => TransferAsset { assets, dest }, + TransferReserveAsset { assets, dest, effects } + => TransferReserveAsset { assets, dest, effects }, + HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity} + => HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity}, + HrmpChannelAccepted { recipient} + => HrmpChannelAccepted { recipient}, + HrmpChannelClosing { initiator, sender, recipient} + => HrmpChannelClosing { initiator, sender, recipient}, + Transact { origin_type, require_weight_at_most, call} + => Transact { origin_type, require_weight_at_most, call: call.into() }, + RelayedFrom { who, message } + => RelayedFrom { who, message: alloc::boxed::Box::new((*message).into()) }, + } + } +} + +pub mod opaque { + /// The basic concrete type of `generic::Xcm`, which doesn't make any assumptions about the format of a + /// call other than it is pre-encoded. + pub type Xcm = super::Xcm<()>; + + pub use super::order::opaque::*; +} diff --git a/xcm/src/v1/multi_asset.rs b/xcm/src/v1/multi_asset.rs new file mode 100644 index 000000000000..552e67f03d8e --- /dev/null +++ b/xcm/src/v1/multi_asset.rs @@ -0,0 +1,380 @@ +// Copyright 2021 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 <http://www.gnu.org/licenses/>. + +//! Cross-Consensus Message format data structures. + +use core::{result, convert::TryFrom}; +use alloc::vec::Vec; + +use parity_scale_codec::{self, Encode, Decode}; +use super::{MultiLocation, VersionedMultiAsset}; + +/// A general identifier for an instance of a non-fungible asset class. +#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug)] +pub enum AssetInstance { + /// Undefined - used if the NFA class has only one instance. + Undefined, + + /// A compact index. Technically this could be greater than u128, but this implementation supports only + /// values up to `2**128 - 1`. + Index { #[codec(compact)] id: u128 }, + + /// A 4-byte fixed-length datum. + Array4([u8; 4]), + + /// An 8-byte fixed-length datum. + Array8([u8; 8]), + + /// A 16-byte fixed-length datum. + Array16([u8; 16]), + + /// A 32-byte fixed-length datum. + Array32([u8; 32]), + + /// An arbitrary piece of data. Use only when necessary. + Blob(Vec<u8>), +} + +/// A single general identifier for an asset. +/// +/// Represents both fungible and non-fungible assets. May only be used to represent a single asset class. +/// +/// Wildcards may or may not be allowed by the interpreting context. +/// +/// Assets classes may be identified in one of two ways: either an abstract identifier or a concrete identifier. +/// Implementations may support only one of these. A single asset may be referenced from multiple asset identifiers, +/// though will tend to have only a single *preferred* identifier. +/// +/// ### Abstract identifiers +/// +/// Abstract identifiers are absolute identifiers that represent a notional asset which can exist within multiple +/// consensus systems. These tend to be simpler to deal with since their broad meaning is unchanged regardless stay of +/// the consensus system in which it is interpreted. +/// +/// However, in the attempt to provide uniformity across consensus systems, they may conflate different instantiations +/// of some notional asset (e.g. the reserve asset and a local reserve-backed derivative of it) under the same name, +/// leading to confusion. It also implies that one notional asset is accounted for locally in only one way. This may not +/// be the case, e.g. where there are multiple bridge instances each providing a bridged "BTC" token yet none being +/// fungible between the others. +/// +/// Since they are meant to be absolute and universal, a global registry is needed to ensure that name collisions do not +/// occur. +/// +/// An abstract identifier is represented as a simple variable-size byte string. As of writing, no global registry +/// exists and no proposals have been put forth for asset labeling. +/// +/// ### Concrete identifiers +/// +/// Concrete identifiers are *relative identifiers* that specifically identify a single asset through its location in a +/// consensus system relative to the context interpreting. Use of a `MultiLocation` ensures that similar but non +/// fungible variants of the same underlying asset can be properly distinguished, and obviates the need for any kind of +/// central registry. +/// +/// The limitation is that the asset identifier cannot be trivially copied between consensus systems and must instead be +/// "re-anchored" whenever being moved to a new consensus system, using the two systems' relative paths. +/// +/// Throughout XCM, messages are authored such that *when interpreted from the receiver's point of view* they will have +/// the desired meaning/effect. This means that relative paths should always by constructed to be read from the point of +/// view of the receiving system, *which may be have a completely different meaning in the authoring system*. +/// +/// Concrete identifiers are the preferred way of identifying an asset since they are entirely unambiguous. +/// +/// A concrete identifier is represented by a `MultiLocation`. If a system has an unambiguous primary asset (such as +/// Bitcoin with BTC or Ethereum with ETH), then it will conventionally be identified as the chain itself. Alternative +/// and more specific ways of referring to an asset within a system include: +/// +/// - `<chain>/PalletInstance(<id>)` for a Frame chain with a single-asset pallet instance (such as an instance of the +/// Balances pallet). +/// - `<chain>/PalletInstance(<id>)/GeneralIndex(<index>)` for a Frame chain with an indexed multi-asset pallet instance +/// (such as an instance of the Assets pallet). +/// - `<chain>/AccountId32` for an ERC-20-style single-asset smart-contract on a Frame-based contracts chain. +/// - `<chain>/AccountKey20` for an ERC-20-style single-asset smart-contract on an Ethereum-like chain. +/// +#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug)] +pub enum MultiAsset { + /// No assets. Rarely used. + None, + + /// All assets. Typically used for the subset of assets to be used for an `Order`, and in that context means + /// "all assets currently in holding". + All, + + /// All fungible assets. Typically used for the subset of assets to be used for an `Order`, and in that context + /// means "all fungible assets currently in holding". + AllFungible, + + /// All non-fungible assets. Typically used for the subset of assets to be used for an `Order`, and in that + /// context means "all non-fungible assets currently in holding". + AllNonFungible, + + /// All fungible assets of a given abstract asset `id`entifier. + AllAbstractFungible { id: Vec<u8> }, + + /// All non-fungible assets of a given abstract asset `class`. + AllAbstractNonFungible { class: Vec<u8> }, + + /// All fungible assets of a given concrete asset `id`entifier. + AllConcreteFungible { id: MultiLocation }, + + /// All non-fungible assets of a given concrete asset `class`. + AllConcreteNonFungible { class: MultiLocation }, + + /// Some specific `amount` of the fungible asset identified by an abstract `id`. + AbstractFungible { id: Vec<u8>, #[codec(compact)] amount: u128 }, + + /// Some specific `instance` of the non-fungible asset whose `class` is identified abstractly. + AbstractNonFungible { class: Vec<u8>, instance: AssetInstance }, + + /// Some specific `amount` of the fungible asset identified by an concrete `id`. + ConcreteFungible { id: MultiLocation, #[codec(compact)] amount: u128 }, + + /// Some specific `instance` of the non-fungible asset whose `class` is identified concretely. + ConcreteNonFungible { class: MultiLocation, instance: AssetInstance }, +} + +impl MultiAsset { + /// Returns `true` if the `MultiAsset` is a wildcard and can refer to classes of assets, instead of just one. + /// + /// Typically can also be inferred by the name starting with `All`. + pub fn is_wildcard(&self) -> bool { + match self { + MultiAsset::None + | MultiAsset::AbstractFungible {..} + | MultiAsset::AbstractNonFungible {..} + | MultiAsset::ConcreteFungible {..} + | MultiAsset::ConcreteNonFungible {..} + => false, + + MultiAsset::All + | MultiAsset::AllFungible + | MultiAsset::AllNonFungible + | MultiAsset::AllAbstractFungible {..} + | MultiAsset::AllConcreteFungible {..} + | MultiAsset::AllAbstractNonFungible {..} + | MultiAsset::AllConcreteNonFungible {..} + => true, + } + } + + fn is_none(&self) -> bool { + match self { + MultiAsset::None + | MultiAsset::AbstractFungible { amount: 0, .. } + | MultiAsset::ConcreteFungible { amount: 0, .. } + => true, + + _ => false, + } + } + + fn is_fungible(&self) -> bool { + match self { + MultiAsset::All + | MultiAsset::AllFungible + | MultiAsset::AllAbstractFungible {..} + | MultiAsset::AllConcreteFungible {..} + | MultiAsset::AbstractFungible {..} + | MultiAsset::ConcreteFungible {..} + => true, + + _ => false, + } + } + + fn is_non_fungible(&self) -> bool { + match self { + MultiAsset::All + | MultiAsset::AllNonFungible + | MultiAsset::AllAbstractNonFungible {..} + | MultiAsset::AllConcreteNonFungible {..} + | MultiAsset::AbstractNonFungible {..} + | MultiAsset::ConcreteNonFungible {..} + => true, + + _ => false, + } + } + + fn is_concrete_fungible(&self, id: &MultiLocation) -> bool { + match self { + MultiAsset::AllFungible => true, + MultiAsset::AllConcreteFungible { id: i } + | MultiAsset::ConcreteFungible { id: i, .. } + => i == id, + + _ => false, + } + } + + fn is_abstract_fungible(&self, id: &[u8]) -> bool { + match self { + MultiAsset::AllFungible => true, + MultiAsset::AllAbstractFungible { id: i } + | MultiAsset::AbstractFungible { id: i, .. } + => i == id, + _ => false, + } + } + + fn is_concrete_non_fungible(&self, class: &MultiLocation) -> bool { + match self { + MultiAsset::AllNonFungible => true, + MultiAsset::AllConcreteNonFungible { class: i } + | MultiAsset::ConcreteNonFungible { class: i, .. } + => i == class, + _ => false, + } + } + + fn is_abstract_non_fungible(&self, class: &[u8]) -> bool { + match self { + MultiAsset::AllNonFungible => true, + MultiAsset::AllAbstractNonFungible { class: i } + | MultiAsset::AbstractNonFungible { class: i, .. } + => i == class, + _ => false, + } + } + + fn is_all(&self) -> bool { matches!(self, MultiAsset::All) } + + /// Returns true if `self` is a super-set of the given `inner`. + /// + /// Typically, any wildcard is never contained in anything else, and a wildcard can contain any other non-wildcard. + /// For more details, see the implementation and tests. + pub fn contains(&self, inner: &MultiAsset) -> bool { + use MultiAsset::*; + + // Inner cannot be wild + if inner.is_wildcard() { return false } + // Everything contains nothing. + if inner.is_none() { return true } + + // Everything contains anything. + if self.is_all() { return true } + // Nothing contains nothing. + if self.is_none() { return false } + + match self { + // Anything fungible contains "all fungibles" + AllFungible => inner.is_fungible(), + // Anything non-fungible contains "all non-fungibles" + AllNonFungible => inner.is_non_fungible(), + + AllConcreteFungible { id } => inner.is_concrete_fungible(id), + AllAbstractFungible { id } => inner.is_abstract_fungible(id), + AllConcreteNonFungible { class } => inner.is_concrete_non_fungible(class), + AllAbstractNonFungible { class } => inner.is_abstract_non_fungible(class), + + ConcreteFungible { id, amount } => matches!( + inner, + ConcreteFungible { id: inner_id , amount: inner_amount } if inner_id == id && amount >= inner_amount + ), + AbstractFungible { id, amount } => matches!( + inner, + AbstractFungible { id: inner_id , amount: inner_amount } if inner_id == id && amount >= inner_amount + ), + ConcreteNonFungible { .. } => self == inner, + AbstractNonFungible { .. } => self == inner, + _ => false, + } + } + + pub fn reanchor(&mut self, prepend: &MultiLocation) -> Result<(), ()> { + use MultiAsset::*; + match self { + AllConcreteFungible { ref mut id } + | AllConcreteNonFungible { class: ref mut id } + | ConcreteFungible { ref mut id, .. } + | ConcreteNonFungible { class: ref mut id, .. } + => id.prepend_with(prepend.clone()).map_err(|_| ()), + _ => Ok(()), + } + } +} + +impl From<MultiAsset> for VersionedMultiAsset { + fn from(x: MultiAsset) -> Self { + VersionedMultiAsset::V1(x) + } +} + +impl TryFrom<VersionedMultiAsset> for MultiAsset { + type Error = (); + fn try_from(x: VersionedMultiAsset) -> result::Result<Self, ()> { + match x { + VersionedMultiAsset::V1(x) => Ok(x), + _ => Err(()), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn contains_works() { + use alloc::vec; + use MultiAsset::*; + // trivial case: all contains any non-wildcard. + assert!(All.contains(&None)); + assert!(All.contains(&AbstractFungible { id: alloc::vec![99u8], amount: 1 })); + + // trivial case: none contains nothing, except itself. + assert!(None.contains(&None)); + assert!(!None.contains(&AllFungible)); + assert!(!None.contains(&All)); + + // A bit more sneaky: Nothing can contain wildcard, even All ir the thing itself. + assert!(!All.contains(&All)); + assert!(!All.contains(&AllFungible)); + assert!(!AllFungible.contains(&AllFungible)); + assert!(!AllNonFungible.contains(&AllNonFungible)); + + // For fungibles, containing is basically equality, or equal id with higher amount. + assert!( + !AbstractFungible { id: vec![99u8], amount: 99 } + .contains(&AbstractFungible { id: vec![1u8], amount: 99 }) + ); + assert!( + AbstractFungible { id: vec![99u8], amount: 99 } + .contains(&AbstractFungible { id: vec![99u8], amount: 99 }) + ); + assert!( + AbstractFungible { id: vec![99u8], amount: 99 } + .contains(&AbstractFungible { id: vec![99u8], amount: 9 }) + ); + assert!( + !AbstractFungible { id: vec![99u8], amount: 99 } + .contains(&AbstractFungible { id: vec![99u8], amount: 100 }) + ); + + // For non-fungibles, containing is equality. + assert!( + !AbstractNonFungible {class: vec![99u8], instance: AssetInstance::Index { id: 9 } } + .contains(&AbstractNonFungible { class: vec![98u8], instance: AssetInstance::Index { id: 9 } }) + ); + assert!( + !AbstractNonFungible { class: vec![99u8], instance: AssetInstance::Index { id: 8 } } + .contains(&AbstractNonFungible { class: vec![99u8], instance: AssetInstance::Index { id: 9 } }) + ); + assert!( + AbstractNonFungible { class: vec![99u8], instance: AssetInstance::Index { id: 9 } } + .contains(&AbstractNonFungible { class: vec![99u8], instance: AssetInstance::Index { id: 9 } }) + ); + } +} diff --git a/xcm/src/v1/multi_location.rs b/xcm/src/v1/multi_location.rs new file mode 100644 index 000000000000..ecffb26f8838 --- /dev/null +++ b/xcm/src/v1/multi_location.rs @@ -0,0 +1,867 @@ +// Copyright 2021 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 <http://www.gnu.org/licenses/>. + +//! Cross-Consensus Message format data structures. + +use core::{convert::TryFrom, mem, result}; + +use parity_scale_codec::{self, Encode, Decode}; +use super::Junction; +use crate::VersionedMultiLocation; + +/// A relative path between state-bearing consensus systems. +/// +/// A location in a consensus system is defined as an *isolatable state machine* held within global consensus. The +/// location in question need not have a sophisticated consensus algorithm of its own; a single account within +/// Ethereum, for example, could be considered a location. +/// +/// A very-much non-exhaustive list of types of location include: +/// - A (normal, layer-1) block chain, e.g. the Bitcoin mainnet or a parachain. +/// - A layer-0 super-chain, e.g. the Polkadot Relay chain. +/// - A layer-2 smart contract, e.g. an ERC-20 on Ethereum. +/// - A logical functional component of a chain, e.g. a single instance of a pallet on a Frame-based Substrate chain. +/// - An account. +/// +/// 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. +/// +/// This specific `MultiLocation` implementation uses a Rust `enum` in order to make pattern matching easier. +/// +/// The `MultiLocation` value of `Null` simply refers to the interpreting consensus system. +#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug)] +pub struct MultiLocation { + parents: u8, + junctions: Junctions, +} + +/// Maximum number of junctions a multilocation can contain. +pub const MAX_MULTILOCATION_LENGTH: usize = 8; + +impl MultiLocation { + /// Creates a new MultiLocation, ensuring that the length of it does not exceed the maximum, + /// otherwise returns `Err`. + pub fn new(parents: u8, junctions: Junctions) -> result::Result<MultiLocation, ()> { + if parents as usize + junctions.len() > MAX_MULTILOCATION_LENGTH { + return Err(()) + } + Ok(MultiLocation { + parents, + junctions, + }) + } + + /// Return a reference to the junctions field. + pub fn junctions(&self) -> &Junctions { + &self.junctions + } + + /// Return a mutable reference to the junctions field. + pub fn junctions_mut(&mut self) -> &mut Junctions { + &mut self.junctions + } + + /// Returns the number of `Parent` junctions at the beginning of `self`. + pub fn parent_count(&self) -> usize { + self.parents as usize + } + + /// Returns the number of parents and junctions in `self`. + pub fn len(&self) -> usize { + self.parent_count() + self.junctions.len() + } + + /// Returns first junction that is not a parent, or `None` if the location is empty or + /// contains only parents. + pub fn first_non_parent(&self) -> Option<&Junction> { + self.junctions.first() + } + + /// Returns last junction, or `None` if the location is empty or contains only parents. + pub fn last(&self) -> Option<&Junction> { + self.junctions.last() + } + + /// Splits off the first non-parent 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_non_parent(self) -> (MultiLocation, Option<Junction>) { + let MultiLocation { parents, junctions } = self; + let (prefix, suffix) = junctions.split_first(); + let multilocation = MultiLocation { + parents, + junctions: prefix, + }; + (multilocation, suffix) + } + + /// 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 or that `self` only contains parents. + pub fn split_last(self) -> (MultiLocation, Option<Junction>) { + let MultiLocation { parents, junctions } = self; + let (prefix, suffix) = junctions.split_last(); + let multilocation = MultiLocation { + parents, + junctions: prefix, + }; + (multilocation, suffix) + } + + /// Bumps the parent count up by 1. Returns `Err` in case of overflow. + pub fn push_parent(&mut self) -> result::Result<(), ()> { + if self.len() >= MAX_MULTILOCATION_LENGTH { + return Err(()) + } + self.parents = self.parents.saturating_add(1); + Ok(()) + } + + /// Mutates `self`, suffixing its non-parent junctions with `new`. Returns `Err` in case of overflow. + pub fn push_non_parent(&mut self, new: Junction) -> result::Result<(), ()> { + let mut n = Junctions::Null; + mem::swap(&mut self.junctions, &mut n); + match n.pushed_with(new) { + Ok(result) => { self.junctions = result; Ok(()) } + Err(old) => { self.junctions = old; Err(()) } + } + } + + /// Mutates `self`, prefixing its non-parent junctions with `new`. Returns `Err` in case of overflow. + pub fn push_front_non_parent(&mut self, new: Junction) -> result::Result<(), ()> { + let mut n = Junctions::Null; + mem::swap(&mut self.junctions, &mut n); + match n.pushed_front_with(new) { + Ok(result) => { self.junctions = result; Ok(()) } + Err(old) => { self.junctions = old; Err(()) } + } + } + + /// Consumes `self` and returns a `MultiLocation` with its parent count incremented by 1, or + /// an `Err` with the original value of `self` in case of overflow. + pub fn pushed_with_parent(self) -> result::Result<Self, Self> { + if self.len() >= MAX_MULTILOCATION_LENGTH { + return Err(self) + } + Ok(MultiLocation { + parents: self.parents.saturating_add(1), + ..self + }) + } + + /// 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_non_parent(self, new: Junction) -> result::Result<Self, Self> { + if self.len() >= MAX_MULTILOCATION_LENGTH { + return Err(self) + } + Ok(MultiLocation { + parents: self.parents, + junctions: self.junctions.pushed_with(new).expect("length is less than max length; qed"), + }) + } + + /// 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_non_parent(self, new: Junction) -> result::Result<Self, Self> { + if self.len() >= MAX_MULTILOCATION_LENGTH { + return Err(self) + } + Ok(MultiLocation { + parents: self.parents, + junctions: self.junctions.pushed_front_with(new).expect("length is less than max length; qed"), + }) + } + + /// 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.junctions.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.junctions.at_mut(i - num_parents) + } + + /// Decrement the parent count by 1. + pub fn pop_parent(&mut self) { + self.parents = self.parents.saturating_sub(1); + } + + /// Removes the first non-parent element from `self`, returning it + /// (or `None` if it was empty or if `self` contains only parents). + pub fn take_first_non_parent(&mut self) -> Option<Junction> { + self.junctions.take_first() + } + + /// Removes the last element from `junctions`, returning it (or `None` if it was empty or if + /// `self` only contains parents). + pub fn take_last(&mut self) -> Option<Junction> { + self.junctions.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)).unwrap(); + /// assert_eq!( + /// m.match_and_split(&MultiLocation::new(1, X1(PalletInstance(3))).unwrap()), + /// Some(&OnlyChild), + /// ); + /// assert_eq!(m.match_and_split(&MultiLocation::new(1, Null).unwrap()), None); + /// # } + /// ``` + pub fn match_and_split(&self, prefix: &MultiLocation) -> Option<&Junction> { + if self.parents != prefix.parents { + return None + } + self.junctions.match_and_split(&prefix.junctions) + } + + /// 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)).unwrap(); + /// assert_eq!(m.append_with(MultiLocation::new(1, X1(PalletInstance(3))).unwrap()), Ok(())); + /// assert_eq!(m, MultiLocation::new(1, X2(Parachain(21), PalletInstance(3))).unwrap()); + /// # } + /// ``` + 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))).unwrap(); + /// assert_eq!(m.prepend_with(MultiLocation::new(1, X2(Parachain(21), OnlyChild)).unwrap()), Ok(())); + /// assert_eq!(m, MultiLocation::new(1, X1(PalletInstance(3))).unwrap()); + /// # } + /// ``` + pub fn prepend_with(&mut self, mut prefix: MultiLocation) -> Result<(), MultiLocation> { + let self_parents = self.parent_count(); + let prepend_len = (self_parents as isize - prefix.junctions.len() as isize).abs() as usize; + if self.junctions.len() + prefix.parent_count() + prepend_len > MAX_MULTILOCATION_LENGTH { + return Err(prefix) + } + + let mut final_parent_count = prefix.parents; + for _ in 0..self_parents { + if prefix.take_last().is_none() { + // If true, this means self parent count is greater than prefix junctions length; + // add the resulting self parent count to final_parent_count + final_parent_count += self.parents; + break + } + self.pop_parent(); + } + + self.parents = final_parent_count; + for j in prefix.junctions.into_iter_rev() { + self.push_front_non_parent(j).expect( + "self junctions len + prefix parent count + prepend len is less than max length; qed" + ); + } + Ok(()) + } +} + +impl From<Junctions> for MultiLocation { + fn from(junctions: Junctions) -> Self { + MultiLocation { + parents: 0, + junctions, + } + } +} + +impl From<Junction> for MultiLocation { + fn from(x: Junction) -> Self { + MultiLocation { + parents: 0, + junctions: Junctions::X1(x), + } + } +} + +impl From<()> for MultiLocation { + fn from(_: ()) -> Self { + MultiLocation { + parents: 0, + junctions: Junctions::Null, + } + } +} +impl From<(Junction,)> for MultiLocation { + fn from(x: (Junction,)) -> Self { + MultiLocation { + parents: 0, + junctions: Junctions::X1(x.0), + } + } +} +impl From<(Junction, Junction)> for MultiLocation { + fn from(x: (Junction, Junction)) -> Self { + MultiLocation { + parents: 0, + junctions: Junctions::X2(x.0, x.1), + } + } +} +impl From<(Junction, Junction, Junction)> for MultiLocation { + fn from(x: (Junction, Junction, Junction)) -> Self { + MultiLocation { + parents: 0, + junctions: 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 { + parents: 0, + junctions: 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 { + parents: 0, + junctions: 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 { + parents: 0, + junctions: 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 { + parents: 0, + junctions: 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)> for MultiLocation { + fn from(x: (Junction, Junction, Junction, Junction, Junction, Junction, Junction, Junction)) -> Self { + MultiLocation { + parents: 0, + junctions: Junctions::X8(x.0, x.1, x.2, x.3, x.4, x.5, x.6, x.7), + } + } +} + +impl From<[Junction; 0]> for MultiLocation { + fn from(_: [Junction; 0]) -> Self { + MultiLocation { + parents: 0, + junctions: Junctions::Null, + } + } +} +impl From<[Junction; 1]> for MultiLocation { + fn from(x: [Junction; 1]) -> Self { + let [x0] = x; + MultiLocation { + parents: 0, + junctions: Junctions::X1(x0), + } + } +} +impl From<[Junction; 2]> for MultiLocation { + fn from(x: [Junction; 2]) -> Self { + let [x0, x1] = x; + MultiLocation { + parents: 0, + junctions: Junctions::X2(x0, x1), + } + } +} +impl From<[Junction; 3]> for MultiLocation { + fn from(x: [Junction; 3]) -> Self { + let [x0, x1, x2] = x; + MultiLocation { + parents: 0, + junctions: Junctions::X3(x0, x1, x2), + } + } +} +impl From<[Junction; 4]> for MultiLocation { + fn from(x: [Junction; 4]) -> Self { + let [x0, x1, x2, x3] = x; + MultiLocation { + parents: 0, + junctions: 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 { + parents: 0, + junctions: 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 { + parents: 0, + junctions: 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 { + parents: 0, + junctions: 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 { + parents: 0, + junctions: Junctions::X8(x0, x1, x2, x3, x4, x5, x6, x7), + } + } +} + +#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug)] +pub enum Junctions { + /// The interpreting consensus system. + Null, + /// 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<Junction> { + self.0.take_first() + } +} + +pub struct JunctionsReverseIterator(Junctions); +impl Iterator for JunctionsReverseIterator { + type Item = Junction; + fn next(&mut self) -> Option<Junction> { + self.0.take_last() + } +} + +pub struct JunctionsRefIterator<'a>(&'a Junctions, 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; + result + } +} + +pub struct JunctionsReverseRefIterator<'a>(&'a Junctions, usize); +impl<'a> Iterator for JunctionsReverseRefIterator<'a> { + type Item = &'a Junction; + fn next(&mut self) -> Option<&'a Junction> { + self.1 += 1; + self.0.at(self.0.len().checked_sub(self.1)?) + } +} + +impl Junctions { + /// Returns first junction, or `None` if the location is empty. + pub fn first(&self) -> Option<&Junction> { + match &self { + Junctions::Null => 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 { + Junctions::Null => 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) -> (Junctions, Option<Junction>) { + match self { + Junctions::Null => (Junctions::Null, None), + Junctions::X1(a) => (Junctions::Null, 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) -> (Junctions, Option<Junction>) { + match self { + Junctions::Null => (Junctions::Null, None), + Junctions::X1(a) => (Junctions::Null, 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<Junction> { + let mut d = Junctions::Null; + mem::swap(&mut *self, &mut d); + let (tail, head) = d.split_first(); + *self = tail; + head + } + + /// Removes the last element from `self`, returning it (or `None` if it was empty). + pub fn take_last(&mut self) -> Option<Junction> { + let mut d = Junctions::Null; + mem::swap(&mut *self, &mut d); + let (head, tail) = d.split_last(); + *self = head; + tail + } + + /// 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<Self, Self> { + Ok(match self { + Junctions::Null => 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 `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<Self, Self> { + Ok(match self { + Junctions::Null => 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 { + match &self { + Junctions::Null => 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, 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, + }) + } + + /// Returns a mutable reference to the junction at index `i`, or `None` if the location doesn't contain that many + /// elements. + pub fn at_mut(&mut self, i: usize) -> Option<&mut Junction> { + Some(match (i, self) { + (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) -> JunctionsRefIterator { + JunctionsRefIterator(&self, 0) + } + + /// Returns a reference iterator over the junctions in reverse. + pub fn iter_rev(&self) -> JunctionsReverseRefIterator { + JunctionsReverseRefIterator(&self, 0) + } + + /// Consumes `self` and returns an iterator over the junctions. + pub fn into_iter(self) -> JunctionsIterator { + JunctionsIterator(self) + } + + /// Consumes `self` and returns an iterator over the junctions in reverse. + pub fn into_iter_rev(self) -> JunctionsReverseIterator { + JunctionsReverseIterator(self) + } + + /// Ensures that self begins with `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::*}; + /// # fn main() { + /// 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: &Junctions) -> Option<&Junction> { + if prefix.len() + 1 != self.len() { + return None + } + for i in 0..prefix.len() { + if prefix.at(i) != self.at(i) { + return None + } + } + return self.at(prefix.len()) + } +} + +impl From<MultiLocation> for VersionedMultiLocation { + fn from(x: MultiLocation) -> Self { + VersionedMultiLocation::V1(x) + } +} + +impl TryFrom<VersionedMultiLocation> for MultiLocation { + type Error = (); + fn try_from(x: VersionedMultiLocation) -> result::Result<Self, ()> { + match x { + VersionedMultiLocation::V1(x) => Ok(x), + _ => Err(()), + } + } +} + +#[cfg(test)] +mod tests { + use super::{Junctions::*, MultiLocation}; + use crate::opaque::v1::{Junction::*, NetworkId::Any}; + + #[test] + fn match_and_split_works() { + let m = MultiLocation { parents: 1, junctions: X2(Parachain(42), AccountIndex64 { network: Any, index: 23 }) }; + assert_eq!(m.match_and_split(&MultiLocation { parents: 1, junctions: Null }), None); + assert_eq!( + m.match_and_split(&MultiLocation { parents: 1, junctions: X1(Parachain(42)) }), + Some(&AccountIndex64 { network: Any, index: 23 }) + ); + assert_eq!(m.match_and_split(&m), None); + } + + #[test] + fn append_with_works() { + let acc = AccountIndex64 { network: Any, index: 23 }; + let mut m = MultiLocation { parents: 1, junctions: X1(Parachain(42)) }; + assert_eq!(m.append_with(MultiLocation::from(X2(PalletInstance(3), acc.clone()))), Ok(())); + assert_eq!(m, MultiLocation { parents: 1, junctions: X3(Parachain(42), PalletInstance(3), acc.clone()) }); + + // cannot append to create overly long multilocation + let acc = AccountIndex64 { network: Any, index: 23 }; + let mut m = MultiLocation { parents: 6, junctions: X1(Parachain(42)) }; + let suffix = MultiLocation::from(X2(PalletInstance(3), acc.clone())); + assert_eq!(m.append_with(suffix.clone()), Err(suffix)); + } + + #[test] + fn prepend_with_works() { + let mut m = MultiLocation { parents: 1, junctions: X2(Parachain(42), AccountIndex64 { network: Any, index: 23 }) }; + assert_eq!(m.prepend_with(MultiLocation { parents: 1, junctions: X1(OnlyChild) }), Ok(())); + assert_eq!(m, MultiLocation { parents: 1, junctions: X2(Parachain(42), AccountIndex64 { network: Any, index: 23 }) }); + + // cannot prepend to create overly long multilocation + let mut m = MultiLocation { parents: 6, junctions: X1(Parachain(42)) }; + let prefix = MultiLocation { parents: 2, junctions: Null }; + assert_eq!(m.prepend_with(prefix.clone()), Err(prefix)); + + let prefix = MultiLocation { parents: 1, junctions: Null }; + assert_eq!(m.prepend_with(prefix), Ok(())); + assert_eq!(m, MultiLocation { parents: 7, junctions: X1(Parachain(42)) }); + } +} diff --git a/xcm/src/v1/order.rs b/xcm/src/v1/order.rs new file mode 100644 index 000000000000..f1e48c3b90c2 --- /dev/null +++ b/xcm/src/v1/order.rs @@ -0,0 +1,140 @@ +// Copyright 2021 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 <http://www.gnu.org/licenses/>. + +//! Version 1 of the Cross-Consensus Message format data structures. + +use alloc::vec::Vec; +use derivative::Derivative; +use parity_scale_codec::{self, Encode, Decode}; +use super::{MultiAsset, MultiLocation, Xcm}; + +/// An instruction to be executed on some or all of the assets in holding, used by asset-related XCM messages. +#[derive(Derivative, Encode, Decode)] +#[derivative(Clone(bound=""), Eq(bound=""), PartialEq(bound=""), Debug(bound=""))] +#[codec(encode_bound())] +#[codec(decode_bound())] +pub enum Order<Call> { + /// Do nothing. Not generally used. + #[codec(index = 0)] + Null, + + /// Remove the asset(s) (`assets`) from holding and place equivalent assets under the ownership of `dest` within + /// this consensus system. + /// + /// - `assets`: The asset(s) to remove from holding. + /// - `dest`: The new owner for the assets. + /// + /// Errors: + #[codec(index = 1)] + DepositAsset { assets: Vec<MultiAsset>, dest: MultiLocation }, + + /// Remove the asset(s) (`assets`) from holding and place equivalent assets under the ownership of `dest` within + /// this consensus system. + /// + /// Send an onward XCM message to `dest` of `ReserveAssetDeposit` with the given `effects`. + /// + /// - `assets`: The asset(s) to remove from holding. + /// - `dest`: The new owner for the assets. + /// - `effects`: The orders that should be contained in the `ReserveAssetDeposit` which is sent onwards to + /// `dest. + /// + /// Errors: + #[codec(index = 2)] + DepositReserveAsset { assets: Vec<MultiAsset>, dest: MultiLocation, effects: Vec<Order<()>> }, + + /// Remove the asset(s) (`give`) from holding and replace them with alternative assets. + /// + /// The minimum amount of assets to be received into holding for the order not to fail may be stated. + /// + /// - `give`: The asset(s) to remove from holding. + /// - `receive`: The minimum amount of assets(s) which `give` should be exchanged for. The meaning of wildcards + /// is undefined and they should be not be used. + /// + /// Errors: + #[codec(index = 3)] + ExchangeAsset { give: Vec<MultiAsset>, receive: Vec<MultiAsset> }, + + /// Remove the asset(s) (`assets`) from holding and send a `WithdrawAsset` XCM message to a reserve location. + /// + /// - `assets`: The asset(s) to remove from holding. + /// - `reserve`: A valid location that acts as a reserve for all asset(s) in `assets`. The sovereign account + /// of this consensus system *on the reserve location* will have appropriate assets withdrawn and `effects` will + /// be executed on them. There will typically be only one valid location on any given asset/chain combination. + /// - `effects`: The orders to execute on the assets once withdrawn *on the reserve location*. + /// + /// Errors: + #[codec(index = 4)] + InitiateReserveWithdraw { assets: Vec<MultiAsset>, reserve: MultiLocation, effects: Vec<Order<()>> }, + + /// Remove the asset(s) (`assets`) from holding and send a `TeleportAsset` XCM message to a destination location. + /// + /// - `assets`: The asset(s) to remove from holding. + /// - `destination`: A valid location that has a bi-lateral teleportation arrangement. + /// - `effects`: The orders to execute on the assets once arrived *on the destination location*. + /// + /// Errors: + #[codec(index = 5)] + InitiateTeleport { assets: Vec<MultiAsset>, dest: MultiLocation, effects: Vec<Order<()>> }, + + /// Send a `Balances` XCM message with the `assets` value equal to the holding contents, or a portion thereof. + /// + /// - `query_id`: An identifier that will be replicated into the returned XCM message. + /// - `dest`: A valid destination for the returned XCM message. This may be limited to the current origin. + /// - `assets`: A filter for the assets that should be reported back. The assets reported back will be, asset- + /// wise, *the lesser of this value and the holding account*. No wildcards will be used when reporting assets + /// back. + /// + /// Errors: + #[codec(index = 6)] + QueryHolding { #[codec(compact)] query_id: u64, dest: MultiLocation, assets: Vec<MultiAsset> }, + + /// Pay for the execution of some Xcm with up to `weight` picoseconds of execution time, paying for this with + /// up to `fees` from the holding account. + /// + /// Errors: + #[codec(index = 7)] + BuyExecution { fees: MultiAsset, weight: u64, debt: u64, halt_on_error: bool, xcm: Vec<Xcm<Call>> }, +} + +pub mod opaque { + pub type Order = super::Order<()>; +} + +impl<Call> Order<Call> { + pub fn into<C>(self) -> Order<C> { Order::from(self) } + pub fn from<C>(order: Order<C>) -> Self { + use Order::*; + match order { + Null => Null, + DepositAsset { assets, dest } + => DepositAsset { assets, dest }, + DepositReserveAsset { assets, dest, effects } + => DepositReserveAsset { assets, dest, effects }, + ExchangeAsset { give, receive } + => ExchangeAsset { give, receive }, + InitiateReserveWithdraw { assets, reserve, effects } + => InitiateReserveWithdraw { assets, reserve, effects }, + InitiateTeleport { assets, dest, effects } + => InitiateTeleport { assets, dest, effects }, + QueryHolding { query_id, dest, assets } + => QueryHolding { query_id, dest, assets }, + BuyExecution { fees, weight, debt, halt_on_error, xcm } => { + let xcm = xcm.into_iter().map(Xcm::from).collect(); + BuyExecution { fees, weight, debt, halt_on_error, xcm } + }, + } + } +} diff --git a/xcm/src/v1/traits.rs b/xcm/src/v1/traits.rs new file mode 100644 index 000000000000..6f3dccce1630 --- /dev/null +++ b/xcm/src/v1/traits.rs @@ -0,0 +1,246 @@ +// Copyright 2021 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 <http://www.gnu.org/licenses/>. + +//! Cross-Consensus Message format data structures. + +use core::result; +use parity_scale_codec::{Encode, Decode}; + +use super::{MultiLocation, Xcm}; + +#[derive(Clone, Encode, Decode, Eq, PartialEq, Debug)] +pub enum Error { + Undefined, + Overflow, + /// The operation is intentionally unsupported. + Unimplemented, + UnhandledXcmVersion, + UnhandledXcmMessage, + UnhandledEffect, + EscalationOfPrivilege, + UntrustedReserveLocation, + UntrustedTeleportLocation, + DestinationBufferOverflow, + /// The message and destination was recognized as being reachable but the operation could not be completed. + /// A human-readable explanation of the specific issue is provided. + SendFailed(#[codec(skip)] &'static str), + /// The message and destination combination was not recognized as being reachable. + CannotReachDestination(MultiLocation, Xcm<()>), + MultiLocationFull, + FailedToDecode, + BadOrigin, + ExceedsMaxMessageSize, + FailedToTransactAsset(#[codec(skip)] &'static str), + /// Execution of the XCM would potentially result in a greater weight used than the pre-specified + /// weight limit. The amount that is potentially required is the parameter. + WeightLimitReached(Weight), + Wildcard, + /// The case where an XCM message has specified a optional weight limit and the weight required for + /// processing is too great. + /// + /// Used by: + /// - `Transact` + TooMuchWeightRequired, + /// The fees specified by the XCM message were not found in the holding account. + /// + /// Used by: + /// - `BuyExecution` + NotHoldingFees, + /// The weight of an XCM message is not computable ahead of execution. This generally means at least part + /// of the message is invalid, which could be due to it containing overly nested structures or an invalid + /// nested data segment (e.g. for the call in `Transact`). + WeightNotComputable, + /// The XCM did not pass the barrier condition for execution. The barrier condition differs on different + /// chains and in different circumstances, but generally it means that the conditions surrounding the message + /// were not such that the chain considers the message worth spending time executing. Since most chains + /// lift the barrier to execution on appropriate payment, presentation of an NFT voucher, or based on the + /// message origin, it means that none of those were the case. + Barrier, + /// Indicates that it is not possible for a location to have an asset be withdrawn or transferred from its + /// ownership. This probably means it doesn't own (enough of) it, but may also indicate that it is under a + /// lock, hold, freeze or is otherwise unavailable. + NotWithdrawable, + /// Indicates that the consensus system cannot deposit an asset under the ownership of a particular location. + LocationCannotHold, + /// The assets given to purchase weight is are insufficient for the weight desired. + TooExpensive, + /// The given asset is not handled. + AssetNotFound, +} + +impl From<()> for Error { + fn from(_: ()) -> Self { + Self::Undefined + } +} + +pub type Result = result::Result<(), Error>; + +/// Local weight type; execution time in picoseconds. +pub type Weight = u64; + +/// Outcome of an XCM execution. +#[derive(Clone, Encode, Decode, Eq, PartialEq, Debug)] +pub enum Outcome { + /// Execution completed successfully; given weight was used. + Complete(Weight), + /// Execution started, but did not complete successfully due to the given error; given weight was used. + Incomplete(Weight, Error), + /// Execution did not start due to the given error. + Error(Error), +} + +impl Outcome { + pub fn ensure_complete(self) -> Result { + match self { + Outcome::Complete(_) => Ok(()), + Outcome::Incomplete(_, e) => Err(e), + Outcome::Error(e) => Err(e), + } + } + pub fn ensure_execution(self) -> result::Result<Weight, Error> { + match self { + Outcome::Complete(w) => Ok(w), + Outcome::Incomplete(w, _) => Ok(w), + Outcome::Error(e) => Err(e), + } + } + /// How much weight was used by the XCM execution attempt. + pub fn weight_used(&self) -> Weight { + match self { + Outcome::Complete(w) => *w, + Outcome::Incomplete(w, _) => *w, + Outcome::Error(_) => 0, + } + } +} + +/// Type of XCM message executor. +pub trait ExecuteXcm<Call> { + /// Execute some XCM `message` from `origin` using no more than `weight_limit` weight. The weight limit is + /// a basic hard-limit and the implementation may place further restrictions or requirements on weight and + /// other aspects. + fn execute_xcm(origin: MultiLocation, message: Xcm<Call>, weight_limit: Weight) -> Outcome { + Self::execute_xcm_in_credit(origin, message, weight_limit, 0) + } + + /// Execute some XCM `message` from `origin` using no more than `weight_limit` weight. + /// + /// Some amount of `weight_credit` may be provided which, depending on the implementation, may allow + /// execution without associated payment. + fn execute_xcm_in_credit( + origin: MultiLocation, + message: Xcm<Call>, + weight_limit: Weight, + weight_credit: Weight, + ) -> Outcome; +} + +impl<C> ExecuteXcm<C> for () { + fn execute_xcm_in_credit( + _origin: MultiLocation, + _message: Xcm<C>, + _weight_limit: Weight, + _weight_credit: Weight, + ) -> Outcome { + Outcome::Error(Error::Unimplemented) + } +} + +/// Utility for sending an XCM message. +/// +/// These can be amalgamated in tuples to form sophisticated routing systems. In tuple format, each router might return +/// `CannotReachDestination` to pass the execution to the next sender item. Note that each `CannotReachDestination` +/// might alter the destination and the xcm message for to the next router. +/// +/// +/// # Example +/// ```rust +/// # use xcm::v0::{MultiLocation, Xcm, Junction, Error, OriginKind, SendXcm, Result}; +/// # use parity_scale_codec::Encode; +/// +/// /// A sender that only passes the message through and does nothing. +/// struct Sender1; +/// impl SendXcm for Sender1 { +/// fn send_xcm(destination: MultiLocation, message: Xcm<()>) -> Result { +/// return Err(Error::CannotReachDestination(destination, message)) +/// } +/// } +/// +/// /// A sender that accepts a message that has an X2 junction, otherwise stops the routing. +/// struct Sender2; +/// impl SendXcm for Sender2 { +/// fn send_xcm(destination: MultiLocation, message: Xcm<()>) -> Result { +/// if let MultiLocation::X2(j1, j2) = destination { +/// Ok(()) +/// } else { +/// Err(Error::Undefined) +/// } +/// } +/// } +/// +/// /// A sender that accepts a message from an X1 parent junction, passing through otherwise. +/// struct Sender3; +/// impl SendXcm for Sender3 { +/// fn send_xcm(destination: MultiLocation, message: Xcm<()>) -> Result { +/// match destination { +/// MultiLocation::X1(j) if j == Junction::Parent => Ok(()), +/// _ => Err(Error::CannotReachDestination(destination, message)), +/// } +/// } +/// } +/// +/// // A call to send via XCM. We don't really care about this. +/// # fn main() { +/// let call: Vec<u8> = ().encode(); +/// let message = Xcm::Transact { origin_type: OriginKind::Superuser, require_weight_at_most: 0, call: call.into() }; +/// let destination = MultiLocation::X1(Junction::Parent); +/// +/// assert!( +/// // Sender2 will block this. +/// <(Sender1, Sender2, Sender3) as SendXcm>::send_xcm(destination.clone(), message.clone()) +/// .is_err() +/// ); +/// +/// assert!( +/// // Sender3 will catch this. +/// <(Sender1, Sender3) as SendXcm>::send_xcm(destination.clone(), message.clone()) +/// .is_ok() +/// ); +/// # } +/// ``` +pub trait SendXcm { + /// Send an XCM `message` to a given `destination`. + /// + /// If it is not a destination which can be reached with this type but possibly could by others, then it *MUST* + /// return `CannotReachDestination`. Any other error will cause the tuple implementation to exit early without + /// trying other type fields. + fn send_xcm(destination: MultiLocation, message: Xcm<()>) -> Result; +} + +#[impl_trait_for_tuples::impl_for_tuples(30)] +impl SendXcm for Tuple { + fn send_xcm(destination: MultiLocation, message: Xcm<()>) -> Result { + for_tuples!( #( + // we shadow `destination` and `message` in each expansion for the next one. + let (destination, message) = match Tuple::send_xcm(destination, message) { + Err(Error::CannotReachDestination(d, m)) => (d, m), + o @ _ => return o, + }; + )* ); + Err(Error::CannotReachDestination(destination, message)) + } +} From 621e8737368257deacea7aa46da2e751539d775d Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Fri, 30 Jul 2021 09:09:39 -0700 Subject: [PATCH 003/166] Remove v1 module --- xcm/src/lib.rs | 11 - xcm/src/v0/junction.rs | 34 -- xcm/src/v0/mod.rs | 5 +- xcm/src/v0/multi_asset.rs | 1 - xcm/src/v0/multi_location.rs | 1025 ++++++++++++++++++---------------- xcm/src/v0/traits.rs | 17 +- xcm/src/v1/junction.rs | 133 ----- xcm/src/v1/mod.rs | 317 ----------- xcm/src/v1/multi_asset.rs | 380 ------------- xcm/src/v1/multi_location.rs | 867 ---------------------------- xcm/src/v1/order.rs | 140 ----- xcm/src/v1/traits.rs | 246 -------- 12 files changed, 563 insertions(+), 2613 deletions(-) delete mode 100644 xcm/src/v1/junction.rs delete mode 100644 xcm/src/v1/mod.rs delete mode 100644 xcm/src/v1/multi_asset.rs delete mode 100644 xcm/src/v1/multi_location.rs delete mode 100644 xcm/src/v1/order.rs delete mode 100644 xcm/src/v1/traits.rs diff --git a/xcm/src/lib.rs b/xcm/src/lib.rs index b2d8d3a2a487..1addc44bd552 100644 --- a/xcm/src/lib.rs +++ b/xcm/src/lib.rs @@ -27,7 +27,6 @@ use parity_scale_codec::{Encode, Decode}; use derivative::Derivative; pub mod v0; -pub mod v1; mod double_encoded; pub use double_encoded::DoubleEncoded; @@ -39,7 +38,6 @@ pub use double_encoded::DoubleEncoded; #[codec(decode_bound())] pub enum VersionedXcm<Call> { V0(v0::Xcm<Call>), - V1(v1::Xcm<Call>), } pub mod opaque { @@ -50,13 +48,6 @@ pub mod opaque { pub use crate::v0::opaque::{Xcm, Order}; } - pub mod v1 { - // Everything from v1 - pub use crate::v1::*; - // Then override with the opaque types in v1 - pub use crate::v1::opaque::{Xcm, Order}; - } - /// The basic `VersionedXcm` type which just uses the `Vec<u8>` as an encoded call. pub type VersionedXcm = super::VersionedXcm<()>; } @@ -65,12 +56,10 @@ pub mod opaque { #[derive(Clone, Eq, PartialEq, Encode, Decode, Debug)] pub enum VersionedMultiLocation { V0(v0::MultiLocation), - V1(v1::MultiLocation), } /// A versioned multi-asset, an identifier for an asset within a consensus system. #[derive(Clone, Eq, PartialEq, Encode, Decode, Debug)] pub enum VersionedMultiAsset { V0(v0::MultiAsset), - V1(v1::MultiAsset), } diff --git a/xcm/src/v0/junction.rs b/xcm/src/v0/junction.rs index b89c665a3903..3785e11b672c 100644 --- a/xcm/src/v0/junction.rs +++ b/xcm/src/v0/junction.rs @@ -86,11 +86,6 @@ impl BodyPart { /// 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 { - /// The consensus system of which the context is a member and state-wise super-set. - /// - /// NOTE: This item is *not* a sub-consensus item: a consensus system may not identify itself trustlessly as - /// a location that includes this junction. - Parent, /// An indexed parachain belonging to and operated by the context. /// /// Generally used when the context is a Polkadot Relay-chain. @@ -136,32 +131,3 @@ pub enum Junction { /// things such as multisigs also. Plurality { id: BodyId, part: BodyPart }, } - -impl Junction { - /// Returns true if this junction is a `Parent` item. - pub fn is_parent(&self) -> bool { - match self { - Junction::Parent => true, - _ => false, - } - } - - /// Returns true if this junction can be considered an interior part of its context. This is generally `true`, - /// except for the `Parent` item. - pub fn is_interior(&self) -> bool { - match self { - Junction::Parent => false, - - Junction::Parachain(..) - | Junction::AccountId32 { .. } - | Junction::AccountIndex64 { .. } - | Junction::AccountKey20 { .. } - | Junction::PalletInstance { .. } - | Junction::GeneralIndex { .. } - | Junction::GeneralKey(..) - | Junction::OnlyChild - | Junction::Plurality { .. } - => true, - } - } -} diff --git a/xcm/src/v0/mod.rs b/xcm/src/v0/mod.rs index 1263297aff2b..0ff166efb15a 100644 --- a/xcm/src/v0/mod.rs +++ b/xcm/src/v0/mod.rs @@ -29,7 +29,7 @@ mod order; mod traits; pub use junction::{Junction, NetworkId, BodyId, BodyPart}; pub use multi_asset::{MultiAsset, AssetInstance}; -pub use multi_location::MultiLocation; +pub use multi_location::{Junctions::{self, *}, MultiLocation}; pub use order::Order; pub use traits::{Error, Result, SendXcm, ExecuteXcm, Outcome}; @@ -37,7 +37,7 @@ pub use traits::{Error, Result, SendXcm, ExecuteXcm, Outcome}; pub mod prelude { pub use super::junction::{Junction::*, NetworkId, BodyId, BodyPart}; pub use super::multi_asset::{MultiAsset::{self, *}, AssetInstance::{self, *}}; - pub use super::multi_location::MultiLocation::{self, *}; + pub use super::multi_location::{Junctions::{self, *}, MultiLocation}; pub use super::order::Order::{self, *}; pub use super::traits::{Error as XcmError, Result as XcmResult, SendXcm, ExecuteXcm, Outcome}; pub use super::{Xcm::{self, *}, OriginKind}; @@ -272,7 +272,6 @@ impl<Call> TryFrom<VersionedXcm<Call>> for Xcm<Call> { fn try_from(x: VersionedXcm<Call>) -> result::Result<Self, ()> { match x { VersionedXcm::V0(x) => Ok(x), - _ => Err(()), } } } diff --git a/xcm/src/v0/multi_asset.rs b/xcm/src/v0/multi_asset.rs index 4dd0ba1cb4d2..dc682902df65 100644 --- a/xcm/src/v0/multi_asset.rs +++ b/xcm/src/v0/multi_asset.rs @@ -317,7 +317,6 @@ impl TryFrom<VersionedMultiAsset> for MultiAsset { fn try_from(x: VersionedMultiAsset) -> result::Result<Self, ()> { match x { VersionedMultiAsset::V0(x) => Ok(x), - _ => Err(()), } } } diff --git a/xcm/src/v0/multi_location.rs b/xcm/src/v0/multi_location.rs index 772c9738b8b7..c92efd903a21 100644 --- a/xcm/src/v0/multi_location.rs +++ b/xcm/src/v0/multi_location.rs @@ -16,7 +16,7 @@ //! Cross-Consensus Message format data structures. -use core::{result, mem, convert::TryFrom}; +use core::{convert::TryFrom, mem, result}; use parity_scale_codec::{self, Encode, Decode}; use super::Junction; @@ -45,154 +45,487 @@ use crate::VersionedMultiLocation; /// /// The `MultiLocation` value of `Null` simply refers to the interpreting consensus system. #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug)] -pub enum MultiLocation { - /// The interpreting consensus system. - Null, - /// 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 MultiLocation { + parents: u8, + junctions: Junctions, } /// Maximum number of junctions a `MultiLocation` can contain. pub const MAX_MULTILOCATION_LENGTH: usize = 8; +impl MultiLocation { + /// Creates a new MultiLocation, ensuring that the length of it does not exceed the maximum, + /// otherwise returns `Err`. + pub fn new(parents: u8, junctions: Junctions) -> result::Result<MultiLocation, ()> { + if parents as usize + junctions.len() > MAX_MULTILOCATION_LENGTH { + return Err(()) + } + Ok(MultiLocation { + parents, + junctions, + }) + } + + /// Return a reference to the junctions field. + pub fn junctions(&self) -> &Junctions { + &self.junctions + } + + /// Return a mutable reference to the junctions field. + pub fn junctions_mut(&mut self) -> &mut Junctions { + &mut self.junctions + } + + /// Returns the number of `Parent` junctions at the beginning of `self`. + pub fn parent_count(&self) -> usize { + self.parents as usize + } + + /// Returns the number of parents and junctions in `self`. + pub fn len(&self) -> usize { + self.parent_count() + self.junctions.len() + } + + /// Returns first junction that is not a parent, or `None` if the location is empty or + /// contains only parents. + pub fn first_non_parent(&self) -> Option<&Junction> { + self.junctions.first() + } + + /// Returns last junction, or `None` if the location is empty or contains only parents. + pub fn last(&self) -> Option<&Junction> { + self.junctions.last() + } + + /// Splits off the first non-parent 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_non_parent(self) -> (MultiLocation, Option<Junction>) { + let MultiLocation { parents, junctions } = self; + let (prefix, suffix) = junctions.split_first(); + let multilocation = MultiLocation { + parents, + junctions: prefix, + }; + (multilocation, suffix) + } + + /// 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 or that `self` only contains parents. + pub fn split_last(self) -> (MultiLocation, Option<Junction>) { + let MultiLocation { parents, junctions } = self; + let (prefix, suffix) = junctions.split_last(); + let multilocation = MultiLocation { + parents, + junctions: prefix, + }; + (multilocation, suffix) + } + + /// Bumps the parent count up by 1. Returns `Err` in case of overflow. + pub fn push_parent(&mut self) -> result::Result<(), ()> { + if self.len() >= MAX_MULTILOCATION_LENGTH { + return Err(()) + } + self.parents = self.parents.saturating_add(1); + Ok(()) + } + + /// Mutates `self`, suffixing its non-parent junctions with `new`. Returns `Err` in case of overflow. + pub fn push_non_parent(&mut self, new: Junction) -> result::Result<(), ()> { + let mut n = Junctions::Null; + mem::swap(&mut self.junctions, &mut n); + match n.pushed_with(new) { + Ok(result) => { self.junctions = result; Ok(()) } + Err(old) => { self.junctions = old; Err(()) } + } + } + + /// Mutates `self`, prefixing its non-parent junctions with `new`. Returns `Err` in case of overflow. + pub fn push_front_non_parent(&mut self, new: Junction) -> result::Result<(), ()> { + let mut n = Junctions::Null; + mem::swap(&mut self.junctions, &mut n); + match n.pushed_front_with(new) { + Ok(result) => { self.junctions = result; Ok(()) } + Err(old) => { self.junctions = old; Err(()) } + } + } + + /// Consumes `self` and returns a `MultiLocation` with its parent count incremented by 1, or + /// an `Err` with the original value of `self` in case of overflow. + pub fn pushed_with_parent(self) -> result::Result<Self, Self> { + if self.len() >= MAX_MULTILOCATION_LENGTH { + return Err(self) + } + Ok(MultiLocation { + parents: self.parents.saturating_add(1), + ..self + }) + } + + /// 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_non_parent(self, new: Junction) -> result::Result<Self, Self> { + if self.len() >= MAX_MULTILOCATION_LENGTH { + return Err(self) + } + Ok(MultiLocation { + parents: self.parents, + junctions: self.junctions.pushed_with(new).expect("length is less than max length; qed"), + }) + } + + /// 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_non_parent(self, new: Junction) -> result::Result<Self, Self> { + if self.len() >= MAX_MULTILOCATION_LENGTH { + return Err(self) + } + Ok(MultiLocation { + parents: self.parents, + junctions: self.junctions.pushed_front_with(new).expect("length is less than max length; qed"), + }) + } + + /// 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.junctions.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.junctions.at_mut(i - num_parents) + } + + /// Decrement the parent count by 1. + pub fn pop_parent(&mut self) { + self.parents = self.parents.saturating_sub(1); + } + + /// Removes the first non-parent element from `self`, returning it + /// (or `None` if it was empty or if `self` contains only parents). + pub fn take_first_non_parent(&mut self) -> Option<Junction> { + self.junctions.take_first() + } + + /// Removes the last element from `junctions`, returning it (or `None` if it was empty or if + /// `self` only contains parents). + pub fn take_last(&mut self) -> Option<Junction> { + self.junctions.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::v0::{Junctions::*, Junction::*, MultiLocation}; + /// # fn main() { + /// let mut m = MultiLocation::new(1, X2(PalletInstance(3), OnlyChild)).unwrap(); + /// assert_eq!( + /// m.match_and_split(&MultiLocation::new(1, X1(PalletInstance(3))).unwrap()), + /// Some(&OnlyChild), + /// ); + /// assert_eq!(m.match_and_split(&MultiLocation::new(1, Null).unwrap()), None); + /// # } + /// ``` + pub fn match_and_split(&self, prefix: &MultiLocation) -> Option<&Junction> { + if self.parents != prefix.parents { + return None + } + self.junctions.match_and_split(&prefix.junctions) + } + + /// 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::v0::{Junctions::*, Junction::*, MultiLocation}; + /// # fn main() { + /// let mut m = MultiLocation::new(1, X2(Parachain(21), OnlyChild)).unwrap(); + /// assert_eq!(m.append_with(MultiLocation::new(1, X1(PalletInstance(3))).unwrap()), Ok(())); + /// assert_eq!(m, MultiLocation::new(1, X2(Parachain(21), PalletInstance(3))).unwrap()); + /// # } + /// ``` + 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::v0::{Junctions::*, Junction::*, MultiLocation}; + /// # fn main() { + /// let mut m = MultiLocation::new(2, X1(PalletInstance(3))).unwrap(); + /// assert_eq!(m.prepend_with(MultiLocation::new(1, X2(Parachain(21), OnlyChild)).unwrap()), Ok(())); + /// assert_eq!(m, MultiLocation::new(1, X1(PalletInstance(3))).unwrap()); + /// # } + /// ``` + pub fn prepend_with(&mut self, mut prefix: MultiLocation) -> Result<(), MultiLocation> { + let self_parents = self.parent_count(); + let prepend_len = (self_parents as isize - prefix.junctions.len() as isize).abs() as usize; + if self.junctions.len() + prefix.parent_count() + prepend_len > MAX_MULTILOCATION_LENGTH { + return Err(prefix) + } + + let mut final_parent_count = prefix.parents; + for _ in 0..self_parents { + if prefix.take_last().is_none() { + // If true, this means self parent count is greater than prefix junctions length; + // add the resulting self parent count to final_parent_count + final_parent_count += self.parents; + break + } + self.pop_parent(); + } + + self.parents = final_parent_count; + for j in prefix.junctions.into_iter_rev() { + self.push_front_non_parent(j).expect( + "self junctions len + prefix parent count + prepend len is less than max length; qed" + ); + } + Ok(()) + } +} + +impl From<Junctions> for MultiLocation { + fn from(junctions: Junctions) -> Self { + MultiLocation { + parents: 0, + junctions, + } + } +} + impl From<Junction> for MultiLocation { fn from(x: Junction) -> Self { - MultiLocation::X1(x) + MultiLocation { + parents: 0, + junctions: Junctions::X1(x), + } } } impl From<()> for MultiLocation { fn from(_: ()) -> Self { - MultiLocation::Null + MultiLocation { + parents: 0, + junctions: Junctions::Null, + } } } impl From<(Junction,)> for MultiLocation { fn from(x: (Junction,)) -> Self { - MultiLocation::X1(x.0) + MultiLocation { + parents: 0, + junctions: 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, + junctions: 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, + junctions: 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, + junctions: 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, + junctions: 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, + junctions: 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, + junctions: 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)> for MultiLocation { 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, + junctions: Junctions::X8(x.0, x.1, x.2, x.3, x.4, x.5, x.6, x.7), + } } } impl From<[Junction; 0]> for MultiLocation { fn from(_: [Junction; 0]) -> Self { - MultiLocation::Null + MultiLocation { + parents: 0, + junctions: Junctions::Null, + } } } impl From<[Junction; 1]> for MultiLocation { fn from(x: [Junction; 1]) -> Self { let [x0] = x; - MultiLocation::X1(x0) + MultiLocation { + parents: 0, + junctions: 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, + junctions: 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, + junctions: 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, + junctions: 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, + junctions: 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, + junctions: 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, + junctions: 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, + junctions: Junctions::X8(x0, x1, x2, x3, x4, x5, x6, x7), + } } } -pub struct MultiLocationIterator(MultiLocation); -impl Iterator for MultiLocationIterator { +#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug)] +pub enum Junctions { + /// The interpreting consensus system. + Null, + /// 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<Junction> { self.0.take_first() } } -pub struct MultiLocationReverseIterator(MultiLocation); -impl Iterator for MultiLocationReverseIterator { +pub struct JunctionsReverseIterator(Junctions); +impl Iterator for JunctionsReverseIterator { type Item = Junction; fn next(&mut self) -> Option<Junction> { self.0.take_last() } } -pub struct MultiLocationRefIterator<'a>(&'a MultiLocation, usize); -impl<'a> Iterator for MultiLocationRefIterator<'a> { +pub struct JunctionsRefIterator<'a>(&'a Junctions, 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); @@ -201,8 +534,8 @@ impl<'a> Iterator for MultiLocationRefIterator<'a> { } } -pub struct MultiLocationReverseRefIterator<'a>(&'a MultiLocation, usize); -impl<'a> Iterator for MultiLocationReverseRefIterator<'a> { +pub struct JunctionsReverseRefIterator<'a>(&'a Junctions, usize); +impl<'a> Iterator for JunctionsReverseRefIterator<'a> { type Item = &'a Junction; fn next(&mut self) -> Option<&'a Junction> { self.1 += 1; @@ -210,72 +543,72 @@ impl<'a> Iterator for MultiLocationReverseRefIterator<'a> { } } -impl MultiLocation { +impl Junctions { /// Returns first junction, or `None` if the location is empty. pub fn first(&self) -> Option<&Junction> { match &self { - MultiLocation::Null => 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::Null => 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::Null => 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::Null => 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<Junction>) { + pub fn split_first(self) -> (Junctions, Option<Junction>) { match self { - MultiLocation::Null => (MultiLocation::Null, None), - MultiLocation::X1(a) => (MultiLocation::Null, 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::Null => (Junctions::Null, None), + Junctions::X1(a) => (Junctions::Null, 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<Junction>) { + pub fn split_last(self) -> (Junctions, Option<Junction>) { match self { - MultiLocation::Null => (MultiLocation::Null, None), - MultiLocation::X1(a) => (MultiLocation::Null, 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::Null => (Junctions::Null, None), + Junctions::X1(a) => (Junctions::Null, 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<Junction> { - let mut d = MultiLocation::Null; + let mut d = Junctions::Null; mem::swap(&mut *self, &mut d); let (tail, head) = d.split_first(); *self = tail; @@ -284,41 +617,41 @@ impl MultiLocation { /// Removes the last element from `self`, returning it (or `None` if it was empty). pub fn take_last(&mut self) -> Option<Junction> { - let mut d = MultiLocation::Null; + let mut d = Junctions::Null; 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<Self, Self> { Ok(match self { - MultiLocation::Null => 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::Null => 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<Self, Self> { Ok(match self { - MultiLocation::Null => 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::Null => 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)?, }) } @@ -326,57 +659,57 @@ impl MultiLocation { /// Returns the number of junctions in `self`. pub fn len(&self) -> usize { match &self { - MultiLocation::Null => 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::Null => 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, + (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, }) } @@ -385,64 +718,64 @@ 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(&self, 0) } /// Returns a reference iterator over the junctions in reverse. - pub fn iter_rev(&self) -> MultiLocationReverseRefIterator { - MultiLocationReverseRefIterator(&self, 0) + pub fn iter_rev(&self) -> JunctionsReverseRefIterator { + JunctionsReverseRefIterator(&self, 0) } /// Consumes `self` and returns an iterator over the junctions. - pub fn into_iter(self) -> MultiLocationIterator { - MultiLocationIterator(self) + pub fn into_iter(self) -> JunctionsIterator { + JunctionsIterator(self) } /// Consumes `self` and returns an iterator over the junctions in reverse. - pub fn into_iter_rev(self) -> MultiLocationReverseIterator { - MultiLocationReverseIterator(self) + pub fn into_iter_rev(self) -> JunctionsReverseIterator { + JunctionsReverseIterator(self) } /// Ensures that self begins with `prefix` and that it has a single `Junction` item following. @@ -450,14 +783,14 @@ impl MultiLocation { /// /// # Example /// ```rust - /// # use xcm::v0::{MultiLocation::*, Junction::*}; + /// # use xcm::v0::{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 } @@ -468,212 +801,6 @@ 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::Null; - 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::Null; - 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::Null; - 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::v0::{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::v0::{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"); - } - 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::v0::{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<MultiLocation> for VersionedMultiLocation { @@ -687,22 +814,21 @@ impl TryFrom<VersionedMultiLocation> for MultiLocation { fn try_from(x: VersionedMultiLocation) -> result::Result<Self, ()> { match x { VersionedMultiLocation::V0(x) => Ok(x), - _ => Err(()), } } } #[cfg(test)] mod tests { - use super::MultiLocation::*; + use super::{Junctions::*, MultiLocation}; use crate::opaque::v0::{Junction::*, NetworkId::Any}; #[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, junctions: X2(Parachain(42), AccountIndex64 { network: Any, index: 23 }) }; + assert_eq!(m.match_and_split(&MultiLocation { parents: 1, junctions: Null }), None); assert_eq!( - m.match_and_split(&X2(Parent, Parachain(42))), + m.match_and_split(&MultiLocation { parents: 1, junctions: X1(Parachain(42)) }), Some(&AccountIndex64 { network: Any, index: 23 }) ); assert_eq!(m.match_and_split(&m), None); @@ -711,81 +837,30 @@ 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, junctions: X1(Parachain(42)) }; + assert_eq!(m.append_with(MultiLocation::from(X2(PalletInstance(3), acc.clone()))), Ok(())); + assert_eq!(m, MultiLocation { parents: 1, junctions: 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: 6, junctions: X1(Parachain(42)) }; + let suffix = MultiLocation::from(X2(PalletInstance(3), acc.clone())); 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 })); + let mut m = MultiLocation { parents: 1, junctions: X2(Parachain(42), AccountIndex64 { network: Any, index: 23 }) }; + assert_eq!(m.prepend_with(MultiLocation { parents: 1, junctions: X1(OnlyChild) }), Ok(())); + assert_eq!(m, MultiLocation { parents: 1, junctions: X2(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); + let mut m = MultiLocation { parents: 6, junctions: X1(Parachain(42)) }; + let prefix = MultiLocation { parents: 2, junctions: Null }; 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); - 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); - 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)); - } - - #[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, Null); - - 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, Null); - - let mut m = X4( Parent, Parent, Parachain(1), Parachain(2)); - m.canonicalize(); - assert_eq!(m, X4( Parent, Parent, Parachain(1), Parachain(2))); + let prefix = MultiLocation { parents: 1, junctions: Null }; + assert_eq!(m.prepend_with(prefix), Ok(())); + assert_eq!(m, MultiLocation { parents: 7, junctions: X1(Parachain(42)) }); } } diff --git a/xcm/src/v0/traits.rs b/xcm/src/v0/traits.rs index 9a01f227e766..9f8bab7f7d19 100644 --- a/xcm/src/v0/traits.rs +++ b/xcm/src/v0/traits.rs @@ -184,7 +184,7 @@ impl<C> ExecuteXcm<C> for () { /// /// # Example /// ```rust -/// # use xcm::v0::{MultiLocation, Xcm, Junction, Error, OriginKind, SendXcm, Result}; +/// # use xcm::v0::{MultiLocation, Junctions, Xcm, Junction, Error, OriginKind, SendXcm, Result}; /// # use parity_scale_codec::Encode; /// /// /// A sender that only passes the message through and does nothing. @@ -199,7 +199,9 @@ impl<C> ExecuteXcm<C> 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.junctions(), Junctions::X2(j1, j2)) +/// && destination.parent_count() == 0 +/// { /// Ok(()) /// } else { /// Err(Error::Undefined) @@ -211,9 +213,12 @@ impl<C> ExecuteXcm<C> 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.junctions(), Junctions::Null) +/// && destination.parent_count() == 1 +/// { +/// Ok(()) +/// } else { +/// Err(Error::CannotReachDestination(destination, message)) /// } /// } /// } @@ -222,7 +227,7 @@ impl<C> ExecuteXcm<C> for () { /// # fn main() { /// let call: Vec<u8> = ().encode(); /// let message = Xcm::Transact { origin_type: OriginKind::Superuser, require_weight_at_most: 0, call: call.into() }; -/// let destination = MultiLocation::X1(Junction::Parent); +/// let destination = MultiLocation::new(1, Junctions::Null).unwrap(); /// /// assert!( /// // Sender2 will block this. diff --git a/xcm/src/v1/junction.rs b/xcm/src/v1/junction.rs deleted file mode 100644 index 5375f286d44d..000000000000 --- a/xcm/src/v1/junction.rs +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright 2021 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 <http://www.gnu.org/licenses/>. - -//! Support datastructures for `MultiLocation`, primarily the `Junction` datatype. - -use alloc::vec::Vec; -use parity_scale_codec::{self, Encode, Decode}; - -/// A global identifier of an account-bearing consensus system. -#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug)] -pub enum NetworkId { - /// Unidentified/any. - Any, - /// Some named network. - Named(Vec<u8>), - /// The Polkadot Relay chain - Polkadot, - /// Kusama. - Kusama, -} - -/// An identifier of a pluralistic body. -#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug)] -pub enum BodyId { - /// The only body in its context. - Unit, - /// A named body. - Named(Vec<u8>), - /// An indexed body. - // TODO: parity-scale-codec#262: Change to be a tuple. - Index { #[codec(compact)] id: u32 }, - /// The unambiguous executive body (for Polkadot, this would be the Polkadot council). - Executive, - /// The unambiguous technical body (for Polkadot, this would be the Technical Committee). - Technical, - /// The unambiguous legislative body (for Polkadot, this could be considered the opinion of a majority of - /// lock-voters). - Legislative, - /// The unambiguous judicial body (this doesn't exist on Polkadot, but if it were to get a "grand oracle", it - /// may be considered as that). - Judicial, -} - -/// A part of a pluralistic body. -#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug)] -pub enum BodyPart { - /// The body's declaration, under whatever means it decides. - Voice, - /// A given number of members of the body. - Members { #[codec(compact)] count: u32 }, - /// A given number of members of the body, out of some larger caucus. - Fraction { #[codec(compact)] nom: u32, #[codec(compact)] denom: u32 }, - /// No less than the given proportion of members of the body. - AtLeastProportion { #[codec(compact)] nom: u32, #[codec(compact)] denom: u32 }, - /// More than than the given proportion of members of the body. - MoreThanProportion { #[codec(compact)] nom: u32, #[codec(compact)] denom: u32 }, -} - -impl BodyPart { - /// Returns `true` if the part represents a strict majority (> 50%) of the body in question. - pub fn is_majority(&self) -> bool { - match self { - BodyPart::Fraction { nom, denom } if *nom * 2 > *denom => true, - BodyPart::AtLeastProportion { nom, denom } if *nom * 2 > *denom => true, - BodyPart::MoreThanProportion { nom, denom } if *nom * 2 >= *denom => true, - _ => false, - } - } -} - -/// 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)] id: 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<u8>), - /// 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 }, -} diff --git a/xcm/src/v1/mod.rs b/xcm/src/v1/mod.rs deleted file mode 100644 index 7be850a087c6..000000000000 --- a/xcm/src/v1/mod.rs +++ /dev/null @@ -1,317 +0,0 @@ -// Copyright 2021 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 <http://www.gnu.org/licenses/>. - -//! Version 1 of the Cross-Consensus Message format data structures. - -use core::{result, convert::TryFrom, fmt::Debug}; -use derivative::Derivative; -use alloc::vec::Vec; -use parity_scale_codec::{self, Encode, Decode}; -use crate::{VersionedMultiAsset, DoubleEncoded, VersionedXcm}; - -mod junction; -mod multi_asset; -mod multi_location; -mod order; -mod traits; -pub use junction::{Junction, NetworkId, BodyId, BodyPart}; -pub use multi_asset::{MultiAsset, AssetInstance}; -pub use multi_location::{Junctions, MultiLocation}; -pub use order::Order; -pub use traits::{Error, Result, SendXcm, ExecuteXcm, Outcome}; - -/// A prelude for importing all types typically used when interacting with XCM messages. -pub mod prelude { - pub use super::junction::{Junction::*, NetworkId, BodyId, BodyPart}; - pub use super::multi_asset::{MultiAsset::{self, *}, AssetInstance::{self, *}}; - pub use super::multi_location::{Junctions::{self, *}, MultiLocation}; - pub use super::order::Order::{self, *}; - pub use super::traits::{Error as XcmError, Result as XcmResult, SendXcm, ExecuteXcm, Outcome}; - pub use super::{Xcm::{self, *}, OriginKind}; -} - -// TODO: #2841 #XCMENCODE Efficient encodings for Vec<MultiAsset>, Vec<Order>, using initial byte values 128+ to encode -// the number of items in the vector. - -/// Basically just the XCM (more general) version of `ParachainDispatchOrigin`. -#[derive(Copy, Clone, Eq, PartialEq, Encode, Decode, Debug)] -pub enum OriginKind { - /// Origin should just be the native dispatch origin representation for the sender in the - /// local runtime framework. For Cumulus/Frame chains this is the `Parachain` or `Relay` origin - /// if coming from a chain, though there may be others if the `MultiLocation` XCM origin has a - /// primary/native dispatch origin form. - Native, - - /// Origin should just be the standard account-based origin with the sovereign account of - /// the sender. For Cumulus/Frame chains, this is the `Signed` origin. - SovereignAccount, - - /// Origin should be the super-user. For Cumulus/Frame chains, this is the `Root` origin. - /// This will not usually be an available option. - Superuser, - - /// Origin should be interpreted as an XCM native origin and the `MultiLocation` should be - /// encoded directly in the dispatch origin unchanged. For Cumulus/Frame chains, this will be - /// the `pallet_xcm::Origin::Xcm` type. - Xcm, -} - -/// Response data to a query. -#[derive(Clone, Eq, PartialEq, Encode, Decode, Debug)] -pub enum Response { - /// Some assets. - Assets(Vec<MultiAsset>), -} - -/// Cross-Consensus Message: A message from one consensus system to another. -/// -/// Consensus systems that may send and receive messages include blockchains and smart contracts. -/// -/// All messages are delivered from a known *origin*, expressed as a `MultiLocation`. -/// -/// This is the inner XCM format and is version-sensitive. Messages are typically passed using the outer -/// XCM format, known as `VersionedXcm`. -#[derive(Derivative, Encode, Decode)] -#[derivative(Clone(bound = ""), Eq(bound = ""), PartialEq(bound = ""), Debug(bound = ""))] -#[codec(encode_bound())] -#[codec(decode_bound())] -pub enum Xcm<Call> { - /// Withdraw asset(s) (`assets`) from the ownership of `origin` and place them into `holding`. Execute the - /// orders (`effects`). - /// - /// - `assets`: The asset(s) to be withdrawn into holding. - /// - `effects`: The order(s) to execute on the holding account. - /// - /// Kind: *Instruction*. - /// - /// Errors: - #[codec(index = 0)] - WithdrawAsset { assets: Vec<MultiAsset>, effects: Vec<Order<Call>> }, - - /// Asset(s) (`assets`) have been received into the ownership of this system on the `origin` system. - /// - /// Some orders are given (`effects`) which should be executed once the corresponding derivative assets have - /// been placed into `holding`. - /// - /// - `assets`: The asset(s) that are minted into holding. - /// - `effects`: The order(s) to execute on the holding account. - /// - /// Safety: `origin` must be trusted to have received and be storing `assets` such that they may later be - /// withdrawn should this system send a corresponding message. - /// - /// Kind: *Trusted Indication*. - /// - /// Errors: - #[codec(index = 1)] - ReserveAssetDeposit { assets: Vec<MultiAsset>, effects: Vec<Order<Call>> }, - - /// Asset(s) (`assets`) have been destroyed on the `origin` system and equivalent assets should be - /// created on this system. - /// - /// Some orders are given (`effects`) which should be executed once the corresponding derivative assets have - /// been placed into `holding`. - /// - /// - `assets`: The asset(s) that are minted into holding. - /// - `effects`: The order(s) to execute on the holding account. - /// - /// Safety: `origin` must be trusted to have irrevocably destroyed the `assets` prior as a consequence of - /// sending this message. - /// - /// Kind: *Trusted Indication*. - /// - /// Errors: - #[codec(index = 2)] - TeleportAsset { assets: Vec<MultiAsset>, effects: Vec<Order<Call>> }, - - /// Indication of the contents of the holding account corresponding to the `QueryHolding` order of `query_id`. - /// - /// - `query_id`: The identifier of the query that resulted in this message being sent. - /// - `assets`: The message content. - /// - /// Safety: No concerns. - /// - /// Kind: *Information*. - /// - /// Errors: - #[codec(index = 3)] - QueryResponse { #[codec(compact)] query_id: u64, response: Response }, - - /// Withdraw asset(s) (`assets`) from the ownership of `origin` and place equivalent assets under the - /// ownership of `dest` within this consensus system. - /// - /// - `assets`: The asset(s) to be withdrawn. - /// - `dest`: The new owner for the assets. - /// - /// Safety: No concerns. - /// - /// Kind: *Instruction*. - /// - /// Errors: - #[codec(index = 4)] - TransferAsset { assets: Vec<MultiAsset>, dest: MultiLocation }, - - /// Withdraw asset(s) (`assets`) from the ownership of `origin` and place equivalent assets under the - /// ownership of `dest` within this consensus system. - /// - /// Send an onward XCM message to `dest` of `ReserveAssetDeposit` with the given `effects`. - /// - /// - `assets`: The asset(s) to be withdrawn. - /// - `dest`: The new owner for the assets. - /// - `effects`: The orders that should be contained in the `ReserveAssetDeposit` which is sent onwards to - /// `dest. - /// - /// Safety: No concerns. - /// - /// Kind: *Instruction*. - /// - /// Errors: - #[codec(index = 5)] - TransferReserveAsset { assets: Vec<MultiAsset>, dest: MultiLocation, effects: Vec<Order<()>> }, - - /// Apply the encoded transaction `call`, whose dispatch-origin should be `origin` as expressed by the kind - /// of origin `origin_type`. - /// - /// - `origin_type`: The means of expressing the message origin as a dispatch origin. - /// - `max_weight`: The weight of `call`; this should be at least the chain's calculated weight and will - /// be used in the weight determination arithmetic. - /// - `call`: The encoded transaction to be applied. - /// - /// Safety: No concerns. - /// - /// Kind: *Instruction*. - /// - /// Errors: - #[codec(index = 6)] - Transact { origin_type: OriginKind, require_weight_at_most: u64, call: DoubleEncoded<Call> }, - - /// A message to notify about a new incoming HRMP channel. This message is meant to be sent by the - /// relay-chain to a para. - /// - /// - `sender`: The sender in the to-be opened channel. Also, the initiator of the channel opening. - /// - `max_message_size`: The maximum size of a message proposed by the sender. - /// - `max_capacity`: The maximum number of messages that can be queued in the channel. - /// - /// Safety: The message should originate directly from the relay-chain. - /// - /// Kind: *System Notification* - #[codec(index = 7)] - HrmpNewChannelOpenRequest { - #[codec(compact)] sender: u32, - #[codec(compact)] max_message_size: u32, - #[codec(compact)] max_capacity: u32, - }, - - /// A message to notify about that a previously sent open channel request has been accepted by - /// the recipient. That means that the channel will be opened during the next relay-chain session - /// change. This message is meant to be sent by the relay-chain to a para. - /// - /// Safety: The message should originate directly from the relay-chain. - /// - /// Kind: *System Notification* - /// - /// Errors: - #[codec(index = 8)] - HrmpChannelAccepted { - #[codec(compact)] recipient: u32, - }, - - /// A message to notify that the other party in an open channel decided to close it. In particular, - /// `initiator` is going to close the channel opened from `sender` to the `recipient`. The close - /// will be enacted at the next relay-chain session change. This message is meant to be sent by - /// the relay-chain to a para. - /// - /// Safety: The message should originate directly from the relay-chain. - /// - /// Kind: *System Notification* - /// - /// Errors: - #[codec(index = 9)] - HrmpChannelClosing { - #[codec(compact)] initiator: u32, - #[codec(compact)] sender: u32, - #[codec(compact)] recipient: u32, - }, - - /// A message to indicate that the embedded XCM is actually arriving on behalf of some consensus - /// location within the origin. - /// - /// Safety: `who` must be an interior location of the context. This basically means that no `Parent` - /// junctions are allowed in it. This should be verified at the time of XCM execution. - /// - /// Kind: *Instruction* - /// - /// Errors: - #[codec(index = 10)] - RelayedFrom { - who: MultiLocation, - message: alloc::boxed::Box<Xcm<Call>>, - }, -} - -impl<Call> From<Xcm<Call>> for VersionedXcm<Call> { - fn from(x: Xcm<Call>) -> Self { - VersionedXcm::V1(x) - } -} - -impl<Call> TryFrom<VersionedXcm<Call>> for Xcm<Call> { - type Error = (); - fn try_from(x: VersionedXcm<Call>) -> result::Result<Self, ()> { - match x { - VersionedXcm::V1(x) => Ok(x), - _ => Err(()), - } - } -} - -impl<Call> Xcm<Call> { - pub fn into<C>(self) -> Xcm<C> { Xcm::from(self) } - pub fn from<C>(xcm: Xcm<C>) -> Self { - use Xcm::*; - match xcm { - WithdrawAsset { assets, effects } - => WithdrawAsset { assets, effects: effects.into_iter().map(Order::into).collect() }, - ReserveAssetDeposit { assets, effects } - => ReserveAssetDeposit { assets, effects: effects.into_iter().map(Order::into).collect() }, - TeleportAsset { assets, effects } - => TeleportAsset { assets, effects: effects.into_iter().map(Order::into).collect() }, - QueryResponse { query_id: u64, response } - => QueryResponse { query_id: u64, response }, - TransferAsset { assets, dest } - => TransferAsset { assets, dest }, - TransferReserveAsset { assets, dest, effects } - => TransferReserveAsset { assets, dest, effects }, - HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity} - => HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity}, - HrmpChannelAccepted { recipient} - => HrmpChannelAccepted { recipient}, - HrmpChannelClosing { initiator, sender, recipient} - => HrmpChannelClosing { initiator, sender, recipient}, - Transact { origin_type, require_weight_at_most, call} - => Transact { origin_type, require_weight_at_most, call: call.into() }, - RelayedFrom { who, message } - => RelayedFrom { who, message: alloc::boxed::Box::new((*message).into()) }, - } - } -} - -pub mod opaque { - /// The basic concrete type of `generic::Xcm`, which doesn't make any assumptions about the format of a - /// call other than it is pre-encoded. - pub type Xcm = super::Xcm<()>; - - pub use super::order::opaque::*; -} diff --git a/xcm/src/v1/multi_asset.rs b/xcm/src/v1/multi_asset.rs deleted file mode 100644 index 552e67f03d8e..000000000000 --- a/xcm/src/v1/multi_asset.rs +++ /dev/null @@ -1,380 +0,0 @@ -// Copyright 2021 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 <http://www.gnu.org/licenses/>. - -//! Cross-Consensus Message format data structures. - -use core::{result, convert::TryFrom}; -use alloc::vec::Vec; - -use parity_scale_codec::{self, Encode, Decode}; -use super::{MultiLocation, VersionedMultiAsset}; - -/// A general identifier for an instance of a non-fungible asset class. -#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug)] -pub enum AssetInstance { - /// Undefined - used if the NFA class has only one instance. - Undefined, - - /// A compact index. Technically this could be greater than u128, but this implementation supports only - /// values up to `2**128 - 1`. - Index { #[codec(compact)] id: u128 }, - - /// A 4-byte fixed-length datum. - Array4([u8; 4]), - - /// An 8-byte fixed-length datum. - Array8([u8; 8]), - - /// A 16-byte fixed-length datum. - Array16([u8; 16]), - - /// A 32-byte fixed-length datum. - Array32([u8; 32]), - - /// An arbitrary piece of data. Use only when necessary. - Blob(Vec<u8>), -} - -/// A single general identifier for an asset. -/// -/// Represents both fungible and non-fungible assets. May only be used to represent a single asset class. -/// -/// Wildcards may or may not be allowed by the interpreting context. -/// -/// Assets classes may be identified in one of two ways: either an abstract identifier or a concrete identifier. -/// Implementations may support only one of these. A single asset may be referenced from multiple asset identifiers, -/// though will tend to have only a single *preferred* identifier. -/// -/// ### Abstract identifiers -/// -/// Abstract identifiers are absolute identifiers that represent a notional asset which can exist within multiple -/// consensus systems. These tend to be simpler to deal with since their broad meaning is unchanged regardless stay of -/// the consensus system in which it is interpreted. -/// -/// However, in the attempt to provide uniformity across consensus systems, they may conflate different instantiations -/// of some notional asset (e.g. the reserve asset and a local reserve-backed derivative of it) under the same name, -/// leading to confusion. It also implies that one notional asset is accounted for locally in only one way. This may not -/// be the case, e.g. where there are multiple bridge instances each providing a bridged "BTC" token yet none being -/// fungible between the others. -/// -/// Since they are meant to be absolute and universal, a global registry is needed to ensure that name collisions do not -/// occur. -/// -/// An abstract identifier is represented as a simple variable-size byte string. As of writing, no global registry -/// exists and no proposals have been put forth for asset labeling. -/// -/// ### Concrete identifiers -/// -/// Concrete identifiers are *relative identifiers* that specifically identify a single asset through its location in a -/// consensus system relative to the context interpreting. Use of a `MultiLocation` ensures that similar but non -/// fungible variants of the same underlying asset can be properly distinguished, and obviates the need for any kind of -/// central registry. -/// -/// The limitation is that the asset identifier cannot be trivially copied between consensus systems and must instead be -/// "re-anchored" whenever being moved to a new consensus system, using the two systems' relative paths. -/// -/// Throughout XCM, messages are authored such that *when interpreted from the receiver's point of view* they will have -/// the desired meaning/effect. This means that relative paths should always by constructed to be read from the point of -/// view of the receiving system, *which may be have a completely different meaning in the authoring system*. -/// -/// Concrete identifiers are the preferred way of identifying an asset since they are entirely unambiguous. -/// -/// A concrete identifier is represented by a `MultiLocation`. If a system has an unambiguous primary asset (such as -/// Bitcoin with BTC or Ethereum with ETH), then it will conventionally be identified as the chain itself. Alternative -/// and more specific ways of referring to an asset within a system include: -/// -/// - `<chain>/PalletInstance(<id>)` for a Frame chain with a single-asset pallet instance (such as an instance of the -/// Balances pallet). -/// - `<chain>/PalletInstance(<id>)/GeneralIndex(<index>)` for a Frame chain with an indexed multi-asset pallet instance -/// (such as an instance of the Assets pallet). -/// - `<chain>/AccountId32` for an ERC-20-style single-asset smart-contract on a Frame-based contracts chain. -/// - `<chain>/AccountKey20` for an ERC-20-style single-asset smart-contract on an Ethereum-like chain. -/// -#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug)] -pub enum MultiAsset { - /// No assets. Rarely used. - None, - - /// All assets. Typically used for the subset of assets to be used for an `Order`, and in that context means - /// "all assets currently in holding". - All, - - /// All fungible assets. Typically used for the subset of assets to be used for an `Order`, and in that context - /// means "all fungible assets currently in holding". - AllFungible, - - /// All non-fungible assets. Typically used for the subset of assets to be used for an `Order`, and in that - /// context means "all non-fungible assets currently in holding". - AllNonFungible, - - /// All fungible assets of a given abstract asset `id`entifier. - AllAbstractFungible { id: Vec<u8> }, - - /// All non-fungible assets of a given abstract asset `class`. - AllAbstractNonFungible { class: Vec<u8> }, - - /// All fungible assets of a given concrete asset `id`entifier. - AllConcreteFungible { id: MultiLocation }, - - /// All non-fungible assets of a given concrete asset `class`. - AllConcreteNonFungible { class: MultiLocation }, - - /// Some specific `amount` of the fungible asset identified by an abstract `id`. - AbstractFungible { id: Vec<u8>, #[codec(compact)] amount: u128 }, - - /// Some specific `instance` of the non-fungible asset whose `class` is identified abstractly. - AbstractNonFungible { class: Vec<u8>, instance: AssetInstance }, - - /// Some specific `amount` of the fungible asset identified by an concrete `id`. - ConcreteFungible { id: MultiLocation, #[codec(compact)] amount: u128 }, - - /// Some specific `instance` of the non-fungible asset whose `class` is identified concretely. - ConcreteNonFungible { class: MultiLocation, instance: AssetInstance }, -} - -impl MultiAsset { - /// Returns `true` if the `MultiAsset` is a wildcard and can refer to classes of assets, instead of just one. - /// - /// Typically can also be inferred by the name starting with `All`. - pub fn is_wildcard(&self) -> bool { - match self { - MultiAsset::None - | MultiAsset::AbstractFungible {..} - | MultiAsset::AbstractNonFungible {..} - | MultiAsset::ConcreteFungible {..} - | MultiAsset::ConcreteNonFungible {..} - => false, - - MultiAsset::All - | MultiAsset::AllFungible - | MultiAsset::AllNonFungible - | MultiAsset::AllAbstractFungible {..} - | MultiAsset::AllConcreteFungible {..} - | MultiAsset::AllAbstractNonFungible {..} - | MultiAsset::AllConcreteNonFungible {..} - => true, - } - } - - fn is_none(&self) -> bool { - match self { - MultiAsset::None - | MultiAsset::AbstractFungible { amount: 0, .. } - | MultiAsset::ConcreteFungible { amount: 0, .. } - => true, - - _ => false, - } - } - - fn is_fungible(&self) -> bool { - match self { - MultiAsset::All - | MultiAsset::AllFungible - | MultiAsset::AllAbstractFungible {..} - | MultiAsset::AllConcreteFungible {..} - | MultiAsset::AbstractFungible {..} - | MultiAsset::ConcreteFungible {..} - => true, - - _ => false, - } - } - - fn is_non_fungible(&self) -> bool { - match self { - MultiAsset::All - | MultiAsset::AllNonFungible - | MultiAsset::AllAbstractNonFungible {..} - | MultiAsset::AllConcreteNonFungible {..} - | MultiAsset::AbstractNonFungible {..} - | MultiAsset::ConcreteNonFungible {..} - => true, - - _ => false, - } - } - - fn is_concrete_fungible(&self, id: &MultiLocation) -> bool { - match self { - MultiAsset::AllFungible => true, - MultiAsset::AllConcreteFungible { id: i } - | MultiAsset::ConcreteFungible { id: i, .. } - => i == id, - - _ => false, - } - } - - fn is_abstract_fungible(&self, id: &[u8]) -> bool { - match self { - MultiAsset::AllFungible => true, - MultiAsset::AllAbstractFungible { id: i } - | MultiAsset::AbstractFungible { id: i, .. } - => i == id, - _ => false, - } - } - - fn is_concrete_non_fungible(&self, class: &MultiLocation) -> bool { - match self { - MultiAsset::AllNonFungible => true, - MultiAsset::AllConcreteNonFungible { class: i } - | MultiAsset::ConcreteNonFungible { class: i, .. } - => i == class, - _ => false, - } - } - - fn is_abstract_non_fungible(&self, class: &[u8]) -> bool { - match self { - MultiAsset::AllNonFungible => true, - MultiAsset::AllAbstractNonFungible { class: i } - | MultiAsset::AbstractNonFungible { class: i, .. } - => i == class, - _ => false, - } - } - - fn is_all(&self) -> bool { matches!(self, MultiAsset::All) } - - /// Returns true if `self` is a super-set of the given `inner`. - /// - /// Typically, any wildcard is never contained in anything else, and a wildcard can contain any other non-wildcard. - /// For more details, see the implementation and tests. - pub fn contains(&self, inner: &MultiAsset) -> bool { - use MultiAsset::*; - - // Inner cannot be wild - if inner.is_wildcard() { return false } - // Everything contains nothing. - if inner.is_none() { return true } - - // Everything contains anything. - if self.is_all() { return true } - // Nothing contains nothing. - if self.is_none() { return false } - - match self { - // Anything fungible contains "all fungibles" - AllFungible => inner.is_fungible(), - // Anything non-fungible contains "all non-fungibles" - AllNonFungible => inner.is_non_fungible(), - - AllConcreteFungible { id } => inner.is_concrete_fungible(id), - AllAbstractFungible { id } => inner.is_abstract_fungible(id), - AllConcreteNonFungible { class } => inner.is_concrete_non_fungible(class), - AllAbstractNonFungible { class } => inner.is_abstract_non_fungible(class), - - ConcreteFungible { id, amount } => matches!( - inner, - ConcreteFungible { id: inner_id , amount: inner_amount } if inner_id == id && amount >= inner_amount - ), - AbstractFungible { id, amount } => matches!( - inner, - AbstractFungible { id: inner_id , amount: inner_amount } if inner_id == id && amount >= inner_amount - ), - ConcreteNonFungible { .. } => self == inner, - AbstractNonFungible { .. } => self == inner, - _ => false, - } - } - - pub fn reanchor(&mut self, prepend: &MultiLocation) -> Result<(), ()> { - use MultiAsset::*; - match self { - AllConcreteFungible { ref mut id } - | AllConcreteNonFungible { class: ref mut id } - | ConcreteFungible { ref mut id, .. } - | ConcreteNonFungible { class: ref mut id, .. } - => id.prepend_with(prepend.clone()).map_err(|_| ()), - _ => Ok(()), - } - } -} - -impl From<MultiAsset> for VersionedMultiAsset { - fn from(x: MultiAsset) -> Self { - VersionedMultiAsset::V1(x) - } -} - -impl TryFrom<VersionedMultiAsset> for MultiAsset { - type Error = (); - fn try_from(x: VersionedMultiAsset) -> result::Result<Self, ()> { - match x { - VersionedMultiAsset::V1(x) => Ok(x), - _ => Err(()), - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn contains_works() { - use alloc::vec; - use MultiAsset::*; - // trivial case: all contains any non-wildcard. - assert!(All.contains(&None)); - assert!(All.contains(&AbstractFungible { id: alloc::vec![99u8], amount: 1 })); - - // trivial case: none contains nothing, except itself. - assert!(None.contains(&None)); - assert!(!None.contains(&AllFungible)); - assert!(!None.contains(&All)); - - // A bit more sneaky: Nothing can contain wildcard, even All ir the thing itself. - assert!(!All.contains(&All)); - assert!(!All.contains(&AllFungible)); - assert!(!AllFungible.contains(&AllFungible)); - assert!(!AllNonFungible.contains(&AllNonFungible)); - - // For fungibles, containing is basically equality, or equal id with higher amount. - assert!( - !AbstractFungible { id: vec![99u8], amount: 99 } - .contains(&AbstractFungible { id: vec![1u8], amount: 99 }) - ); - assert!( - AbstractFungible { id: vec![99u8], amount: 99 } - .contains(&AbstractFungible { id: vec![99u8], amount: 99 }) - ); - assert!( - AbstractFungible { id: vec![99u8], amount: 99 } - .contains(&AbstractFungible { id: vec![99u8], amount: 9 }) - ); - assert!( - !AbstractFungible { id: vec![99u8], amount: 99 } - .contains(&AbstractFungible { id: vec![99u8], amount: 100 }) - ); - - // For non-fungibles, containing is equality. - assert!( - !AbstractNonFungible {class: vec![99u8], instance: AssetInstance::Index { id: 9 } } - .contains(&AbstractNonFungible { class: vec![98u8], instance: AssetInstance::Index { id: 9 } }) - ); - assert!( - !AbstractNonFungible { class: vec![99u8], instance: AssetInstance::Index { id: 8 } } - .contains(&AbstractNonFungible { class: vec![99u8], instance: AssetInstance::Index { id: 9 } }) - ); - assert!( - AbstractNonFungible { class: vec![99u8], instance: AssetInstance::Index { id: 9 } } - .contains(&AbstractNonFungible { class: vec![99u8], instance: AssetInstance::Index { id: 9 } }) - ); - } -} diff --git a/xcm/src/v1/multi_location.rs b/xcm/src/v1/multi_location.rs deleted file mode 100644 index ecffb26f8838..000000000000 --- a/xcm/src/v1/multi_location.rs +++ /dev/null @@ -1,867 +0,0 @@ -// Copyright 2021 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 <http://www.gnu.org/licenses/>. - -//! Cross-Consensus Message format data structures. - -use core::{convert::TryFrom, mem, result}; - -use parity_scale_codec::{self, Encode, Decode}; -use super::Junction; -use crate::VersionedMultiLocation; - -/// A relative path between state-bearing consensus systems. -/// -/// A location in a consensus system is defined as an *isolatable state machine* held within global consensus. The -/// location in question need not have a sophisticated consensus algorithm of its own; a single account within -/// Ethereum, for example, could be considered a location. -/// -/// A very-much non-exhaustive list of types of location include: -/// - A (normal, layer-1) block chain, e.g. the Bitcoin mainnet or a parachain. -/// - A layer-0 super-chain, e.g. the Polkadot Relay chain. -/// - A layer-2 smart contract, e.g. an ERC-20 on Ethereum. -/// - A logical functional component of a chain, e.g. a single instance of a pallet on a Frame-based Substrate chain. -/// - An account. -/// -/// 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. -/// -/// This specific `MultiLocation` implementation uses a Rust `enum` in order to make pattern matching easier. -/// -/// The `MultiLocation` value of `Null` simply refers to the interpreting consensus system. -#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug)] -pub struct MultiLocation { - parents: u8, - junctions: Junctions, -} - -/// Maximum number of junctions a multilocation can contain. -pub const MAX_MULTILOCATION_LENGTH: usize = 8; - -impl MultiLocation { - /// Creates a new MultiLocation, ensuring that the length of it does not exceed the maximum, - /// otherwise returns `Err`. - pub fn new(parents: u8, junctions: Junctions) -> result::Result<MultiLocation, ()> { - if parents as usize + junctions.len() > MAX_MULTILOCATION_LENGTH { - return Err(()) - } - Ok(MultiLocation { - parents, - junctions, - }) - } - - /// Return a reference to the junctions field. - pub fn junctions(&self) -> &Junctions { - &self.junctions - } - - /// Return a mutable reference to the junctions field. - pub fn junctions_mut(&mut self) -> &mut Junctions { - &mut self.junctions - } - - /// Returns the number of `Parent` junctions at the beginning of `self`. - pub fn parent_count(&self) -> usize { - self.parents as usize - } - - /// Returns the number of parents and junctions in `self`. - pub fn len(&self) -> usize { - self.parent_count() + self.junctions.len() - } - - /// Returns first junction that is not a parent, or `None` if the location is empty or - /// contains only parents. - pub fn first_non_parent(&self) -> Option<&Junction> { - self.junctions.first() - } - - /// Returns last junction, or `None` if the location is empty or contains only parents. - pub fn last(&self) -> Option<&Junction> { - self.junctions.last() - } - - /// Splits off the first non-parent 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_non_parent(self) -> (MultiLocation, Option<Junction>) { - let MultiLocation { parents, junctions } = self; - let (prefix, suffix) = junctions.split_first(); - let multilocation = MultiLocation { - parents, - junctions: prefix, - }; - (multilocation, suffix) - } - - /// 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 or that `self` only contains parents. - pub fn split_last(self) -> (MultiLocation, Option<Junction>) { - let MultiLocation { parents, junctions } = self; - let (prefix, suffix) = junctions.split_last(); - let multilocation = MultiLocation { - parents, - junctions: prefix, - }; - (multilocation, suffix) - } - - /// Bumps the parent count up by 1. Returns `Err` in case of overflow. - pub fn push_parent(&mut self) -> result::Result<(), ()> { - if self.len() >= MAX_MULTILOCATION_LENGTH { - return Err(()) - } - self.parents = self.parents.saturating_add(1); - Ok(()) - } - - /// Mutates `self`, suffixing its non-parent junctions with `new`. Returns `Err` in case of overflow. - pub fn push_non_parent(&mut self, new: Junction) -> result::Result<(), ()> { - let mut n = Junctions::Null; - mem::swap(&mut self.junctions, &mut n); - match n.pushed_with(new) { - Ok(result) => { self.junctions = result; Ok(()) } - Err(old) => { self.junctions = old; Err(()) } - } - } - - /// Mutates `self`, prefixing its non-parent junctions with `new`. Returns `Err` in case of overflow. - pub fn push_front_non_parent(&mut self, new: Junction) -> result::Result<(), ()> { - let mut n = Junctions::Null; - mem::swap(&mut self.junctions, &mut n); - match n.pushed_front_with(new) { - Ok(result) => { self.junctions = result; Ok(()) } - Err(old) => { self.junctions = old; Err(()) } - } - } - - /// Consumes `self` and returns a `MultiLocation` with its parent count incremented by 1, or - /// an `Err` with the original value of `self` in case of overflow. - pub fn pushed_with_parent(self) -> result::Result<Self, Self> { - if self.len() >= MAX_MULTILOCATION_LENGTH { - return Err(self) - } - Ok(MultiLocation { - parents: self.parents.saturating_add(1), - ..self - }) - } - - /// 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_non_parent(self, new: Junction) -> result::Result<Self, Self> { - if self.len() >= MAX_MULTILOCATION_LENGTH { - return Err(self) - } - Ok(MultiLocation { - parents: self.parents, - junctions: self.junctions.pushed_with(new).expect("length is less than max length; qed"), - }) - } - - /// 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_non_parent(self, new: Junction) -> result::Result<Self, Self> { - if self.len() >= MAX_MULTILOCATION_LENGTH { - return Err(self) - } - Ok(MultiLocation { - parents: self.parents, - junctions: self.junctions.pushed_front_with(new).expect("length is less than max length; qed"), - }) - } - - /// 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.junctions.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.junctions.at_mut(i - num_parents) - } - - /// Decrement the parent count by 1. - pub fn pop_parent(&mut self) { - self.parents = self.parents.saturating_sub(1); - } - - /// Removes the first non-parent element from `self`, returning it - /// (or `None` if it was empty or if `self` contains only parents). - pub fn take_first_non_parent(&mut self) -> Option<Junction> { - self.junctions.take_first() - } - - /// Removes the last element from `junctions`, returning it (or `None` if it was empty or if - /// `self` only contains parents). - pub fn take_last(&mut self) -> Option<Junction> { - self.junctions.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)).unwrap(); - /// assert_eq!( - /// m.match_and_split(&MultiLocation::new(1, X1(PalletInstance(3))).unwrap()), - /// Some(&OnlyChild), - /// ); - /// assert_eq!(m.match_and_split(&MultiLocation::new(1, Null).unwrap()), None); - /// # } - /// ``` - pub fn match_and_split(&self, prefix: &MultiLocation) -> Option<&Junction> { - if self.parents != prefix.parents { - return None - } - self.junctions.match_and_split(&prefix.junctions) - } - - /// 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)).unwrap(); - /// assert_eq!(m.append_with(MultiLocation::new(1, X1(PalletInstance(3))).unwrap()), Ok(())); - /// assert_eq!(m, MultiLocation::new(1, X2(Parachain(21), PalletInstance(3))).unwrap()); - /// # } - /// ``` - 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))).unwrap(); - /// assert_eq!(m.prepend_with(MultiLocation::new(1, X2(Parachain(21), OnlyChild)).unwrap()), Ok(())); - /// assert_eq!(m, MultiLocation::new(1, X1(PalletInstance(3))).unwrap()); - /// # } - /// ``` - pub fn prepend_with(&mut self, mut prefix: MultiLocation) -> Result<(), MultiLocation> { - let self_parents = self.parent_count(); - let prepend_len = (self_parents as isize - prefix.junctions.len() as isize).abs() as usize; - if self.junctions.len() + prefix.parent_count() + prepend_len > MAX_MULTILOCATION_LENGTH { - return Err(prefix) - } - - let mut final_parent_count = prefix.parents; - for _ in 0..self_parents { - if prefix.take_last().is_none() { - // If true, this means self parent count is greater than prefix junctions length; - // add the resulting self parent count to final_parent_count - final_parent_count += self.parents; - break - } - self.pop_parent(); - } - - self.parents = final_parent_count; - for j in prefix.junctions.into_iter_rev() { - self.push_front_non_parent(j).expect( - "self junctions len + prefix parent count + prepend len is less than max length; qed" - ); - } - Ok(()) - } -} - -impl From<Junctions> for MultiLocation { - fn from(junctions: Junctions) -> Self { - MultiLocation { - parents: 0, - junctions, - } - } -} - -impl From<Junction> for MultiLocation { - fn from(x: Junction) -> Self { - MultiLocation { - parents: 0, - junctions: Junctions::X1(x), - } - } -} - -impl From<()> for MultiLocation { - fn from(_: ()) -> Self { - MultiLocation { - parents: 0, - junctions: Junctions::Null, - } - } -} -impl From<(Junction,)> for MultiLocation { - fn from(x: (Junction,)) -> Self { - MultiLocation { - parents: 0, - junctions: Junctions::X1(x.0), - } - } -} -impl From<(Junction, Junction)> for MultiLocation { - fn from(x: (Junction, Junction)) -> Self { - MultiLocation { - parents: 0, - junctions: Junctions::X2(x.0, x.1), - } - } -} -impl From<(Junction, Junction, Junction)> for MultiLocation { - fn from(x: (Junction, Junction, Junction)) -> Self { - MultiLocation { - parents: 0, - junctions: 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 { - parents: 0, - junctions: 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 { - parents: 0, - junctions: 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 { - parents: 0, - junctions: 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 { - parents: 0, - junctions: 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)> for MultiLocation { - fn from(x: (Junction, Junction, Junction, Junction, Junction, Junction, Junction, Junction)) -> Self { - MultiLocation { - parents: 0, - junctions: Junctions::X8(x.0, x.1, x.2, x.3, x.4, x.5, x.6, x.7), - } - } -} - -impl From<[Junction; 0]> for MultiLocation { - fn from(_: [Junction; 0]) -> Self { - MultiLocation { - parents: 0, - junctions: Junctions::Null, - } - } -} -impl From<[Junction; 1]> for MultiLocation { - fn from(x: [Junction; 1]) -> Self { - let [x0] = x; - MultiLocation { - parents: 0, - junctions: Junctions::X1(x0), - } - } -} -impl From<[Junction; 2]> for MultiLocation { - fn from(x: [Junction; 2]) -> Self { - let [x0, x1] = x; - MultiLocation { - parents: 0, - junctions: Junctions::X2(x0, x1), - } - } -} -impl From<[Junction; 3]> for MultiLocation { - fn from(x: [Junction; 3]) -> Self { - let [x0, x1, x2] = x; - MultiLocation { - parents: 0, - junctions: Junctions::X3(x0, x1, x2), - } - } -} -impl From<[Junction; 4]> for MultiLocation { - fn from(x: [Junction; 4]) -> Self { - let [x0, x1, x2, x3] = x; - MultiLocation { - parents: 0, - junctions: 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 { - parents: 0, - junctions: 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 { - parents: 0, - junctions: 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 { - parents: 0, - junctions: 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 { - parents: 0, - junctions: Junctions::X8(x0, x1, x2, x3, x4, x5, x6, x7), - } - } -} - -#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug)] -pub enum Junctions { - /// The interpreting consensus system. - Null, - /// 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<Junction> { - self.0.take_first() - } -} - -pub struct JunctionsReverseIterator(Junctions); -impl Iterator for JunctionsReverseIterator { - type Item = Junction; - fn next(&mut self) -> Option<Junction> { - self.0.take_last() - } -} - -pub struct JunctionsRefIterator<'a>(&'a Junctions, 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; - result - } -} - -pub struct JunctionsReverseRefIterator<'a>(&'a Junctions, usize); -impl<'a> Iterator for JunctionsReverseRefIterator<'a> { - type Item = &'a Junction; - fn next(&mut self) -> Option<&'a Junction> { - self.1 += 1; - self.0.at(self.0.len().checked_sub(self.1)?) - } -} - -impl Junctions { - /// Returns first junction, or `None` if the location is empty. - pub fn first(&self) -> Option<&Junction> { - match &self { - Junctions::Null => 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 { - Junctions::Null => 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) -> (Junctions, Option<Junction>) { - match self { - Junctions::Null => (Junctions::Null, None), - Junctions::X1(a) => (Junctions::Null, 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) -> (Junctions, Option<Junction>) { - match self { - Junctions::Null => (Junctions::Null, None), - Junctions::X1(a) => (Junctions::Null, 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<Junction> { - let mut d = Junctions::Null; - mem::swap(&mut *self, &mut d); - let (tail, head) = d.split_first(); - *self = tail; - head - } - - /// Removes the last element from `self`, returning it (or `None` if it was empty). - pub fn take_last(&mut self) -> Option<Junction> { - let mut d = Junctions::Null; - mem::swap(&mut *self, &mut d); - let (head, tail) = d.split_last(); - *self = head; - tail - } - - /// 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<Self, Self> { - Ok(match self { - Junctions::Null => 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 `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<Self, Self> { - Ok(match self { - Junctions::Null => 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 { - match &self { - Junctions::Null => 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, 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, - }) - } - - /// Returns a mutable reference to the junction at index `i`, or `None` if the location doesn't contain that many - /// elements. - pub fn at_mut(&mut self, i: usize) -> Option<&mut Junction> { - Some(match (i, self) { - (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) -> JunctionsRefIterator { - JunctionsRefIterator(&self, 0) - } - - /// Returns a reference iterator over the junctions in reverse. - pub fn iter_rev(&self) -> JunctionsReverseRefIterator { - JunctionsReverseRefIterator(&self, 0) - } - - /// Consumes `self` and returns an iterator over the junctions. - pub fn into_iter(self) -> JunctionsIterator { - JunctionsIterator(self) - } - - /// Consumes `self` and returns an iterator over the junctions in reverse. - pub fn into_iter_rev(self) -> JunctionsReverseIterator { - JunctionsReverseIterator(self) - } - - /// Ensures that self begins with `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::*}; - /// # fn main() { - /// 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: &Junctions) -> Option<&Junction> { - if prefix.len() + 1 != self.len() { - return None - } - for i in 0..prefix.len() { - if prefix.at(i) != self.at(i) { - return None - } - } - return self.at(prefix.len()) - } -} - -impl From<MultiLocation> for VersionedMultiLocation { - fn from(x: MultiLocation) -> Self { - VersionedMultiLocation::V1(x) - } -} - -impl TryFrom<VersionedMultiLocation> for MultiLocation { - type Error = (); - fn try_from(x: VersionedMultiLocation) -> result::Result<Self, ()> { - match x { - VersionedMultiLocation::V1(x) => Ok(x), - _ => Err(()), - } - } -} - -#[cfg(test)] -mod tests { - use super::{Junctions::*, MultiLocation}; - use crate::opaque::v1::{Junction::*, NetworkId::Any}; - - #[test] - fn match_and_split_works() { - let m = MultiLocation { parents: 1, junctions: X2(Parachain(42), AccountIndex64 { network: Any, index: 23 }) }; - assert_eq!(m.match_and_split(&MultiLocation { parents: 1, junctions: Null }), None); - assert_eq!( - m.match_and_split(&MultiLocation { parents: 1, junctions: X1(Parachain(42)) }), - Some(&AccountIndex64 { network: Any, index: 23 }) - ); - assert_eq!(m.match_and_split(&m), None); - } - - #[test] - fn append_with_works() { - let acc = AccountIndex64 { network: Any, index: 23 }; - let mut m = MultiLocation { parents: 1, junctions: X1(Parachain(42)) }; - assert_eq!(m.append_with(MultiLocation::from(X2(PalletInstance(3), acc.clone()))), Ok(())); - assert_eq!(m, MultiLocation { parents: 1, junctions: X3(Parachain(42), PalletInstance(3), acc.clone()) }); - - // cannot append to create overly long multilocation - let acc = AccountIndex64 { network: Any, index: 23 }; - let mut m = MultiLocation { parents: 6, junctions: X1(Parachain(42)) }; - let suffix = MultiLocation::from(X2(PalletInstance(3), acc.clone())); - assert_eq!(m.append_with(suffix.clone()), Err(suffix)); - } - - #[test] - fn prepend_with_works() { - let mut m = MultiLocation { parents: 1, junctions: X2(Parachain(42), AccountIndex64 { network: Any, index: 23 }) }; - assert_eq!(m.prepend_with(MultiLocation { parents: 1, junctions: X1(OnlyChild) }), Ok(())); - assert_eq!(m, MultiLocation { parents: 1, junctions: X2(Parachain(42), AccountIndex64 { network: Any, index: 23 }) }); - - // cannot prepend to create overly long multilocation - let mut m = MultiLocation { parents: 6, junctions: X1(Parachain(42)) }; - let prefix = MultiLocation { parents: 2, junctions: Null }; - assert_eq!(m.prepend_with(prefix.clone()), Err(prefix)); - - let prefix = MultiLocation { parents: 1, junctions: Null }; - assert_eq!(m.prepend_with(prefix), Ok(())); - assert_eq!(m, MultiLocation { parents: 7, junctions: X1(Parachain(42)) }); - } -} diff --git a/xcm/src/v1/order.rs b/xcm/src/v1/order.rs deleted file mode 100644 index f1e48c3b90c2..000000000000 --- a/xcm/src/v1/order.rs +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright 2021 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 <http://www.gnu.org/licenses/>. - -//! Version 1 of the Cross-Consensus Message format data structures. - -use alloc::vec::Vec; -use derivative::Derivative; -use parity_scale_codec::{self, Encode, Decode}; -use super::{MultiAsset, MultiLocation, Xcm}; - -/// An instruction to be executed on some or all of the assets in holding, used by asset-related XCM messages. -#[derive(Derivative, Encode, Decode)] -#[derivative(Clone(bound=""), Eq(bound=""), PartialEq(bound=""), Debug(bound=""))] -#[codec(encode_bound())] -#[codec(decode_bound())] -pub enum Order<Call> { - /// Do nothing. Not generally used. - #[codec(index = 0)] - Null, - - /// Remove the asset(s) (`assets`) from holding and place equivalent assets under the ownership of `dest` within - /// this consensus system. - /// - /// - `assets`: The asset(s) to remove from holding. - /// - `dest`: The new owner for the assets. - /// - /// Errors: - #[codec(index = 1)] - DepositAsset { assets: Vec<MultiAsset>, dest: MultiLocation }, - - /// Remove the asset(s) (`assets`) from holding and place equivalent assets under the ownership of `dest` within - /// this consensus system. - /// - /// Send an onward XCM message to `dest` of `ReserveAssetDeposit` with the given `effects`. - /// - /// - `assets`: The asset(s) to remove from holding. - /// - `dest`: The new owner for the assets. - /// - `effects`: The orders that should be contained in the `ReserveAssetDeposit` which is sent onwards to - /// `dest. - /// - /// Errors: - #[codec(index = 2)] - DepositReserveAsset { assets: Vec<MultiAsset>, dest: MultiLocation, effects: Vec<Order<()>> }, - - /// Remove the asset(s) (`give`) from holding and replace them with alternative assets. - /// - /// The minimum amount of assets to be received into holding for the order not to fail may be stated. - /// - /// - `give`: The asset(s) to remove from holding. - /// - `receive`: The minimum amount of assets(s) which `give` should be exchanged for. The meaning of wildcards - /// is undefined and they should be not be used. - /// - /// Errors: - #[codec(index = 3)] - ExchangeAsset { give: Vec<MultiAsset>, receive: Vec<MultiAsset> }, - - /// Remove the asset(s) (`assets`) from holding and send a `WithdrawAsset` XCM message to a reserve location. - /// - /// - `assets`: The asset(s) to remove from holding. - /// - `reserve`: A valid location that acts as a reserve for all asset(s) in `assets`. The sovereign account - /// of this consensus system *on the reserve location* will have appropriate assets withdrawn and `effects` will - /// be executed on them. There will typically be only one valid location on any given asset/chain combination. - /// - `effects`: The orders to execute on the assets once withdrawn *on the reserve location*. - /// - /// Errors: - #[codec(index = 4)] - InitiateReserveWithdraw { assets: Vec<MultiAsset>, reserve: MultiLocation, effects: Vec<Order<()>> }, - - /// Remove the asset(s) (`assets`) from holding and send a `TeleportAsset` XCM message to a destination location. - /// - /// - `assets`: The asset(s) to remove from holding. - /// - `destination`: A valid location that has a bi-lateral teleportation arrangement. - /// - `effects`: The orders to execute on the assets once arrived *on the destination location*. - /// - /// Errors: - #[codec(index = 5)] - InitiateTeleport { assets: Vec<MultiAsset>, dest: MultiLocation, effects: Vec<Order<()>> }, - - /// Send a `Balances` XCM message with the `assets` value equal to the holding contents, or a portion thereof. - /// - /// - `query_id`: An identifier that will be replicated into the returned XCM message. - /// - `dest`: A valid destination for the returned XCM message. This may be limited to the current origin. - /// - `assets`: A filter for the assets that should be reported back. The assets reported back will be, asset- - /// wise, *the lesser of this value and the holding account*. No wildcards will be used when reporting assets - /// back. - /// - /// Errors: - #[codec(index = 6)] - QueryHolding { #[codec(compact)] query_id: u64, dest: MultiLocation, assets: Vec<MultiAsset> }, - - /// Pay for the execution of some Xcm with up to `weight` picoseconds of execution time, paying for this with - /// up to `fees` from the holding account. - /// - /// Errors: - #[codec(index = 7)] - BuyExecution { fees: MultiAsset, weight: u64, debt: u64, halt_on_error: bool, xcm: Vec<Xcm<Call>> }, -} - -pub mod opaque { - pub type Order = super::Order<()>; -} - -impl<Call> Order<Call> { - pub fn into<C>(self) -> Order<C> { Order::from(self) } - pub fn from<C>(order: Order<C>) -> Self { - use Order::*; - match order { - Null => Null, - DepositAsset { assets, dest } - => DepositAsset { assets, dest }, - DepositReserveAsset { assets, dest, effects } - => DepositReserveAsset { assets, dest, effects }, - ExchangeAsset { give, receive } - => ExchangeAsset { give, receive }, - InitiateReserveWithdraw { assets, reserve, effects } - => InitiateReserveWithdraw { assets, reserve, effects }, - InitiateTeleport { assets, dest, effects } - => InitiateTeleport { assets, dest, effects }, - QueryHolding { query_id, dest, assets } - => QueryHolding { query_id, dest, assets }, - BuyExecution { fees, weight, debt, halt_on_error, xcm } => { - let xcm = xcm.into_iter().map(Xcm::from).collect(); - BuyExecution { fees, weight, debt, halt_on_error, xcm } - }, - } - } -} diff --git a/xcm/src/v1/traits.rs b/xcm/src/v1/traits.rs deleted file mode 100644 index 6f3dccce1630..000000000000 --- a/xcm/src/v1/traits.rs +++ /dev/null @@ -1,246 +0,0 @@ -// Copyright 2021 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 <http://www.gnu.org/licenses/>. - -//! Cross-Consensus Message format data structures. - -use core::result; -use parity_scale_codec::{Encode, Decode}; - -use super::{MultiLocation, Xcm}; - -#[derive(Clone, Encode, Decode, Eq, PartialEq, Debug)] -pub enum Error { - Undefined, - Overflow, - /// The operation is intentionally unsupported. - Unimplemented, - UnhandledXcmVersion, - UnhandledXcmMessage, - UnhandledEffect, - EscalationOfPrivilege, - UntrustedReserveLocation, - UntrustedTeleportLocation, - DestinationBufferOverflow, - /// The message and destination was recognized as being reachable but the operation could not be completed. - /// A human-readable explanation of the specific issue is provided. - SendFailed(#[codec(skip)] &'static str), - /// The message and destination combination was not recognized as being reachable. - CannotReachDestination(MultiLocation, Xcm<()>), - MultiLocationFull, - FailedToDecode, - BadOrigin, - ExceedsMaxMessageSize, - FailedToTransactAsset(#[codec(skip)] &'static str), - /// Execution of the XCM would potentially result in a greater weight used than the pre-specified - /// weight limit. The amount that is potentially required is the parameter. - WeightLimitReached(Weight), - Wildcard, - /// The case where an XCM message has specified a optional weight limit and the weight required for - /// processing is too great. - /// - /// Used by: - /// - `Transact` - TooMuchWeightRequired, - /// The fees specified by the XCM message were not found in the holding account. - /// - /// Used by: - /// - `BuyExecution` - NotHoldingFees, - /// The weight of an XCM message is not computable ahead of execution. This generally means at least part - /// of the message is invalid, which could be due to it containing overly nested structures or an invalid - /// nested data segment (e.g. for the call in `Transact`). - WeightNotComputable, - /// The XCM did not pass the barrier condition for execution. The barrier condition differs on different - /// chains and in different circumstances, but generally it means that the conditions surrounding the message - /// were not such that the chain considers the message worth spending time executing. Since most chains - /// lift the barrier to execution on appropriate payment, presentation of an NFT voucher, or based on the - /// message origin, it means that none of those were the case. - Barrier, - /// Indicates that it is not possible for a location to have an asset be withdrawn or transferred from its - /// ownership. This probably means it doesn't own (enough of) it, but may also indicate that it is under a - /// lock, hold, freeze or is otherwise unavailable. - NotWithdrawable, - /// Indicates that the consensus system cannot deposit an asset under the ownership of a particular location. - LocationCannotHold, - /// The assets given to purchase weight is are insufficient for the weight desired. - TooExpensive, - /// The given asset is not handled. - AssetNotFound, -} - -impl From<()> for Error { - fn from(_: ()) -> Self { - Self::Undefined - } -} - -pub type Result = result::Result<(), Error>; - -/// Local weight type; execution time in picoseconds. -pub type Weight = u64; - -/// Outcome of an XCM execution. -#[derive(Clone, Encode, Decode, Eq, PartialEq, Debug)] -pub enum Outcome { - /// Execution completed successfully; given weight was used. - Complete(Weight), - /// Execution started, but did not complete successfully due to the given error; given weight was used. - Incomplete(Weight, Error), - /// Execution did not start due to the given error. - Error(Error), -} - -impl Outcome { - pub fn ensure_complete(self) -> Result { - match self { - Outcome::Complete(_) => Ok(()), - Outcome::Incomplete(_, e) => Err(e), - Outcome::Error(e) => Err(e), - } - } - pub fn ensure_execution(self) -> result::Result<Weight, Error> { - match self { - Outcome::Complete(w) => Ok(w), - Outcome::Incomplete(w, _) => Ok(w), - Outcome::Error(e) => Err(e), - } - } - /// How much weight was used by the XCM execution attempt. - pub fn weight_used(&self) -> Weight { - match self { - Outcome::Complete(w) => *w, - Outcome::Incomplete(w, _) => *w, - Outcome::Error(_) => 0, - } - } -} - -/// Type of XCM message executor. -pub trait ExecuteXcm<Call> { - /// Execute some XCM `message` from `origin` using no more than `weight_limit` weight. The weight limit is - /// a basic hard-limit and the implementation may place further restrictions or requirements on weight and - /// other aspects. - fn execute_xcm(origin: MultiLocation, message: Xcm<Call>, weight_limit: Weight) -> Outcome { - Self::execute_xcm_in_credit(origin, message, weight_limit, 0) - } - - /// Execute some XCM `message` from `origin` using no more than `weight_limit` weight. - /// - /// Some amount of `weight_credit` may be provided which, depending on the implementation, may allow - /// execution without associated payment. - fn execute_xcm_in_credit( - origin: MultiLocation, - message: Xcm<Call>, - weight_limit: Weight, - weight_credit: Weight, - ) -> Outcome; -} - -impl<C> ExecuteXcm<C> for () { - fn execute_xcm_in_credit( - _origin: MultiLocation, - _message: Xcm<C>, - _weight_limit: Weight, - _weight_credit: Weight, - ) -> Outcome { - Outcome::Error(Error::Unimplemented) - } -} - -/// Utility for sending an XCM message. -/// -/// These can be amalgamated in tuples to form sophisticated routing systems. In tuple format, each router might return -/// `CannotReachDestination` to pass the execution to the next sender item. Note that each `CannotReachDestination` -/// might alter the destination and the xcm message for to the next router. -/// -/// -/// # Example -/// ```rust -/// # use xcm::v0::{MultiLocation, Xcm, Junction, Error, OriginKind, SendXcm, Result}; -/// # use parity_scale_codec::Encode; -/// -/// /// A sender that only passes the message through and does nothing. -/// struct Sender1; -/// impl SendXcm for Sender1 { -/// fn send_xcm(destination: MultiLocation, message: Xcm<()>) -> Result { -/// return Err(Error::CannotReachDestination(destination, message)) -/// } -/// } -/// -/// /// A sender that accepts a message that has an X2 junction, otherwise stops the routing. -/// struct Sender2; -/// impl SendXcm for Sender2 { -/// fn send_xcm(destination: MultiLocation, message: Xcm<()>) -> Result { -/// if let MultiLocation::X2(j1, j2) = destination { -/// Ok(()) -/// } else { -/// Err(Error::Undefined) -/// } -/// } -/// } -/// -/// /// A sender that accepts a message from an X1 parent junction, passing through otherwise. -/// struct Sender3; -/// impl SendXcm for Sender3 { -/// fn send_xcm(destination: MultiLocation, message: Xcm<()>) -> Result { -/// match destination { -/// MultiLocation::X1(j) if j == Junction::Parent => Ok(()), -/// _ => Err(Error::CannotReachDestination(destination, message)), -/// } -/// } -/// } -/// -/// // A call to send via XCM. We don't really care about this. -/// # fn main() { -/// let call: Vec<u8> = ().encode(); -/// let message = Xcm::Transact { origin_type: OriginKind::Superuser, require_weight_at_most: 0, call: call.into() }; -/// let destination = MultiLocation::X1(Junction::Parent); -/// -/// assert!( -/// // Sender2 will block this. -/// <(Sender1, Sender2, Sender3) as SendXcm>::send_xcm(destination.clone(), message.clone()) -/// .is_err() -/// ); -/// -/// assert!( -/// // Sender3 will catch this. -/// <(Sender1, Sender3) as SendXcm>::send_xcm(destination.clone(), message.clone()) -/// .is_ok() -/// ); -/// # } -/// ``` -pub trait SendXcm { - /// Send an XCM `message` to a given `destination`. - /// - /// If it is not a destination which can be reached with this type but possibly could by others, then it *MUST* - /// return `CannotReachDestination`. Any other error will cause the tuple implementation to exit early without - /// trying other type fields. - fn send_xcm(destination: MultiLocation, message: Xcm<()>) -> Result; -} - -#[impl_trait_for_tuples::impl_for_tuples(30)] -impl SendXcm for Tuple { - fn send_xcm(destination: MultiLocation, message: Xcm<()>) -> Result { - for_tuples!( #( - // we shadow `destination` and `message` in each expansion for the next one. - let (destination, message) = match Tuple::send_xcm(destination, message) { - Err(Error::CannotReachDestination(d, m)) => (d, m), - o @ _ => return o, - }; - )* ); - Err(Error::CannotReachDestination(destination, message)) - } -} From ee80e03f413a2a2076759a3fd0313daacc391347 Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Fri, 30 Jul 2021 19:16:58 +0200 Subject: [PATCH 004/166] Draft next MultiAsset API. --- xcm/src/lib.rs | 15 + xcm/src/v0/mod.rs | 6 +- xcm/src/v0/multi_asset.rs | 43 +-- xcm/src/v0/multiasset.rs | 440 ++++++++++++++++++++++--- xcm/src/v0/order.rs | 21 +- xcm/xcm-builder/src/mock.rs | 2 +- xcm/xcm-executor/src/assets.rs | 577 +++++++++++---------------------- xcm/xcm-executor/src/lib.rs | 14 +- 8 files changed, 615 insertions(+), 503 deletions(-) diff --git a/xcm/src/lib.rs b/xcm/src/lib.rs index 1addc44bd552..8b459adc7185 100644 --- a/xcm/src/lib.rs +++ b/xcm/src/lib.rs @@ -63,3 +63,18 @@ pub enum VersionedMultiLocation { pub enum VersionedMultiAsset { V0(v0::MultiAsset), } + +impl From<v0::MultiAsset> for VersionedMultiAsset { + fn from(x: v0::MultiAsset) -> Self { + VersionedMultiAsset::V0(x) + } +} + +impl core::convert::TryFrom<VersionedMultiAsset> for v0::MultiAsset { + type Error = (); + fn try_from(x: VersionedMultiAsset) -> core::result::Result<Self, ()> { + match x { + VersionedMultiAsset::V0(x) => Ok(x), + } + } +} diff --git a/xcm/src/v0/mod.rs b/xcm/src/v0/mod.rs index 619e9b9bc75a..cc8044ea19d2 100644 --- a/xcm/src/v0/mod.rs +++ b/xcm/src/v0/mod.rs @@ -20,7 +20,7 @@ use core::{result, convert::TryFrom, fmt::Debug}; use derivative::Derivative; use alloc::vec::Vec; use parity_scale_codec::{self, Encode, Decode}; -use crate::{VersionedMultiAsset, DoubleEncoded, VersionedXcm}; +use crate::{VersionedMultiAsset, VersionedWildMultiAsset, DoubleEncoded, VersionedXcm}; mod junction; mod multi_asset; @@ -30,7 +30,9 @@ mod traits; pub mod multiasset; // the new multiasset. pub use junction::{Junction, NetworkId, BodyId, BodyPart}; -pub use multi_asset::{MultiAsset, AssetInstance}; +pub use multiasset::{ + AssetId, AssetInstance, MultiAsset, MultiAssets, MultiAssetFilter, Fungibility, WildMultiAsset, WildFungibility +}; pub use multi_location::MultiLocation; pub use order::Order; pub use traits::{Error, Result, SendXcm, ExecuteXcm, Outcome}; diff --git a/xcm/src/v0/multi_asset.rs b/xcm/src/v0/multi_asset.rs index dc682902df65..d7065d3e1d8e 100644 --- a/xcm/src/v0/multi_asset.rs +++ b/xcm/src/v0/multi_asset.rs @@ -20,33 +20,7 @@ use core::{result, convert::TryFrom}; use alloc::vec::Vec; use parity_scale_codec::{self, Encode, Decode}; -use super::{MultiLocation, VersionedMultiAsset}; - -/// A general identifier for an instance of a non-fungible asset class. -#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug)] -pub enum AssetInstance { - /// Undefined - used if the NFA class has only one instance. - Undefined, - - /// A compact index. Technically this could be greater than `u128`, but this implementation supports only - /// values up to `2**128 - 1`. - Index { #[codec(compact)] id: u128 }, - - /// A 4-byte fixed-length datum. - Array4([u8; 4]), - - /// An 8-byte fixed-length datum. - Array8([u8; 8]), - - /// A 16-byte fixed-length datum. - Array16([u8; 16]), - - /// A 32-byte fixed-length datum. - Array32([u8; 32]), - - /// An arbitrary piece of data. Use only when necessary. - Blob(Vec<u8>), -} +use super::{MultiLocation, VersionedMultiAsset, AssetInstance}; /// A single general identifier for an asset. /// @@ -306,21 +280,6 @@ impl MultiAsset { } } -impl From<MultiAsset> for VersionedMultiAsset { - fn from(x: MultiAsset) -> Self { - VersionedMultiAsset::V0(x) - } -} - -impl TryFrom<VersionedMultiAsset> for MultiAsset { - type Error = (); - fn try_from(x: VersionedMultiAsset) -> result::Result<Self, ()> { - match x { - VersionedMultiAsset::V0(x) => Ok(x), - } - } -} - #[cfg(test)] mod tests { use super::*; diff --git a/xcm/src/v0/multiasset.rs b/xcm/src/v0/multiasset.rs index 8e1839719f09..010f1ce4c1da 100644 --- a/xcm/src/v0/multiasset.rs +++ b/xcm/src/v0/multiasset.rs @@ -12,13 +12,51 @@ // 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 <http://www.gnu.org/licenses/>. +// along with Polkadot. If not, see <http://www.gnu.org/licenses/>. -//! Cross-Consensus Message format asset data structure. +//! Cross-Consensus Message format asset data structures. +//! +//! This encompasses four types for repesenting assets: +//! - `MultiAsset`: A description of a single asset, either an instance of a non-fungible or some amount of a fungible. +//! - `MultiAssets`: A collection of `MultiAsset`s. These are stored in a `Vec` and sorted with fungibles first. +//! - `Wild`: A single asset wildcard, this can either be "all" assets, or all assets of a specific kind. +//! - `MultiAssetFilter`: A combination of `Wild` and `MultiAssets` designed for efficiently filtering an XCM holding +//! account. +use core::convert::{TryFrom, TryInto}; use alloc::vec::Vec; use parity_scale_codec::{self as codec, Encode, Decode}; -use super::{MultiLocation, multi_asset::{AssetInstance, MultiAsset as OldMultiAsset}}; +use super::{ + MultiLocation, multi_asset::MultiAsset as OldMultiAsset, VersionedMultiAsset, + VersionedWildMultiAsset, +}; +use core::cmp::Ordering; + +/// A general identifier for an instance of a non-fungible asset class. +#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug)] +pub enum AssetInstance { + /// Undefined - used if the NFA class has only one instance. + Undefined, + + /// A compact index. Technically this could be greater than `u128`, but this implementation supports only + /// values up to `2**128 - 1`. + Index { #[codec(compact)] id: u128 }, + + /// A 4-byte fixed-length datum. + Array4([u8; 4]), + + /// An 8-byte fixed-length datum. + Array8([u8; 8]), + + /// A 16-byte fixed-length datum. + Array16([u8; 16]), + + /// A 32-byte fixed-length datum. + Array32([u8; 32]), + + /// An arbitrary piece of data. Use only when necessary. + Blob(Vec<u8>), +} /// Classification of an asset being concrete or abstract. #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)] @@ -28,44 +66,126 @@ pub enum AssetId { } impl AssetId { - /// Prepend a MultiLocation to a concrete asset, giving it a new root location. + /// Prepend a `MultiLocation` to a concrete asset, giving it a new root location. pub fn reanchor(&mut self, prepend: &MultiLocation) -> Result<(), ()> { if let AssetId::Concrete(ref mut l) = self { l.prepend_with(prepend.clone()).map_err(|_| ())?; } Ok(()) } + + /// Use the value of `self` along with a `fun` fungibility specifier to create the corresponding `MultiAsset` value. + pub fn into_multiasset(self, fun: Fungibility) -> MultiAsset { + MultiAsset { fun, id: self } + } + + /// Use the value of `self` along with a `fun` fungibility specifier to create the corresponding `WildMultiAsset` + /// definite (`Asset`) value. + pub fn into_wild(self, fun: Fungibility) -> WildMultiAsset { + WildMultiAsset::Asset(fun, self) + } + + /// Use the value of `self` along with a `fun` fungibility specifier to create the corresponding `WildMultiAsset` + /// wildcard (`AllOf`) value. + pub fn into_allof(self, fun: WildFungibility) -> WildMultiAsset { + WildMultiAsset::AllOf(fun, self) + } } -/// Classification of whether an asset is fungible or not, along with an optional amount or instance. +/// Classification of whether an asset is fungible or not, along with an mandatory amount or instance. #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)] pub enum Fungibility { - Fungible(Option<u128>), - NonFungible(Option<AssetInstance>), + Fungible(u128), + NonFungible(AssetInstance), } -#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)] -pub enum MultiAsset { - None, - Asset(Fungibility, Option<AssetId>), - All, +impl Fungibility { + pub fn is_kind(&self, w: WildFungibility) -> bool { + use {Fungibility::*, WildFungibility::{Fungible as WildFungible, NonFungible as WildNonFungible}}; + matches!((self, w), (Fungible(_), WildFungible) | (NonFungible(_), WildNonFungible)) + } +} + +impl From<u128> for Fungibility { + fn from(amount: u128) -> Fungibility { + debug_assert_ne!(amount, 0); + Fungibility::Fungible(amount) + } +} + +impl From<AssetInstance> for Fungibility { + fn from(instance: AssetInstance) -> Fungibility { + Fungibility::NonFungible(instance) + } +} + + + + +#[derive(Clone, Eq, PartialEq, Debug)] +pub struct MultiAsset { + pub id: AssetId, + pub fun: Fungibility, +} + +impl PartialOrd for MultiAsset { + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + Some(self.cmp(other)) + } +} + +impl Ord for MultiAsset { + fn cmp(&self, other: &Self) -> Ordering { + match (&self.fun, &other.fun) { + (Fungibility::Fungible(..), Fungibility::NonFungible(..)) => return Ordering::Less, + (Fungibility::NonFungible(..), Fungibility::Fungible(..)) => return Ordering::Greater, + } + (&self.id, &self.fun).cmp((&other.id, &other.fun)) + } } impl From<(AssetId, Fungibility)> for MultiAsset { - fn from((asset_id, fungibility): (AssetId, Fungibility)) -> MultiAsset { - MultiAsset::Asset(fungibility, Some(asset_id)) + fn from((id, fun): (AssetId, Fungibility)) -> MultiAsset { + MultiAsset { fun, id } } } -impl From<Fungibility> for MultiAsset { - fn from(fungibility: Fungibility) -> MultiAsset { - MultiAsset::Asset(fungibility, None) +impl From<(AssetId, u128)> for MultiAsset { + fn from((id, amount): (AssetId, u128)) -> MultiAsset { + MultiAsset { fun: amount.into(), id } + } +} + +impl From<(AssetId, AssetInstance)> for MultiAsset { + fn from((id, instance): (AssetId, AssetInstance)) -> MultiAsset { + MultiAsset { fun: instance.into(), id } + } +} + +impl From<MultiAsset> for OldMultiAsset { + fn from(a: MultiAsset) -> Self { + use {AssetId::*, Fungibility::*, OldMultiAsset::*}; + match (a.fun, a.id) { + (Fungible(amount), Concrete(id)) => ConcreteFungible { id, amount }, + (Fungible(amount), Abstract(id)) => AbstractFungible { id, amount }, + (NonFungible(instance), Concrete(class)) => ConcreteNonFungible { class, instance }, + (NonFungible(instance), Abstract(class)) => AbstractNonFungible { class, instance }, + } } } -impl From<()> for MultiAsset { - fn from(_: ()) -> MultiAsset { - MultiAsset::None +impl TryFrom<OldMultiAsset> for MultiAsset { + type Error = (); + fn try_from(a: OldMultiAsset) -> Result<Self, ()> { + use {AssetId::*, Fungibility::*, OldMultiAsset::*}; + let (fun, id) = match a { + ConcreteFungible { id, amount } if amount > 0 => (Fungible(amount), Concrete(id)), + AbstractFungible { id, amount } if amount > 0 => (Fungible(amount), Abstract(id)), + ConcreteNonFungible { class, instance } => (NonFungible(instance), Concrete(class)), + AbstractNonFungible { class, instance } => (NonFungible(instance), Abstract(class)), + _ => return Err(()), + }; + Ok(MultiAsset { fun, id }) } } @@ -76,53 +196,273 @@ impl Encode for MultiAsset { } impl Decode for MultiAsset { + fn decode<I: codec::Input>(input: &mut I) -> Result<Self, parity_scale_codec::Error> { + OldMultiAsset::decode(input) + .and_then(|r| TryInto::try_into(r).map_err(|_| "Unsupported wildcard".into()))? + } +} + +impl MultiAsset { + fn is_fungible(&self, maybe_id: Option<AssetId>) -> bool { + use Fungibility::*; + matches!(self.fun, Fungible(..)) && maybe_id.map_or(true, |i| i == self.id) + } + + fn is_non_fungible(&self, maybe_id: Option<AssetId>) -> bool { + use Fungibility::*; + matches!(self.fun, NonFungible(..)) && maybe_id.map_or(true, |i| i == self.id) + } + + /// Prepend a `MultiLocation` to a concrete asset, giving it a new root location. + pub fn reanchor(&mut self, prepend: &MultiLocation) -> Result<(), ()> { + self.id.reanchor(prepend) + } + + /// Returns true if `self` is a super-set of the given `inner`. + pub fn contains(&self, inner: &MultiAsset) -> bool { + use {MultiAsset::*, Fungibility::*}; + if self.id == inner.id { + match (&self.fun, &inner.fun) { + (Fungible(a), Fungible(i)) if a >= i => return true, + (NonFungible(a), NonFungible(i)) if a == i => return true, + _ => (), + } + } + false + } +} + + + +/// A vec of MultiAssets. There may be no duplicate fungible items in here and when decoding, they must be sorted. +#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode)] +pub struct MultiAssets(Vec<MultiAsset>); + +impl Decode for MultiAssets { + fn decode<I: codec::Input>(input: &mut I) -> Result<Self, parity_scale_codec::Error> { + let r = Vec::<MultiAsset>::decode(input)?; + if r.is_empty() { return Ok(Self(Vec::new())) } + r.iter().skip(1).try_fold(&r[0], |a, b| { + if a.id < b.id || a < b && (a.is_non_fungible(None) || b.is_non_fungible(None)) { + Ok(b) + } else { + Err("Unsupported wildcard".into()) + } + })?; + Ok(Self(r)) + } +} + +impl From<MultiAssets> for Vec<OldMultiAsset> { + fn from(a: MultiAssets) -> Self { + a.0.into_iter().map(OldMultiAsset::from).collect() + } +} + +impl TryFrom<Vec<OldMultiAsset>> for MultiAssets { + type Error = (); + fn try_from(a: Vec<OldMultiAsset>) -> Result<Self, ()> { + a.0.into_iter().map(MultiAsset::try_from).collect() + } +} + +impl MultiAssets { + /// A new (empty) value. + pub fn new() -> Self { + Self(Vec::new()) + } + + /// Add some asset onto the multiasset list. This is quite a laborious operation since it maintains the ordering. + pub fn push(&mut self, a: MultiAsset) { + if let Fungibility::Fungible(ref amount) = a.fun { + for asset in self.0.iter_mut().filter(|x| x.id == a.id) { + if let Fungibility::Fungible(ref mut balance) = asset.fun { + *balance += *amount; + return + } + } + } + self.0.push(a); + self.0.sort(); + } + + /// Returns `true` if this definitely represents no asset. + pub fn is_none(&self) -> bool { + self.0.is_empty() + } + + /// Returns true if `self` is a super-set of the given `inner`. + pub fn contains(&self, inner: &MultiAsset) -> bool { + use {MultiAsset::*, Fungibility::*}; + self.0.iter().any(|i| i.contains(inner)) + } + + /// Consume `self` and return the inner vec. + pub fn drain(self) -> Vec<MultiAsset> { + self.0 + } + + /// Return a reference to the inner vec. + pub fn inner(&self) -> &Vec<MultiAsset> { + &self.0 + } + + /// Prepend a `MultiLocation` to any concrete asset items, giving it a new root location. + pub fn reanchor(&mut self, prepend: &MultiLocation) -> Result<(), ()> { + self.0.iter_mut().try_for_each(|i| i.reanchor(prepend)) + } +} + + + + + +/// Classification of whether an asset is fungible or not, along with an optional amount or instance. +#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug)] +pub enum WildFungibility { + Fungible, + NonFungible, +} + +#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)] +pub enum WildMultiAsset { + All, + // TODO: AllOf { fun: WildFungibility, id: AssetId } + AllOf(WildFungibility, AssetId), +} + +impl Encode for WildMultiAsset { + fn encode(&self) -> Vec<u8> { + OldMultiAsset::from(self.clone()).encode() + } +} + +impl Decode for WildMultiAsset { fn decode<I: codec::Input>(input: &mut I) -> Result<Self, parity_scale_codec::Error> { OldMultiAsset::decode(input).map(Into::into) } } -impl From<MultiAsset> for OldMultiAsset { - fn from(a: MultiAsset) -> Self { - use {AssetId::*, Fungibility::*, OldMultiAsset::*, MultiAsset::Asset}; +impl From<WildMultiAsset> for OldMultiAsset { + fn from(a: WildMultiAsset) -> Self { + use {AssetId::*, Fungibility::*, OldMultiAsset::*, WildMultiAsset::AllOf}; match a { - MultiAsset::None => OldMultiAsset::None, - MultiAsset::All => All, + WildMultiAsset::All => All, + AllOf(WildFungibility::Fungible, Concrete(id)) => AllConcreteFungible { id }, + AllOf(WildFungibility::Fungible, Abstract(id)) => AllAbstractFungible { id }, + AllOf(WildFungibility::NonFungible, Concrete(class)) => AllConcreteNonFungible { class }, + AllOf(WildFungibility::NonFungible, Abstract(class)) => AllAbstractNonFungible { class }, + } + } +} - Asset(Fungible(_), Option::None) => AllFungible, - Asset(NonFungible(_), Option::None) => AllNonFungible, +impl TryFrom<OldMultiAsset> for WildMultiAsset { + type Error = (); + fn try_from(a: OldMultiAsset) -> Result<Self, ()> { + use {AssetId::*, Fungibility::*, OldMultiAsset::*, WildMultiAsset::AllOf}; + Ok(match a { + All => WildMultiAsset::All, + AllConcreteFungible { id } => AllOf(WildFungibility::Fungible, Concrete(id)), + AllAbstractFungible { id } => AllOf(WildFungibility::Fungible, Abstract(id)), + AllConcreteNonFungible { class } => AllOf(WildFungibility::NonFungible, Concrete(class)), + AllAbstractNonFungible { class } => AllOf(WildFungibility::NonFungible, Abstract(class)), + _ => return Err(()), + }) + } +} - Asset(Fungible(Option::None), Some(Concrete(id))) => AllConcreteFungible { id }, - Asset(Fungible(Option::None), Some(Abstract(id))) => AllAbstractFungible { id }, - Asset(NonFungible(Option::None), Some(Concrete(class))) => AllConcreteNonFungible { class }, - Asset(NonFungible(Option::None), Some(Abstract(class))) => AllAbstractNonFungible { class }, +impl WildMultiAsset { + /// Returns true if `self` is a super-set of the given `inner`. + /// + /// Typically, any wildcard is never contained in anything else, and a wildcard can contain any other non-wildcard. + /// For more details, see the implementation and tests. + pub fn contains(&self, inner: &MultiAsset) -> bool { + use WildMultiAsset::*; + match self { + AllOf(fun, id) => inner.fun.is_kind(*fun) && inner.id == id, + All => true, + } + } - Asset(Fungible(Some(amount)), Some(Concrete(id))) => ConcreteFungible { id, amount }, - Asset(Fungible(Some(amount)), Some(Abstract(id))) => AbstractFungible { id, amount }, - Asset(NonFungible(Some(instance)), Some(Concrete(class))) => ConcreteNonFungible { class, instance }, - Asset(NonFungible(Some(instance)), Some(Abstract(class))) => AbstractNonFungible { class, instance }, + /// Prepend a `MultiLocation` to any concrete asset components, giving it a new root location. + pub fn reanchor(&mut self, prepend: &MultiLocation) -> Result<(), ()> { + use WildMultiAsset::*; + match self { + AllOf(_, ref mut id) => id.prepend_with(prepend.clone()).map_err(|_| ()), + _ => Ok(()), } } } -impl From<OldMultiAsset> for MultiAsset { - fn from(a: OldMultiAsset) -> Self { - use {AssetId::*, Fungibility::*, OldMultiAsset::*, MultiAsset::Asset}; + + + + +/// `MultiAsset` collection, either `MultiAssets` or a single wildcard. Note: vectors of wildcards +/// whose encoding is supported in XCM v0 are unsupported in this implementation and will result in a decode error. +#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)] +pub enum MultiAssetFilter { + Assets(MultiAssets), + Wild(WildMultiAsset), +} + +impl From<MultiAssetFilter> for Vec<OldMultiAsset> { + fn from(a: MultiAssetFilter) -> Self { + use MultiAssetFilter::*; match a { - None => MultiAsset::None, - All => MultiAsset::All, + Assets(assets) => assets.0.into_iter().map(OldMultiAsset::from).collect(), + Wild(wild) => vec![wild.into()], + } + } +} - AllFungible => Asset(Fungible(Option::None), Option::None), - AllNonFungible => Asset(NonFungible(Option::None), Option::None), +impl TryFrom<Vec<OldMultiAsset>> for MultiAssetFilter { + type Error = (); + fn try_from(old_assets: Vec<OldMultiAsset>) -> Result<Self, ()> { + use MultiAssetFilter::*; + if old_assets.is_empty() { + return Ok(Assets(MultiAssets::new())) + } + if let (1, Ok(wild)) = (old_assets.len(), old_assets[0].try_into()) { + return Ok(Wild(wild)) + } - AllConcreteFungible { id } => Asset(Fungible(Option::None), Some(Concrete(id))), - AllAbstractFungible { id } => Asset(Fungible(Option::None), Some(Abstract(id))), - AllConcreteNonFungible { class } => Asset(NonFungible(Option::None), Some(Concrete(class))), - AllAbstractNonFungible { class } => Asset(NonFungible(Option::None), Some(Abstract(class))), + old_assets.into_iter().map(MultiAsset::try_from).collect() + } +} + +impl MultiAssetFilter { + /// Returns `true` if the `MultiAsset` is a wildcard and refers to sets of assets, instead of just one. + pub fn is_wildcard(&self) -> bool { + matches!(self, MultiAssetFilter::Wild(..)) + } - ConcreteFungible { id, amount } => Asset(Fungible(Some(amount)), Some(Concrete(id))), - AbstractFungible { id, amount } => Asset(Fungible(Some(amount)), Some(Abstract(id))), - ConcreteNonFungible { class, instance } => Asset(NonFungible(Some(instance)), Some(Concrete(class))), - AbstractNonFungible { class, instance } => Asset(NonFungible(Some(instance)), Some(Abstract(class))), + /// Returns `true` if the `MultiAsset` is not a wildcard. + pub fn is_definite(&self) -> bool { + !self.is_wildcard() + } + + /// Returns `true` if this definitely represents no asset. + pub fn is_none(&self) -> bool { + matches!(self, MultiAssetFilter::Assets(a) if a.is_none()) + } + + /// Returns true if `self` is a super-set of the given `inner`. + /// + /// Typically, any wildcard is never contained in anything else, and a wildcard can contain any other non-wildcard. + /// For more details, see the implementation and tests. + pub fn contains(&self, inner: &MultiAsset) -> bool { + match self { + MultiAssetFilter::Assets(ref assets) => assets.contains(inner), + MultiAssetFilter::Wild(ref wild) => wild.contains(inner), + } + } + + /// Prepend a `MultiLocation` to any concrete asset components, giving it a new root location. + pub fn reanchor(&mut self, prepend: &MultiLocation) -> Result<(), ()> { + match self { + MultiAssetFilter::Assets(ref mut assets) => assets.reanchor(prepend), + MultiAssetFilter::Wild(ref mut wild) => wild.reanchor(prepend), } } } diff --git a/xcm/src/v0/order.rs b/xcm/src/v0/order.rs index 776ac3691c74..fa8aa6df3393 100644 --- a/xcm/src/v0/order.rs +++ b/xcm/src/v0/order.rs @@ -19,7 +19,7 @@ use alloc::vec::Vec; use derivative::Derivative; use parity_scale_codec::{self, Encode, Decode}; -use super::{MultiAsset, MultiLocation, Xcm}; +use super::{MultiAsset, WildMultiAsset, MultiAssetFilter, MultiLocation, Xcm}; /// An instruction to be executed on some or all of the assets in holding, used by asset-related XCM messages. #[derive(Derivative, Encode, Decode)] @@ -39,7 +39,7 @@ pub enum Order<Call> { /// /// Errors: #[codec(index = 1)] - DepositAsset { assets: Vec<MultiAsset>, dest: MultiLocation }, + DepositAsset { assets: MultiAssetFilter, dest: MultiLocation }, /// Remove the asset(s) (`assets`) from holding and place equivalent assets under the ownership of `dest` within /// this consensus system. @@ -53,19 +53,18 @@ pub enum Order<Call> { /// /// Errors: #[codec(index = 2)] - DepositReserveAsset { assets: Vec<MultiAsset>, dest: MultiLocation, effects: Vec<Order<()>> }, + DepositReserveAsset { assets: MultiAssetFilter, dest: MultiLocation, effects: Vec<Order<()>> }, /// Remove the asset(s) (`give`) from holding and replace them with alternative assets. /// /// The minimum amount of assets to be received into holding for the order not to fail may be stated. /// /// - `give`: The asset(s) to remove from holding. - /// - `receive`: The minimum amount of assets(s) which `give` should be exchanged for. The meaning of wildcards - /// is undefined and they should be not be used. + /// - `receive`: The minimum amount of assets(s) which `give` should be exchanged for. /// /// Errors: #[codec(index = 3)] - ExchangeAsset { give: Vec<MultiAsset>, receive: Vec<MultiAsset> }, + ExchangeAsset { give: MultiAssetFilter, receive: Vec<MultiAsset> }, /// Remove the asset(s) (`assets`) from holding and send a `WithdrawAsset` XCM message to a reserve location. /// @@ -77,7 +76,7 @@ pub enum Order<Call> { /// /// Errors: #[codec(index = 4)] - InitiateReserveWithdraw { assets: Vec<MultiAsset>, reserve: MultiLocation, effects: Vec<Order<()>> }, + InitiateReserveWithdraw { assets: MultiAssetFilter, reserve: MultiLocation, effects: Vec<Order<()>> }, /// Remove the asset(s) (`assets`) from holding and send a `TeleportAsset` XCM message to a destination location. /// @@ -87,7 +86,7 @@ pub enum Order<Call> { /// /// Errors: #[codec(index = 5)] - InitiateTeleport { assets: Vec<MultiAsset>, dest: MultiLocation, effects: Vec<Order<()>> }, + InitiateTeleport { assets: MultiAssetFilter, dest: MultiLocation, effects: Vec<Order<()>> }, /// Send a `Balances` XCM message with the `assets` value equal to the holding contents, or a portion thereof. /// @@ -99,14 +98,16 @@ pub enum Order<Call> { /// /// Errors: #[codec(index = 6)] - QueryHolding { #[codec(compact)] query_id: u64, dest: MultiLocation, assets: Vec<MultiAsset> }, + QueryHolding { #[codec(compact)] query_id: u64, dest: MultiLocation, assets: MultiAssetFilter }, /// Pay for the execution of some XCM with up to `weight` picoseconds of execution time, paying for this with /// up to `fees` from the holding account. /// + /// - `fees`: The asset(s) to remove from holding to pay for fees. + /// /// Errors: #[codec(index = 7)] - BuyExecution { fees: MultiAsset, weight: u64, debt: u64, halt_on_error: bool, xcm: Vec<Xcm<Call>> }, + BuyExecution { fees: WildMultiAsset, weight: u64, debt: u64, halt_on_error: bool, xcm: Vec<Xcm<Call>> }, } pub mod opaque { diff --git a/xcm/xcm-builder/src/mock.rs b/xcm/xcm-builder/src/mock.rs index 56d7d753e49e..6e9b7ff5a322 100644 --- a/xcm/xcm-builder/src/mock.rs +++ b/xcm/xcm-builder/src/mock.rs @@ -122,7 +122,7 @@ pub fn add_asset(who: u64, what: MultiAsset) { ASSETS.with(|a| a.borrow_mut() .entry(who) .or_insert(Assets::new()) - .saturating_subsume(what) + .subsume(what) ); } diff --git a/xcm/xcm-executor/src/assets.rs b/xcm/xcm-executor/src/assets.rs index c0d35052482b..97c5fbbc15a5 100644 --- a/xcm/xcm-executor/src/assets.rs +++ b/xcm/xcm-executor/src/assets.rs @@ -15,44 +15,16 @@ // along with Polkadot. If not, see <http://www.gnu.org/licenses/>. use sp_std::{prelude::*, mem, collections::{btree_map::BTreeMap, btree_set::BTreeSet}}; -use xcm::v0::{MultiAsset, MultiLocation, AssetInstance}; +use xcm::v0::{ + MultiAsset, MultiAssets, MultiLocation, AssetInstance, + MultiAssetFilter::{self, Assets, Wild}, + AssetId::{self, Concrete, Abstract}, + WildMultiAsset::{self, All, AllOf}, + Fungibility::{Fungible, NonFungible}, + WildFungibility::{Fungible as WildFungible, NonFungible as WildNonFungible}, +}; use sp_runtime::RuntimeDebug; -/// Classification of an asset being concrete or abstract. -#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, RuntimeDebug)] -pub enum AssetId { - Concrete(MultiLocation), - Abstract(Vec<u8>), -} - -impl AssetId { - /// Prepend a `MultiLocation` to a concrete asset, giving it a new root location. - pub fn prepend_location(&mut self, prepend: &MultiLocation) -> Result<(), ()> { - if let AssetId::Concrete(ref mut l) = self { - l.prepend_with(prepend.clone()).map_err(|_| ())?; - } - Ok(()) - } - - /// Use the value of `self` along with an `amount to create the corresponding `MultiAsset` value for a - /// fungible asset. - pub fn into_fungible_multiasset(self, amount: u128) -> MultiAsset { - match self { - AssetId::Concrete(id) => MultiAsset::ConcreteFungible { id, amount }, - AssetId::Abstract(id) => MultiAsset::AbstractFungible { id, amount }, - } - } - - /// Use the value of `self` along with an `instance to create the corresponding `MultiAsset` value for a - /// non-fungible asset. - pub fn into_non_fungible_multiasset(self, instance: AssetInstance) -> MultiAsset { - match self { - AssetId::Concrete(class) => MultiAsset::ConcreteNonFungible { class, instance }, - AssetId::Abstract(class) => MultiAsset::AbstractNonFungible { class, instance }, - } - } -} - /// List of non-wildcard fungible and non-fungible assets. #[derive(Default, Clone, RuntimeDebug, Eq, PartialEq)] pub struct Assets { @@ -69,7 +41,7 @@ impl From<Vec<MultiAsset>> for Assets { fn from(assets: Vec<MultiAsset>) -> Assets { let mut result = Self::default(); for asset in assets.into_iter() { - result.saturating_subsume(asset) + result.subsume(asset) } result } @@ -84,181 +56,64 @@ impl From<Assets> for Vec<MultiAsset> { impl From<MultiAsset> for Assets { fn from(asset: MultiAsset) -> Assets { let mut result = Self::default(); - result.saturating_subsume(asset); + result.subsume(asset); result } } +/// An error emitted by `take` operations. +pub enum TakeError { + /// There was an attempt to take an asset without saturating (enough of) which did not exist. + AssetUnderflow(MultiAsset), +} + impl Assets { /// New value, containing no assets. pub fn new() -> Self { Self::default() } - /// An iterator over the fungible assets. + /// A borrowing iterator over the fungible assets. pub fn fungible_assets_iter<'a>(&'a self) -> impl Iterator<Item=MultiAsset> + 'a { - self.fungible.iter() - .map(|(id, &amount)| match id.clone() { - AssetId::Concrete(id) => MultiAsset::ConcreteFungible { id, amount }, - AssetId::Abstract(id) => MultiAsset::AbstractFungible { id, amount }, - }) + self.fungible.iter().map(|(id, &amount)| MultiAsset { fun: Fungible(amount), id: id.clone() }) } - /// An iterator over the non-fungible assets. + /// A borrowing iterator over the non-fungible assets. pub fn non_fungible_assets_iter<'a>(&'a self) -> impl Iterator<Item=MultiAsset> + 'a { - self.non_fungible.iter() - .map(|&(ref class, ref instance)| match class.clone() { - AssetId::Concrete(class) => MultiAsset::ConcreteNonFungible { class, instance: instance.clone() }, - AssetId::Abstract(class) => MultiAsset::AbstractNonFungible { class, instance: instance.clone() }, - }) + self.non_fungible.iter().map(|(id, instance)| MultiAsset { fun: NonFungible(instance.clone()), id: id.clone() }) } - /// An iterator over all assets. + /// A consuming iterator over all assets. pub fn into_assets_iter(self) -> impl Iterator<Item=MultiAsset> { - let fungible = self.fungible.into_iter() - .map(|(id, amount)| match id { - AssetId::Concrete(id) => MultiAsset::ConcreteFungible { id, amount }, - AssetId::Abstract(id) => MultiAsset::AbstractFungible { id, amount }, - }); - let non_fungible = self.non_fungible.into_iter() - .map(|(id, instance)| match id { - AssetId::Concrete(class) => MultiAsset::ConcreteNonFungible { class, instance }, - AssetId::Abstract(class) => MultiAsset::AbstractNonFungible { class, instance }, - }); - fungible.chain(non_fungible) - } - - /// An iterator over all assets. + self.fungible.into_iter().map(|(id, amount)| MultiAsset { fun: Fungible(amount), id }) + .chain(self.non_fungible.into_iter().map(|(id, instance)| MultiAsset { fun: NonFungible(instance), id })) + } + + /// A borrowing iterator over all assets. pub fn assets_iter<'a>(&'a self) -> impl Iterator<Item=MultiAsset> + 'a { - let fungible = self.fungible_assets_iter(); - let non_fungible = self.non_fungible_assets_iter(); - fungible.chain(non_fungible) + self.fungible_assets_iter().chain(self.non_fungible_assets_iter()) } /// Mutate `self` to contain all given `assets`, saturating if necessary. - /// - /// Wildcards in `assets` are ignored. - pub fn saturating_subsume_all(&mut self, assets: Assets) { - // OPTIMIZE: Could be done with a much faster btree entry merge and only sum the entries with the - // same key. + pub fn subsume_assets(&mut self, assets: Assets) { + // TODO: Could be done with a much faster btree entry merge and only sum the entries with the + // same key. for asset in assets.into_assets_iter() { - self.saturating_subsume(asset) + self.subsume(asset) } } /// Mutate `self` to contain the given `asset`, saturating if necessary. /// /// Wildcard values of `asset` do nothing. - pub fn saturating_subsume(&mut self, asset: MultiAsset) { - match asset { - MultiAsset::ConcreteFungible { id, amount } => { - self.saturating_subsume_fungible(AssetId::Concrete(id), amount); - } - MultiAsset::AbstractFungible { id, amount } => { - self.saturating_subsume_fungible(AssetId::Abstract(id), amount); - } - MultiAsset::ConcreteNonFungible { class, instance} => { - self.saturating_subsume_non_fungible(AssetId::Concrete(class), instance); - } - MultiAsset::AbstractNonFungible { class, instance} => { - self.saturating_subsume_non_fungible(AssetId::Abstract(class), instance); - } - _ => (), + pub fn subsume(&mut self, asset: MultiAsset) { + match asset.fun { + Fungible(amount) => self.fungible + .entry(asset.id) + .and_modify(|e| *e = e.saturating_add(amount)) + .or_insert(amount), + NonFungible(instance) => self.non_fungible.insert((asset.id, instance)), } } - - /// Consumes `self` and returns its original value excluding `asset` iff it contains at least `asset`. - /// - /// Wildcard assets in `self` will result in an error. - /// - /// `asset` may be a wildcard and are evaluated in the context of `self`. - /// - /// Returns `Ok` with the `self` minus `asset` and the non-wildcard equivalence of `asset` taken if `self` - /// contains `asset`, and `Err` with `self` otherwise. - pub fn less(mut self, asset: MultiAsset) -> Result<(Self, Assets), Self> { - match self.try_take(asset) { - Ok(taken) => Ok((self, taken)), - Err(()) => Err(self), - } - } - - /// Mutates `self` to its original value less `asset` and returns `true` iff it contains at least `asset`. - /// - /// Wildcard assets in `self` will result in an error. - /// - /// `asset` may be a wildcard and are evaluated in the context of `self`. - /// - /// Returns `Ok` with the non-wildcard equivalence of `asset` taken and mutates `self` to its value minus - /// `asset` if `self` contains `asset`, and return `Err` otherwise. - pub fn try_take(&mut self, asset: MultiAsset) -> Result<Assets, ()> { - match asset { - MultiAsset::None => Ok(Assets::new()), - MultiAsset::ConcreteFungible { id, amount } => self.try_take_fungible(AssetId::Concrete(id), amount), - MultiAsset::AbstractFungible { id, amount } => self.try_take_fungible(AssetId::Abstract(id), amount), - MultiAsset::ConcreteNonFungible { class, instance} => self.try_take_non_fungible(AssetId::Concrete(class), instance), - MultiAsset::AbstractNonFungible { class, instance} => self.try_take_non_fungible(AssetId::Abstract(class), instance), - MultiAsset::AllAbstractFungible { id } => Ok(self.take_fungible(&AssetId::Abstract(id))), - MultiAsset::AllConcreteFungible { id } => Ok(self.take_fungible(&AssetId::Concrete(id))), - MultiAsset::AllAbstractNonFungible { class } => Ok(self.take_non_fungible(&AssetId::Abstract(class))), - MultiAsset::AllConcreteNonFungible { class } => Ok(self.take_non_fungible(&AssetId::Concrete(class))), - MultiAsset::AllFungible => { - let mut taken = Assets::new(); - mem::swap(&mut self.fungible, &mut taken.fungible); - Ok(taken) - }, - MultiAsset::AllNonFungible => { - let mut taken = Assets::new(); - mem::swap(&mut self.non_fungible, &mut taken.non_fungible); - Ok(taken) - }, - MultiAsset::All => Ok(self.swapped(Assets::new())), - } - } - - pub fn try_take_fungible(&mut self, id: AssetId, amount: u128) -> Result<Assets, ()> { - self.try_remove_fungible(&id, amount)?; - Ok(id.into_fungible_multiasset(amount).into()) - } - - pub fn try_take_non_fungible(&mut self, id: AssetId, instance: AssetInstance) -> Result<Assets, ()> { - let asset_id_instance = (id, instance); - self.try_remove_non_fungible(&asset_id_instance)?; - let (asset_id, instance) = asset_id_instance; - Ok(asset_id.into_non_fungible_multiasset(instance).into()) - } - - pub fn take_fungible(&mut self, id: &AssetId) -> Assets { - let mut taken = Assets::new(); - if let Some((id, amount)) = self.fungible.remove_entry(&id) { - taken.fungible.insert(id, amount); - } - taken - } - - pub fn take_non_fungible(&mut self, id: &AssetId) -> Assets { - let mut taken = Assets::new(); - let non_fungible = mem::replace(&mut self.non_fungible, Default::default()); - non_fungible.into_iter().for_each(|(c, instance)| { - if &c == id { - taken.non_fungible.insert((c, instance)); - } else { - self.non_fungible.insert((c, instance)); - } - }); - taken - } - - pub fn try_remove_fungible(&mut self, id: &AssetId, amount: u128) -> Result<(), ()> { - let self_amount = self.fungible.get_mut(&id).ok_or(())?; - *self_amount = self_amount.checked_sub(amount).ok_or(())?; - Ok(()) - } - - pub fn try_remove_non_fungible(&mut self, class_instance: &(AssetId, AssetInstance)) -> Result<(), ()> { - match self.non_fungible.remove(class_instance) { - true => Ok(()), - false => Err(()), - } - } - +/* /// Modify `self` to include a new fungible asset by `id` and `amount`, /// saturating if necessary. pub fn saturating_subsume_fungible(&mut self, id: AssetId, amount: u128) { @@ -272,6 +127,12 @@ impl Assets { pub fn saturating_subsume_non_fungible(&mut self, class: AssetId, instance: AssetInstance) { self.non_fungible.insert((class, instance)); } +*/ + /// Swaps two mutable Assets, without deinitializing either one. + pub fn swapped(&mut self, mut with: Assets) -> Self { + mem::swap(&mut *self, &mut with); + with + } /// Alter any concretely identified assets by prepending the given `MultiLocation`. /// @@ -290,6 +151,122 @@ impl Assets { .collect(); } + /// Returns an error unless all `assets` are contained in `self`. In the case of an error, the first asset in + /// `assets` which is not wholly in `self` is returned. + fn ensure_contains(&self, assets: &MultiAssets) -> Result<(), TakeError> { + for asset in assets.inner().iter() { + match asset { + MultiAsset { fun: Fungible(ref amount), ref id } => { + if self.fungible.get(id).map_or(true, |a| a < amount) { + return Err(TakeError((id.clone(), amount).into())) + } + } + MultiAsset { fun: NonFungible(ref instance), ref id } => { + let id_instance = (id.clone(), instance.clone()); + if !self.non_fungible.contains(&id_instance) { + return Err(TakeError(id_instance.into())) + } + } + } + } + return Ok(()) + } + + /// Mutates `self` to its original value less `mask` and returns `true`. + /// + /// If `saturate` is `true`, then `self` is considered to be masked by `mask`, thereby avoiding any attempt at + /// reducing it by assets it does not contain. In this case, the function is infallible. If `saturate` is `false` + /// and `asset` references a definite asset which `self` does not contain then an error is returned. + /// + /// Returns `Ok` with the definite assets token from `self` and mutates `self` to its value minus + /// `asset`. Returns `Err` in the non-saturating case where `self` did not contain (enough of) a definite asset to + /// be removed. + fn general_take(&mut self, mask: MultiAssetFilter, saturate: bool) -> Result<Assets, TakeError> { + match mask { + Wild(All) => Ok(self.swapped(Assets::new())), + Wild(AllOf(WildFungible, id)) => { + let mut taken = Assets::new(); + if let Some((id, amount)) = self.fungible.remove_entry(&id) { + taken.fungible.insert(id, amount); + } + Ok(taken) + } + Wild(AllOf(WildNonFungible, id)) => { + let mut taken = Assets::new(); + let non_fungible = mem::replace(&mut self.non_fungible, Default::default()); + non_fungible.into_iter().for_each(|(c, instance)| { + if &c == id { + taken.non_fungible.insert((c, instance)); + } else { + self.non_fungible.insert((c, instance)); + } + }); + Ok(taken) + } + Assets(assets) => { + if !saturate { + self.ensure_contains(&assets)?; + } + let mut taken = Assets::new(); + for asset in assets.drain().into_iter() { + match asset { + MultiAsset { fun: Fungible(mut amount), id } => { + let (remove, amount) = match self.fungible.get_mut(&id) { + Some(self_amount) => { + let amount = amount.min(*self_amount); + *self_amount -= amount; + (self_amount == 0, amount) + } + None => (false, 0), + }; + if remove { + self.fungible.remove(&id); + } + if amount > 0 { + taken.subsume(MultiAsset::from((id, amount)).into()); + } + } + MultiAsset { fun: NonFungible(instance), id } => { + let id_instance = (id, instance); + if self.non_fungible.remove(&id_instance) { + taken.subsume(id_instance.into()) + } + } + } + } + } + } + } + + /// Mutates `self` to its original value less `asset` and returns `true` iff it contains at least `asset`. + /// + /// `asset` is interpreted as being masked under `self`. + /// + /// Returns `Ok` with the non-wildcard equivalence of `asset` taken and mutates `self` to its value minus + /// `asset` if `self` contains `asset`, and return `Err` otherwise. + pub fn saturating_take(&mut self, asset: MultiAssetFilter) -> Assets { + self.general_take(asset, true).expect("general_take never results in error when saturating") + } + + /// Mutates `self` to its original value less `asset` and returns `true` iff it contains at least `asset`. + /// + /// `asset` is interpreted as being masked under `self`. + /// + /// Returns `Ok` with the non-wildcard equivalence of `asset` taken and mutates `self` to its value minus + /// `asset` if `self` contains `asset`, and return `Err` otherwise. + pub fn try_take(&mut self, asset: MultiAssetFilter) -> Result<Assets, TakeError> { + self.general_take(asset, false) + } + + /// Consumes `self` and returns its original value excluding `asset` iff it contains at least `asset`, as well as + /// the assets excluded. + pub fn less(mut self, asset: WildMultiAsset) -> Result<(Assets, Assets), Self> { + match self.try_take(asset) { + Ok(taken) => Ok((self, taken)), + Err(_) => Err(self), + } + } + /// Return the assets in `self`, but (asset-wise) of no greater value than `assets`. /// /// Result is undefined if `assets` includes elements which match to the same asset more than once. @@ -314,223 +291,41 @@ impl Assets { /// MultiAsset::AbstractFungible { id: vec![0], amount: 50 }, /// ]); /// ``` - pub fn min<'a, M, I>(&self, assets: I) -> Self - where - M: 'a + sp_std::borrow::Borrow<MultiAsset>, - I: IntoIterator<Item = M>, - { - let mut result = Assets::default(); - for asset in assets.into_iter() { - match asset.borrow() { - MultiAsset::None => (), - MultiAsset::All => return self.clone(), - MultiAsset::AllFungible => { - // Replace `result.fungible` with all fungible assets, - // keeping `result.non_fungible` the same. - result = Assets { - fungible: self.fungible.clone(), - non_fungible: result.non_fungible, - } - }, - MultiAsset::AllNonFungible => { - // Replace `result.non_fungible` with all non-fungible assets, - // keeping `result.fungible` the same. - result = Assets { - fungible: result.fungible, - non_fungible: self.non_fungible.clone(), - } - }, - MultiAsset::AllAbstractFungible { id } => { - for asset in self.fungible_assets_iter() { - match &asset { - MultiAsset::AbstractFungible { id: identifier, .. } => { - if id == identifier { result.saturating_subsume(asset) } - }, - _ => (), - } - } - }, - MultiAsset::AllAbstractNonFungible { class } => { - for asset in self.non_fungible_assets_iter() { - match &asset { - MultiAsset::AbstractNonFungible { class: c, .. } => { - if class == c { result.saturating_subsume(asset) } - }, - _ => (), - } - } + pub fn min(&self, mask: MultiAssetFilter) -> Assets { + let mut masked = Assets::new(); + match mask { + Wild(All) => Ok(self.clone()), + Wild(AllOf(WildFungible, id)) => { + if let Some(&(ref id, amount)) = self.fungible.get(&id) { + masked.fungible.insert(id.clone(), amount); } - MultiAsset::AllConcreteFungible { id } => { - for asset in self.fungible_assets_iter() { - match &asset { - MultiAsset::ConcreteFungible { id: identifier, .. } => { - if id == identifier { result.saturating_subsume(asset) } - }, - _ => (), - } - } - }, - MultiAsset::AllConcreteNonFungible { class } => { - for asset in self.non_fungible_assets_iter() { - match &asset { - MultiAsset::ConcreteNonFungible { class: c, .. } => { - if class == c { result.saturating_subsume(asset) } - }, - _ => (), - } - } - } - x @ MultiAsset::ConcreteFungible { .. } | x @ MultiAsset::AbstractFungible { .. } => { - let (id, amount) = match x { - MultiAsset::ConcreteFungible { id, amount } => (AssetId::Concrete(id.clone()), *amount), - MultiAsset::AbstractFungible { id, amount } => (AssetId::Abstract(id.clone()), *amount), - _ => unreachable!(), - }; - if let Some(v) = self.fungible.get(&id) { - result.saturating_subsume_fungible(id, amount.min(*v)); - } - }, - x @ MultiAsset::ConcreteNonFungible { .. } | x @ MultiAsset::AbstractNonFungible { .. } => { - let (class, instance) = match x { - MultiAsset::ConcreteNonFungible { class, instance } => (AssetId::Concrete(class.clone()), instance.clone()), - MultiAsset::AbstractNonFungible { class, instance } => (AssetId::Abstract(class.clone()), instance.clone()), - _ => unreachable!(), - }; - let item = (class, instance); - if self.non_fungible.contains(&item) { - result.non_fungible.insert(item); + } + Wild(AllOf(WildNonFungible, id)) => { + self.non_fungible.iter().for_each(|(ref c, ref instance)| { + if c == id { + masked.non_fungible.insert((c.clone(), instance.clone())); } - } + }); } - } - result - } - - /// Take all possible assets up to `assets` from `self`, mutating `self` and returning the - /// assets taken. - /// - /// Wildcards work. - /// - /// Example: - /// - /// ``` - /// use xcm_executor::Assets; - /// use xcm::v0::{MultiAsset, MultiLocation}; - /// let mut assets_i_have: Assets = vec![ - /// MultiAsset::ConcreteFungible { id: MultiLocation::Null, amount: 100 }, - /// MultiAsset::AbstractFungible { id: vec![0], amount: 100 }, - /// ].into(); - /// let assets_they_want = vec![ - /// MultiAsset::AllAbstractFungible { id: vec![0] }, - /// ]; - /// - /// let assets_they_took: Assets = assets_i_have.saturating_take(assets_they_want); - /// assert_eq!(assets_they_took.into_assets_iter().collect::<Vec<_>>(), vec![ - /// MultiAsset::AbstractFungible { id: vec![0], amount: 100 }, - /// ]); - /// assert_eq!(assets_i_have.into_assets_iter().collect::<Vec<_>>(), vec![ - /// MultiAsset::ConcreteFungible { id: MultiLocation::Null, amount: 100 }, - /// ]); - /// ``` - pub fn saturating_take<I>(&mut self, assets: I) -> Assets - where - I: IntoIterator<Item = MultiAsset>, - { - let mut result = Assets::default(); - for asset in assets.into_iter() { - match asset { - MultiAsset::None => (), - MultiAsset::All => return self.swapped(Assets::default()), - MultiAsset::AllFungible => { - // Remove all fungible assets, and copy them into `result`. - let fungible = mem::replace(&mut self.fungible, Default::default()); - fungible.into_iter().for_each(|(id, amount)| { - result.saturating_subsume_fungible(id, amount); - }) - }, - MultiAsset::AllNonFungible => { - // Remove all non-fungible assets, and copy them into `result`. - let non_fungible = mem::replace(&mut self.non_fungible, Default::default()); - non_fungible.into_iter().for_each(|(class, instance)| { - result.saturating_subsume_non_fungible(class, instance); - }); - }, - x @ MultiAsset::AllAbstractFungible { .. } | x @ MultiAsset::AllConcreteFungible { .. } => { - let id = match x { - MultiAsset::AllConcreteFungible { id } => AssetId::Concrete(id), - MultiAsset::AllAbstractFungible { id } => AssetId::Abstract(id), - _ => unreachable!(), - }; - // At the end of this block, we will be left with only the non-matching fungibles. - let mut non_matching_fungibles = BTreeMap::<AssetId, u128>::new(); - let fungible = mem::replace(&mut self.fungible, Default::default()); - fungible.into_iter().for_each(|(iden, amount)| { - if iden == id { - result.saturating_subsume_fungible(iden, amount); - } else { - non_matching_fungibles.insert(iden, amount); + Assets(assets) => { + for asset in assets.inner().iter() { + match asset { + MultiAsset { fun: Fungible(ref amount), ref id } => { + if let Some(m) = self.fungible.get(id) { + masked.subsume((id.clone(), Fungible(*amount.min(m))).into()); } - }); - self.fungible = non_matching_fungibles; - }, - x @ MultiAsset::AllAbstractNonFungible { .. } | x @ MultiAsset::AllConcreteNonFungible { .. } => { - let class = match x { - MultiAsset::AllConcreteNonFungible { class } => AssetId::Concrete(class), - MultiAsset::AllAbstractNonFungible { class } => AssetId::Abstract(class), - _ => unreachable!(), - }; - // At the end of this block, we will be left with only the non-matching non-fungibles. - let mut non_matching_non_fungibles = BTreeSet::<(AssetId, AssetInstance)>::new(); - let non_fungible = mem::replace(&mut self.non_fungible, Default::default()); - non_fungible.into_iter().for_each(|(c, instance)| { - if class == c { - result.saturating_subsume_non_fungible(c, instance); - } else { - non_matching_non_fungibles.insert((c, instance)); + } + MultiAsset { fun: NonFungible(ref instance), ref id } => { + let id_instance = (id.clone(), instance.clone()); + if self.non_fungible.contains(&id_instance) { + masked.subsume(id_instance.into()); } - }); - self.non_fungible = non_matching_non_fungibles; - }, - x @ MultiAsset::ConcreteFungible {..} | x @ MultiAsset::AbstractFungible {..} => { - let (id, amount) = match x { - MultiAsset::ConcreteFungible { id, amount } => (AssetId::Concrete(id), amount), - MultiAsset::AbstractFungible { id, amount } => (AssetId::Abstract(id), amount), - _ => unreachable!(), - }; - // remove the maxmimum possible up to id/amount from self, add the removed onto - // result - let maybe_value = self.fungible.get(&id); - if let Some(&e) = maybe_value { - if e > amount { - self.fungible.insert(id.clone(), e - amount); - result.saturating_subsume_fungible(id, amount); - } else { - self.fungible.remove(&id); - result.saturating_subsume_fungible(id, e.clone()); } } } - x @ MultiAsset::ConcreteNonFungible {..} | x @ MultiAsset::AbstractNonFungible {..} => { - let (class, instance) = match x { - MultiAsset::ConcreteNonFungible { class, instance } => (AssetId::Concrete(class), instance), - MultiAsset::AbstractNonFungible { class, instance } => (AssetId::Abstract(class), instance), - _ => unreachable!(), - }; - // remove the maxmimum possible up to id/amount from self, add the removed onto - // result - if let Some(entry) = self.non_fungible.take(&(class, instance)) { - result.non_fungible.insert(entry); - } - } } } - result - } - - /// Swaps two mutable Assets, without deinitializing either one. - pub fn swapped(&mut self, mut with: Assets) -> Self { - mem::swap(&mut *self, &mut with); - with + masked } } diff --git a/xcm/xcm-executor/src/lib.rs b/xcm/xcm-executor/src/lib.rs index 8f8a5c9ee617..87b770533db2 100644 --- a/xcm/xcm-executor/src/lib.rs +++ b/xcm/xcm-executor/src/lib.rs @@ -106,10 +106,10 @@ impl<Config: config::Config> XcmExecutor<Config> { log::trace!( target: "xcm::do_execute_xcm", "origin: {:?}, top_level: {:?}, message: {:?}, weight_credit: {:?}, maybe_shallow_weight: {:?}", - origin, - top_level, - message, - weight_credit, + origin, + top_level, + message, + weight_credit, maybe_shallow_weight, ); // This is the weight of everything that cannot be paid for. This basically means all computation @@ -133,7 +133,7 @@ impl<Config: config::Config> XcmExecutor<Config> { for asset in assets { ensure!(!asset.is_wildcard(), XcmError::Wildcard); let withdrawn = Config::AssetTransactor::withdraw_asset(&asset, &origin)?; - holding.saturating_subsume_all(withdrawn); + holding.subsume_assets(withdrawn); } Some((holding, effects)) } @@ -288,7 +288,7 @@ impl<Config: config::Config> XcmExecutor<Config> { let purchasing_weight = Weight::from(weight.checked_add(debt).ok_or(XcmError::Overflow)?); let max_fee = holding.try_take(fees).map_err(|()| XcmError::NotHoldingFees)?; let unspent = trader.buy_weight(purchasing_weight, max_fee)?; - holding.saturating_subsume_all(unspent); + holding.subsume_assets(unspent); let mut remaining_weight = weight; for message in xcm.into_iter() { @@ -298,7 +298,7 @@ impl<Config: config::Config> XcmExecutor<Config> { Ok(surplus) => { total_surplus += surplus } } } - holding.saturating_subsume(trader.refund_weight(remaining_weight)); + holding.subsume(trader.refund_weight(remaining_weight)); } _ => return Err(XcmError::UnhandledEffect)?, } From 65b6fd4d6e12c58c8272a3a3328efc7e52903816 Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Fri, 30 Jul 2021 10:18:36 -0700 Subject: [PATCH 005/166] Implement custom encoding/decoding scheme for MultiLocation --- xcm/src/v0/junction.rs | 6 ++ xcm/src/v0/multi_location.rs | 168 ++++++++++++++++++++++------------- 2 files changed, 110 insertions(+), 64 deletions(-) diff --git a/xcm/src/v0/junction.rs b/xcm/src/v0/junction.rs index 3785e11b672c..d26cecf08b21 100644 --- a/xcm/src/v0/junction.rs +++ b/xcm/src/v0/junction.rs @@ -84,11 +84,17 @@ impl BodyPart { /// 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. +/// +/// NOTE: The codec index starts at 1, because a previous iteration of `Junction` has a `Parent` +/// variant occupying index 0. We deprecate `Junction::Parent` now by having a custom +/// Encode/Decode implementation for `MultiLocation`. Refer to [`MultiLocation`] for more +/// details. #[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. + #[codec(index = 1)] 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. diff --git a/xcm/src/v0/multi_location.rs b/xcm/src/v0/multi_location.rs index c92efd903a21..1ad12cc23759 100644 --- a/xcm/src/v0/multi_location.rs +++ b/xcm/src/v0/multi_location.rs @@ -18,7 +18,7 @@ use core::{convert::TryFrom, mem, result}; -use parity_scale_codec::{self, Encode, Decode}; +use parity_scale_codec::{self, Decode, Encode, Input, Output}; use super::Junction; use crate::VersionedMultiLocation; @@ -44,10 +44,50 @@ use crate::VersionedMultiLocation; /// This specific `MultiLocation` implementation uses a Rust `enum` in order to make pattern matching easier. /// /// The `MultiLocation` value of `Null` simply refers to the interpreting consensus system. -#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug)] +#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)] pub struct MultiLocation { parents: u8, - junctions: Junctions, + interior: Junctions, +} + +impl Encode for MultiLocation { + fn encode_to<T: Output + ?Sized>(&self, dest: &mut T) { + // 8 items max, but we cannot return an error, so we ap silently. + let parents = self.parents.min( + MAX_MULTILOCATION_LENGTH.saturating_sub(self.interior.len()) as u8, + ); + let count = parents.saturating_add(self.interior.len() as u8); + dest.push_byte(count); + for _ in 0..parents { + dest.push_byte(0); + } + for j in self.interior.iter() { + j.encode_to(dest) + } + } +} + +impl Decode for MultiLocation { + fn decode<I: Input>(input: &mut I) -> Result<Self, parity_scale_codec::Error> { + let count = input.read_byte()?; + let mut parents = 0u8; + let mut interior = Junctions::Null; + for i in 0..count { + let b = input.read_byte()?; + if b == 0 { + if i > parents { + // this would imply that there has been at least one non-parent junction, which + // further implies that this is non-canonical. we bail. + return Err(parity_scale_codec::Error::from("Parent after non-Parent forbidden")) + } + parents = parents.saturating_add(1); + } else { + interior = interior.pushed_with(Junction::decode(&mut &[b][..])?) + .map_err(|_| parity_scale_codec::Error::from("Interior too long"))?; + } + } + Ok(MultiLocation { parents, interior }) + } } /// Maximum number of junctions a `MultiLocation` can contain. @@ -62,18 +102,18 @@ impl MultiLocation { } Ok(MultiLocation { parents, - junctions, + interior: junctions, }) } - /// Return a reference to the junctions field. + /// Return a reference to the interior field. pub fn junctions(&self) -> &Junctions { - &self.junctions + &self.interior } - /// Return a mutable reference to the junctions field. + /// Return a mutable reference to the interior field. pub fn junctions_mut(&mut self) -> &mut Junctions { - &mut self.junctions + &mut self.interior } /// Returns the number of `Parent` junctions at the beginning of `self`. @@ -83,28 +123,28 @@ impl MultiLocation { /// Returns the number of parents and junctions in `self`. pub fn len(&self) -> usize { - self.parent_count() + self.junctions.len() + self.parent_count() + self.interior.len() } /// Returns first junction that is not a parent, or `None` if the location is empty or /// contains only parents. pub fn first_non_parent(&self) -> Option<&Junction> { - self.junctions.first() + self.interior.first() } /// Returns last junction, or `None` if the location is empty or contains only parents. pub fn last(&self) -> Option<&Junction> { - self.junctions.last() + self.interior.last() } /// Splits off the first non-parent 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_non_parent(self) -> (MultiLocation, Option<Junction>) { - let MultiLocation { parents, junctions } = self; + let MultiLocation { parents, interior: junctions } = self; let (prefix, suffix) = junctions.split_first(); let multilocation = MultiLocation { parents, - junctions: prefix, + interior: prefix, }; (multilocation, suffix) } @@ -112,11 +152,11 @@ impl MultiLocation { /// 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 or that `self` only contains parents. pub fn split_last(self) -> (MultiLocation, Option<Junction>) { - let MultiLocation { parents, junctions } = self; + let MultiLocation { parents, interior: junctions } = self; let (prefix, suffix) = junctions.split_last(); let multilocation = MultiLocation { parents, - junctions: prefix, + interior: prefix, }; (multilocation, suffix) } @@ -133,20 +173,20 @@ impl MultiLocation { /// Mutates `self`, suffixing its non-parent junctions with `new`. Returns `Err` in case of overflow. pub fn push_non_parent(&mut self, new: Junction) -> result::Result<(), ()> { let mut n = Junctions::Null; - mem::swap(&mut self.junctions, &mut n); + mem::swap(&mut self.interior, &mut n); match n.pushed_with(new) { - Ok(result) => { self.junctions = result; Ok(()) } - Err(old) => { self.junctions = old; Err(()) } + Ok(result) => { self.interior = result; Ok(()) } + Err(old) => { self.interior = old; Err(()) } } } /// Mutates `self`, prefixing its non-parent junctions with `new`. Returns `Err` in case of overflow. pub fn push_front_non_parent(&mut self, new: Junction) -> result::Result<(), ()> { let mut n = Junctions::Null; - mem::swap(&mut self.junctions, &mut n); + mem::swap(&mut self.interior, &mut n); match n.pushed_front_with(new) { - Ok(result) => { self.junctions = result; Ok(()) } - Err(old) => { self.junctions = old; Err(()) } + Ok(result) => { self.interior = result; Ok(()) } + Err(old) => { self.interior = old; Err(()) } } } @@ -170,7 +210,7 @@ impl MultiLocation { } Ok(MultiLocation { parents: self.parents, - junctions: self.junctions.pushed_with(new).expect("length is less than max length; qed"), + interior: self.interior.pushed_with(new).expect("length is less than max length; qed"), }) } @@ -182,7 +222,7 @@ impl MultiLocation { } Ok(MultiLocation { parents: self.parents, - junctions: self.junctions.pushed_front_with(new).expect("length is less than max length; qed"), + interior: self.interior.pushed_front_with(new).expect("length is less than max length; qed"), }) } @@ -193,7 +233,7 @@ impl MultiLocation { if i < num_parents { return None } - self.junctions.at(i - num_parents) + self.interior.at(i - num_parents) } /// Returns a mutable reference to the junction at index `i`, or `None` if the location is a @@ -203,7 +243,7 @@ impl MultiLocation { if i < num_parents { return None } - self.junctions.at_mut(i - num_parents) + self.interior.at_mut(i - num_parents) } /// Decrement the parent count by 1. @@ -214,13 +254,13 @@ impl MultiLocation { /// Removes the first non-parent element from `self`, returning it /// (or `None` if it was empty or if `self` contains only parents). pub fn take_first_non_parent(&mut self) -> Option<Junction> { - self.junctions.take_first() + self.interior.take_first() } /// Removes the last element from `junctions`, returning it (or `None` if it was empty or if /// `self` only contains parents). pub fn take_last(&mut self) -> Option<Junction> { - self.junctions.take_last() + self.interior.take_last() } /// Ensures that `self` has the same number of parents as `prefix`, its junctions begins with @@ -243,7 +283,7 @@ impl MultiLocation { if self.parents != prefix.parents { return None } - self.junctions.match_and_split(&prefix.junctions) + self.interior.match_and_split(&prefix.interior) } /// Mutate `self` so that it is suffixed with `suffix`. The correct normalized form is returned, @@ -288,8 +328,8 @@ impl MultiLocation { /// ``` pub fn prepend_with(&mut self, mut prefix: MultiLocation) -> Result<(), MultiLocation> { let self_parents = self.parent_count(); - let prepend_len = (self_parents as isize - prefix.junctions.len() as isize).abs() as usize; - if self.junctions.len() + prefix.parent_count() + prepend_len > MAX_MULTILOCATION_LENGTH { + let prepend_len = (self_parents as isize - prefix.interior.len() as isize).abs() as usize; + if self.interior.len() + prefix.parent_count() + prepend_len > MAX_MULTILOCATION_LENGTH { return Err(prefix) } @@ -305,7 +345,7 @@ impl MultiLocation { } self.parents = final_parent_count; - for j in prefix.junctions.into_iter_rev() { + for j in prefix.interior.into_iter_rev() { self.push_front_non_parent(j).expect( "self junctions len + prefix parent count + prepend len is less than max length; qed" ); @@ -318,7 +358,7 @@ impl From<Junctions> for MultiLocation { fn from(junctions: Junctions) -> Self { MultiLocation { parents: 0, - junctions, + interior: junctions, } } } @@ -327,7 +367,7 @@ impl From<Junction> for MultiLocation { fn from(x: Junction) -> Self { MultiLocation { parents: 0, - junctions: Junctions::X1(x), + interior: Junctions::X1(x), } } } @@ -336,7 +376,7 @@ impl From<()> for MultiLocation { fn from(_: ()) -> Self { MultiLocation { parents: 0, - junctions: Junctions::Null, + interior: Junctions::Null, } } } @@ -344,7 +384,7 @@ impl From<(Junction,)> for MultiLocation { fn from(x: (Junction,)) -> Self { MultiLocation { parents: 0, - junctions: Junctions::X1(x.0), + interior: Junctions::X1(x.0), } } } @@ -352,7 +392,7 @@ impl From<(Junction, Junction)> for MultiLocation { fn from(x: (Junction, Junction)) -> Self { MultiLocation { parents: 0, - junctions: Junctions::X2(x.0, x.1), + interior: Junctions::X2(x.0, x.1), } } } @@ -360,7 +400,7 @@ impl From<(Junction, Junction, Junction)> for MultiLocation { fn from(x: (Junction, Junction, Junction)) -> Self { MultiLocation { parents: 0, - junctions: Junctions::X3(x.0, x.1, x.2), + interior: Junctions::X3(x.0, x.1, x.2), } } } @@ -368,7 +408,7 @@ impl From<(Junction, Junction, Junction, Junction)> for MultiLocation { fn from(x: (Junction, Junction, Junction, Junction)) -> Self { MultiLocation { parents: 0, - junctions: Junctions::X4(x.0, x.1, x.2, x.3), + interior: Junctions::X4(x.0, x.1, x.2, x.3), } } } @@ -376,7 +416,7 @@ impl From<(Junction, Junction, Junction, Junction, Junction)> for MultiLocation fn from(x: (Junction, Junction, Junction, Junction, Junction)) -> Self { MultiLocation { parents: 0, - junctions: Junctions::X5(x.0, x.1, x.2, x.3, x.4), + interior: Junctions::X5(x.0, x.1, x.2, x.3, x.4), } } } @@ -384,7 +424,7 @@ impl From<(Junction, Junction, Junction, Junction, Junction, Junction)> for Mult fn from(x: (Junction, Junction, Junction, Junction, Junction, Junction)) -> Self { MultiLocation { parents: 0, - junctions: Junctions::X6(x.0, x.1, x.2, x.3, x.4, x.5), + interior: Junctions::X6(x.0, x.1, x.2, x.3, x.4, x.5), } } } @@ -392,7 +432,7 @@ impl From<(Junction, Junction, Junction, Junction, Junction, Junction, Junction) fn from(x: (Junction, Junction, Junction, Junction, Junction, Junction, Junction)) -> Self { MultiLocation { parents: 0, - junctions: Junctions::X7(x.0, x.1, x.2, x.3, x.4, x.5, x.6), + interior: Junctions::X7(x.0, x.1, x.2, x.3, x.4, x.5, x.6), } } } @@ -400,7 +440,7 @@ impl From<(Junction, Junction, Junction, Junction, Junction, Junction, Junction, fn from(x: (Junction, Junction, Junction, Junction, Junction, Junction, Junction, Junction)) -> Self { MultiLocation { parents: 0, - junctions: Junctions::X8(x.0, x.1, x.2, x.3, x.4, x.5, x.6, x.7), + interior: Junctions::X8(x.0, x.1, x.2, x.3, x.4, x.5, x.6, x.7), } } } @@ -409,7 +449,7 @@ impl From<[Junction; 0]> for MultiLocation { fn from(_: [Junction; 0]) -> Self { MultiLocation { parents: 0, - junctions: Junctions::Null, + interior: Junctions::Null, } } } @@ -418,7 +458,7 @@ impl From<[Junction; 1]> for MultiLocation { let [x0] = x; MultiLocation { parents: 0, - junctions: Junctions::X1(x0), + interior: Junctions::X1(x0), } } } @@ -427,7 +467,7 @@ impl From<[Junction; 2]> for MultiLocation { let [x0, x1] = x; MultiLocation { parents: 0, - junctions: Junctions::X2(x0, x1), + interior: Junctions::X2(x0, x1), } } } @@ -436,7 +476,7 @@ impl From<[Junction; 3]> for MultiLocation { let [x0, x1, x2] = x; MultiLocation { parents: 0, - junctions: Junctions::X3(x0, x1, x2), + interior: Junctions::X3(x0, x1, x2), } } } @@ -445,7 +485,7 @@ impl From<[Junction; 4]> for MultiLocation { let [x0, x1, x2, x3] = x; MultiLocation { parents: 0, - junctions: Junctions::X4(x0, x1, x2, x3), + interior: Junctions::X4(x0, x1, x2, x3), } } } @@ -454,7 +494,7 @@ impl From<[Junction; 5]> for MultiLocation { let [x0, x1, x2, x3, x4] = x; MultiLocation { parents: 0, - junctions: Junctions::X5(x0, x1, x2, x3, x4), + interior: Junctions::X5(x0, x1, x2, x3, x4), } } } @@ -463,7 +503,7 @@ impl From<[Junction; 6]> for MultiLocation { let [x0, x1, x2, x3, x4, x5] = x; MultiLocation { parents: 0, - junctions: Junctions::X6(x0, x1, x2, x3, x4, x5), + interior: Junctions::X6(x0, x1, x2, x3, x4, x5), } } } @@ -472,7 +512,7 @@ impl From<[Junction; 7]> for MultiLocation { let [x0, x1, x2, x3, x4, x5, x6] = x; MultiLocation { parents: 0, - junctions: Junctions::X7(x0, x1, x2, x3, x4, x5, x6), + interior: Junctions::X7(x0, x1, x2, x3, x4, x5, x6), } } } @@ -481,7 +521,7 @@ impl From<[Junction; 8]> for MultiLocation { let [x0, x1, x2, x3, x4, x5, x6, x7] = x; MultiLocation { parents: 0, - junctions: Junctions::X8(x0, x1, x2, x3, x4, x5, x6, x7), + interior: Junctions::X8(x0, x1, x2, x3, x4, x5, x6, x7), } } } @@ -825,10 +865,10 @@ mod tests { #[test] fn match_and_split_works() { - let m = MultiLocation { parents: 1, junctions: X2(Parachain(42), AccountIndex64 { network: Any, index: 23 }) }; - assert_eq!(m.match_and_split(&MultiLocation { parents: 1, junctions: Null }), 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: Null }), None); assert_eq!( - m.match_and_split(&MultiLocation { parents: 1, junctions: X1(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); @@ -837,30 +877,30 @@ mod tests { #[test] fn append_with_works() { let acc = AccountIndex64 { network: Any, index: 23 }; - let mut m = MultiLocation { parents: 1, junctions: X1(Parachain(42)) }; + 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, junctions: X3(Parachain(42), PalletInstance(3), acc.clone()) }); + 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 = MultiLocation { parents: 6, junctions: X1(Parachain(42)) }; + let mut m = MultiLocation { parents: 6, interior: X1(Parachain(42)) }; let suffix = MultiLocation::from(X2(PalletInstance(3), acc.clone())); assert_eq!(m.append_with(suffix.clone()), Err(suffix)); } #[test] fn prepend_with_works() { - let mut m = MultiLocation { parents: 1, junctions: X2(Parachain(42), AccountIndex64 { network: Any, index: 23 }) }; - assert_eq!(m.prepend_with(MultiLocation { parents: 1, junctions: X1(OnlyChild) }), Ok(())); - assert_eq!(m, MultiLocation { parents: 1, junctions: X2(Parachain(42), AccountIndex64 { network: Any, index: 23 }) }); + 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 }) }); // cannot prepend to create overly long multilocation - let mut m = MultiLocation { parents: 6, junctions: X1(Parachain(42)) }; - let prefix = MultiLocation { parents: 2, junctions: Null }; + let mut m = MultiLocation { parents: 6, interior: X1(Parachain(42)) }; + let prefix = MultiLocation { parents: 2, interior: Null }; assert_eq!(m.prepend_with(prefix.clone()), Err(prefix)); - let prefix = MultiLocation { parents: 1, junctions: Null }; + let prefix = MultiLocation { parents: 1, interior: Null }; assert_eq!(m.prepend_with(prefix), Ok(())); - assert_eq!(m, MultiLocation { parents: 7, junctions: X1(Parachain(42)) }); + assert_eq!(m, MultiLocation { parents: 7, interior: X1(Parachain(42)) }); } } From 16927cd11a5a6c14895efd2fade4d560bca63289 Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Fri, 30 Jul 2021 10:24:21 -0700 Subject: [PATCH 006/166] Properly implement IntoIterator for Junctions --- xcm/src/v0/multi_location.rs | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/xcm/src/v0/multi_location.rs b/xcm/src/v0/multi_location.rs index 1ad12cc23759..3ea46cfd530a 100644 --- a/xcm/src/v0/multi_location.rs +++ b/xcm/src/v0/multi_location.rs @@ -61,7 +61,7 @@ impl Encode for MultiLocation { for _ in 0..parents { dest.push_byte(0); } - for j in self.interior.iter() { + for j in &self.interior { j.encode_to(dest) } } @@ -583,6 +583,22 @@ impl<'a> Iterator for JunctionsReverseRefIterator<'a> { } } +impl<'a> IntoIterator for &'a Junctions { + type Item = &'a Junction; + type IntoIter = JunctionsRefIterator<'a>; + fn into_iter(self) -> Self::IntoIter { + JunctionsRefIterator(self, 0) + } +} + +impl IntoIterator for Junctions { + type Item = Junction; + type IntoIter = JunctionsIterator; + fn into_iter(self) -> Self::IntoIter { + JunctionsIterator(self) + } +} + impl Junctions { /// Returns first junction, or `None` if the location is empty. pub fn first(&self) -> Option<&Junction> { @@ -808,11 +824,6 @@ impl Junctions { JunctionsReverseRefIterator(&self, 0) } - /// Consumes `self` and returns an iterator over the junctions. - pub fn into_iter(self) -> JunctionsIterator { - JunctionsIterator(self) - } - /// Consumes `self` and returns an iterator over the junctions in reverse. pub fn into_iter_rev(self) -> JunctionsReverseIterator { JunctionsReverseIterator(self) From 786fb460f318bb3547ae228eb9db071a2c1d30b5 Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Fri, 30 Jul 2021 10:28:56 -0700 Subject: [PATCH 007/166] Implement TryFrom<MultiLocation> for Junctions --- xcm/src/v0/multi_location.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/xcm/src/v0/multi_location.rs b/xcm/src/v0/multi_location.rs index 3ea46cfd530a..c683072264c8 100644 --- a/xcm/src/v0/multi_location.rs +++ b/xcm/src/v0/multi_location.rs @@ -854,6 +854,17 @@ impl Junctions { } } +impl TryFrom<MultiLocation> for Junctions { + type Error = (); + fn try_from(x: MultiLocation) -> result::Result<Self, ()> { + if x.parents > 0 { + Err(()) + } else { + Ok(x.interior) + } + } +} + impl From<MultiLocation> for VersionedMultiLocation { fn from(x: MultiLocation) -> Self { VersionedMultiLocation::V0(x) From 5b487a6721382072d6a2088774279b04715ce2e9 Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Fri, 30 Jul 2021 10:30:44 -0700 Subject: [PATCH 008/166] Fix spelling mistakes --- xcm/src/v0/multi_location.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xcm/src/v0/multi_location.rs b/xcm/src/v0/multi_location.rs index c683072264c8..905d267bdf3b 100644 --- a/xcm/src/v0/multi_location.rs +++ b/xcm/src/v0/multi_location.rs @@ -94,7 +94,7 @@ impl Decode for MultiLocation { pub const MAX_MULTILOCATION_LENGTH: usize = 8; impl MultiLocation { - /// Creates a new MultiLocation, ensuring that the length of it does not exceed the maximum, + /// Creates a new `MultiLocation`, ensuring that the length of it does not exceed the maximum, /// otherwise returns `Err`. pub fn new(parents: u8, junctions: Junctions) -> result::Result<MultiLocation, ()> { if parents as usize + junctions.len() > MAX_MULTILOCATION_LENGTH { @@ -246,7 +246,7 @@ impl MultiLocation { self.interior.at_mut(i - num_parents) } - /// Decrement the parent count by 1. + /// Decrements the parent count by 1. pub fn pop_parent(&mut self) { self.parents = self.parents.saturating_sub(1); } From 5c23328a4558c352f70b14ad89e4b606642c457f Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Fri, 30 Jul 2021 10:51:31 -0700 Subject: [PATCH 009/166] Fix tests in xcm-executor --- xcm/src/v0/multi_location.rs | 9 ++++++++ xcm/xcm-executor/src/assets.rs | 22 +++++++++---------- xcm/xcm-executor/src/lib.rs | 1 - xcm/xcm-executor/src/traits/conversion.rs | 14 ++++++------ xcm/xcm-executor/src/traits/transact_asset.rs | 8 +++---- 5 files changed, 31 insertions(+), 23 deletions(-) diff --git a/xcm/src/v0/multi_location.rs b/xcm/src/v0/multi_location.rs index 905d267bdf3b..ff2cb40c5a45 100644 --- a/xcm/src/v0/multi_location.rs +++ b/xcm/src/v0/multi_location.rs @@ -50,6 +50,15 @@ pub struct MultiLocation { interior: Junctions, } +impl Default for MultiLocation { + fn default() -> Self { + MultiLocation { + parents: 0, + interior: Junctions::Null, + } + } +} + impl Encode for MultiLocation { fn encode_to<T: Output + ?Sized>(&self, dest: &mut T) { // 8 items max, but we cannot return an error, so we ap silently. diff --git a/xcm/xcm-executor/src/assets.rs b/xcm/xcm-executor/src/assets.rs index c0d35052482b..343ac28586eb 100644 --- a/xcm/xcm-executor/src/assets.rs +++ b/xcm/xcm-executor/src/assets.rs @@ -300,17 +300,17 @@ impl Assets { /// use xcm_executor::Assets; /// use xcm::v0::{MultiAsset, MultiLocation}; /// let assets_i_have: Assets = vec![ - /// MultiAsset::ConcreteFungible { id: MultiLocation::Null, amount: 100 }, + /// MultiAsset::ConcreteFungible { id: MultiLocation::default(), amount: 100 }, /// MultiAsset::AbstractFungible { id: vec![0], amount: 100 }, /// ].into(); /// let assets_they_want: Assets = vec![ - /// MultiAsset::ConcreteFungible { id: MultiLocation::Null, amount: 200 }, + /// MultiAsset::ConcreteFungible { id: MultiLocation::default(), amount: 200 }, /// MultiAsset::AbstractFungible { id: vec![0], amount: 50 }, /// ].into(); /// /// let assets_we_can_trade: Assets = assets_i_have.min(assets_they_want.assets_iter()); /// assert_eq!(assets_we_can_trade.into_assets_iter().collect::<Vec<_>>(), vec![ - /// MultiAsset::ConcreteFungible { id: MultiLocation::Null, amount: 100 }, + /// MultiAsset::ConcreteFungible { id: MultiLocation::default(), amount: 100 }, /// MultiAsset::AbstractFungible { id: vec![0], amount: 50 }, /// ]); /// ``` @@ -417,7 +417,7 @@ impl Assets { /// use xcm_executor::Assets; /// use xcm::v0::{MultiAsset, MultiLocation}; /// let mut assets_i_have: Assets = vec![ - /// MultiAsset::ConcreteFungible { id: MultiLocation::Null, amount: 100 }, + /// MultiAsset::ConcreteFungible { id: MultiLocation::default(), amount: 100 }, /// MultiAsset::AbstractFungible { id: vec![0], amount: 100 }, /// ].into(); /// let assets_they_want = vec![ @@ -429,7 +429,7 @@ impl Assets { /// MultiAsset::AbstractFungible { id: vec![0], amount: 100 }, /// ]); /// assert_eq!(assets_i_have.into_assets_iter().collect::<Vec<_>>(), vec![ - /// MultiAsset::ConcreteFungible { id: MultiLocation::Null, amount: 100 }, + /// MultiAsset::ConcreteFungible { id: MultiLocation::default(), amount: 100 }, /// ]); /// ``` pub fn saturating_take<I>(&mut self, assets: I) -> Assets @@ -547,11 +547,11 @@ mod tests { } #[allow(non_snake_case)] fn CF(amount: u128) -> MultiAsset { - MultiAsset::ConcreteFungible { id: MultiLocation::Null, amount } + MultiAsset::ConcreteFungible { id: MultiLocation::default(), amount } } #[allow(non_snake_case)] fn CNF(instance_id: u128) -> MultiAsset { - MultiAsset::ConcreteNonFungible { class: MultiLocation::Null, instance: AssetInstance::Index { id: instance_id } } + MultiAsset::ConcreteNonFungible { class: MultiLocation::default(), instance: AssetInstance::Index { id: instance_id } } } fn test_assets() -> Assets { @@ -642,8 +642,8 @@ mod tests { #[test] fn min_all_concrete_works() { let assets = test_assets(); - let fungible = vec![MultiAsset::AllConcreteFungible { id: MultiLocation::Null }]; - let non_fungible = vec![MultiAsset::AllConcreteNonFungible { class: MultiLocation::Null }]; + let fungible = vec![MultiAsset::AllConcreteFungible { id: MultiLocation::default() }]; + let non_fungible = vec![MultiAsset::AllConcreteNonFungible { class: MultiLocation::default() }]; let fungible = assets.min(fungible.iter()); let fungible = fungible.assets_iter().collect::<Vec<_>>(); @@ -724,8 +724,8 @@ mod tests { #[test] fn saturating_take_all_concrete_works() { let mut assets = test_assets(); - let fungible = vec![MultiAsset::AllConcreteFungible { id: MultiLocation::Null }]; - let non_fungible = vec![MultiAsset::AllConcreteNonFungible { class: MultiLocation::Null }]; + let fungible = vec![MultiAsset::AllConcreteFungible { id: MultiLocation::default() }]; + let non_fungible = vec![MultiAsset::AllConcreteNonFungible { class: MultiLocation::default() }]; let fungible = assets.saturating_take(fungible); let fungible = fungible.assets_iter().collect::<Vec<_>>(); diff --git a/xcm/xcm-executor/src/lib.rs b/xcm/xcm-executor/src/lib.rs index 8f8a5c9ee617..b8a7eda909fa 100644 --- a/xcm/xcm-executor/src/lib.rs +++ b/xcm/xcm-executor/src/lib.rs @@ -218,7 +218,6 @@ impl<Config: config::Config> XcmExecutor<Config> { None } (origin, Xcm::RelayedFrom { who, message }) => { - ensure!(who.is_interior(), XcmError::EscalationOfPrivilege); let mut origin = origin; origin.append_with(who).map_err(|_| XcmError::MultiLocationFull)?; let surplus = Self::do_execute_xcm(origin, top_level, *message, weight_credit, None, trader)?; diff --git a/xcm/xcm-executor/src/traits/conversion.rs b/xcm/xcm-executor/src/traits/conversion.rs index 19b2de1a0076..72d9fd979672 100644 --- a/xcm/xcm-executor/src/traits/conversion.rs +++ b/xcm/xcm-executor/src/traits/conversion.rs @@ -125,15 +125,15 @@ impl<T: Clone + Encode + Decode> Convert<Vec<u8>, T> for Decoded { /// which is passed to the next convert item. /// /// ```rust -/// # use xcm::v0::{MultiLocation, Junction, OriginKind}; +/// # use xcm::v0::{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<u32> for BumpParaId { /// fn convert_origin(origin: MultiLocation, _: OriginKind) -> Result<u32, MultiLocation> { -/// match origin { -/// MultiLocation::X1(Junction::Parachain(id)) => { -/// Err(MultiLocation::X1(Junction::Parachain(id + 1))) +/// match origin.junctions() { +/// Junctions::X1(Junction::Parachain(id)) if origin.parent_count() == 0 => { +/// Err(Junctions::X1(Junction::Parachain(id + 1)).into()) /// } /// _ => unreachable!() /// } @@ -143,8 +143,8 @@ impl<T: Clone + Encode + Decode> Convert<Vec<u8>, T> for Decoded { /// struct AcceptPara7; /// impl ConvertOrigin<u32> for AcceptPara7 { /// fn convert_origin(origin: MultiLocation, _: OriginKind) -> Result<u32, MultiLocation> { -/// match origin { -/// MultiLocation::X1(Junction::Parachain(id)) if id == 7 => { +/// match origin.junctions() { +/// Junctions::X1(Junction::Parachain(id)) if id == &7 && origin.parent_count() == 0 => { /// Ok(7) /// } /// _ => Err(origin) @@ -152,7 +152,7 @@ impl<T: Clone + Encode + Decode> Convert<Vec<u8>, 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<u32>>::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 a967f1f6909a..08c13daaa818 100644 --- a/xcm/xcm-executor/src/traits/transact_asset.rs +++ b/xcm/xcm-executor/src/traits/transact_asset.rs @@ -246,27 +246,27 @@ mod tests { fn defaults_to_asset_not_found() { type MultiTransactor = (UnimplementedTransactor, NotFoundTransactor, UnimplementedTransactor); - assert_eq!(MultiTransactor::deposit_asset(&MultiAsset::All, &MultiLocation::Null), Err(XcmError::AssetNotFound)); + assert_eq!(MultiTransactor::deposit_asset(&MultiAsset::All, &MultiLocation::default()), Err(XcmError::AssetNotFound)); } #[test] fn unimplemented_and_not_found_continue_iteration() { type MultiTransactor = (UnimplementedTransactor, NotFoundTransactor, SuccessfulTransactor); - assert_eq!(MultiTransactor::deposit_asset(&MultiAsset::All, &MultiLocation::Null), Ok(())); + assert_eq!(MultiTransactor::deposit_asset(&MultiAsset::All, &MultiLocation::default()), Ok(())); } #[test] fn unexpected_error_stops_iteration() { type MultiTransactor = (OverflowTransactor, SuccessfulTransactor); - assert_eq!(MultiTransactor::deposit_asset(&MultiAsset::All, &MultiLocation::Null), Err(XcmError::Overflow)); + assert_eq!(MultiTransactor::deposit_asset(&MultiAsset::All, &MultiLocation::default()), Err(XcmError::Overflow)); } #[test] fn success_stops_iteration() { type MultiTransactor = (SuccessfulTransactor, OverflowTransactor); - assert_eq!(MultiTransactor::deposit_asset(&MultiAsset::All, &MultiLocation::Null), Ok(())); + assert_eq!(MultiTransactor::deposit_asset(&MultiAsset::All, &MultiLocation::default()), Ok(())); } } From 2661b91a5cc1ea6721e067db71cd1e9bb000fcb3 Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Fri, 30 Jul 2021 19:59:10 +0200 Subject: [PATCH 010/166] XCM core builds --- xcm/src/v0/mod.rs | 11 ++++- xcm/src/v0/multi_asset.rs | 3 +- xcm/src/v0/multiasset.rs | 79 ++++++++++++++++++---------------- xcm/xcm-executor/src/assets.rs | 14 ------ 4 files changed, 51 insertions(+), 56 deletions(-) diff --git a/xcm/src/v0/mod.rs b/xcm/src/v0/mod.rs index cc8044ea19d2..8f16bee29b39 100644 --- a/xcm/src/v0/mod.rs +++ b/xcm/src/v0/mod.rs @@ -20,7 +20,7 @@ use core::{result, convert::TryFrom, fmt::Debug}; use derivative::Derivative; use alloc::vec::Vec; use parity_scale_codec::{self, Encode, Decode}; -use crate::{VersionedMultiAsset, VersionedWildMultiAsset, DoubleEncoded, VersionedXcm}; +use crate::{DoubleEncoded, VersionedXcm}; mod junction; mod multi_asset; @@ -40,7 +40,14 @@ pub use traits::{Error, Result, SendXcm, ExecuteXcm, Outcome}; /// A prelude for importing all types typically used when interacting with XCM messages. pub mod prelude { pub use super::junction::{Junction::*, NetworkId, BodyId, BodyPart}; - pub use super::multi_asset::{MultiAsset::{self, *}, AssetInstance::{self, *}}; + pub use super::multiasset::{ + AssetId, MultiAssets, MultiAsset, + AssetInstance::{self, *}, + MultiAssetFilter::{self, *}, + Fungibility::{self, *}, + WildMultiAsset::{self, *}, + WildFungibility::{self, Fungible as WildFungible, NonFungible as WildNonFungible}, + }; pub use super::multi_location::MultiLocation::{self, *}; pub use super::order::Order::{self, *}; pub use super::traits::{Error as XcmError, Result as XcmResult, SendXcm, ExecuteXcm, Outcome}; diff --git a/xcm/src/v0/multi_asset.rs b/xcm/src/v0/multi_asset.rs index d7065d3e1d8e..fe53f6905aa5 100644 --- a/xcm/src/v0/multi_asset.rs +++ b/xcm/src/v0/multi_asset.rs @@ -16,11 +16,10 @@ //! Cross-Consensus Message format data structures. -use core::{result, convert::TryFrom}; use alloc::vec::Vec; use parity_scale_codec::{self, Encode, Decode}; -use super::{MultiLocation, VersionedMultiAsset, AssetInstance}; +use super::{MultiLocation, AssetInstance}; /// A single general identifier for an asset. /// diff --git a/xcm/src/v0/multiasset.rs b/xcm/src/v0/multiasset.rs index 010f1ce4c1da..45e19323e04a 100644 --- a/xcm/src/v0/multiasset.rs +++ b/xcm/src/v0/multiasset.rs @@ -24,11 +24,10 @@ //! account. use core::convert::{TryFrom, TryInto}; -use alloc::vec::Vec; +use alloc::{vec, vec::Vec}; use parity_scale_codec::{self as codec, Encode, Decode}; use super::{ - MultiLocation, multi_asset::MultiAsset as OldMultiAsset, VersionedMultiAsset, - VersionedWildMultiAsset, + MultiLocation, multi_asset::MultiAsset as OldMultiAsset, }; use core::cmp::Ordering; @@ -79,15 +78,9 @@ impl AssetId { MultiAsset { fun, id: self } } - /// Use the value of `self` along with a `fun` fungibility specifier to create the corresponding `WildMultiAsset` - /// definite (`Asset`) value. - pub fn into_wild(self, fun: Fungibility) -> WildMultiAsset { - WildMultiAsset::Asset(fun, self) - } - /// Use the value of `self` along with a `fun` fungibility specifier to create the corresponding `WildMultiAsset` /// wildcard (`AllOf`) value. - pub fn into_allof(self, fun: WildFungibility) -> WildMultiAsset { + pub fn into_wild(self, fun: WildFungibility) -> WildMultiAsset { WildMultiAsset::AllOf(fun, self) } } @@ -137,10 +130,10 @@ impl PartialOrd for MultiAsset { impl Ord for MultiAsset { fn cmp(&self, other: &Self) -> Ordering { match (&self.fun, &other.fun) { - (Fungibility::Fungible(..), Fungibility::NonFungible(..)) => return Ordering::Less, - (Fungibility::NonFungible(..), Fungibility::Fungible(..)) => return Ordering::Greater, + (Fungibility::Fungible(..), Fungibility::NonFungible(..)) => Ordering::Less, + (Fungibility::NonFungible(..), Fungibility::Fungible(..)) => Ordering::Greater, + _ => (&self.id, &self.fun).cmp(&(&other.id, &other.fun)), } - (&self.id, &self.fun).cmp((&other.id, &other.fun)) } } @@ -197,18 +190,17 @@ impl Encode for MultiAsset { impl Decode for MultiAsset { fn decode<I: codec::Input>(input: &mut I) -> Result<Self, parity_scale_codec::Error> { - OldMultiAsset::decode(input) - .and_then(|r| TryInto::try_into(r).map_err(|_| "Unsupported wildcard".into()))? + OldMultiAsset::decode(input)?.try_into().map_err(|_| "Unsupported wildcard".into()) } } impl MultiAsset { - fn is_fungible(&self, maybe_id: Option<AssetId>) -> bool { + pub fn is_fungible(&self, maybe_id: Option<AssetId>) -> bool { use Fungibility::*; matches!(self.fun, Fungible(..)) && maybe_id.map_or(true, |i| i == self.id) } - fn is_non_fungible(&self, maybe_id: Option<AssetId>) -> bool { + pub fn is_non_fungible(&self, maybe_id: Option<AssetId>) -> bool { use Fungibility::*; matches!(self.fun, NonFungible(..)) && maybe_id.map_or(true, |i| i == self.id) } @@ -220,7 +212,7 @@ impl MultiAsset { /// Returns true if `self` is a super-set of the given `inner`. pub fn contains(&self, inner: &MultiAsset) -> bool { - use {MultiAsset::*, Fungibility::*}; + use Fungibility::*; if self.id == inner.id { match (&self.fun, &inner.fun) { (Fungible(a), Fungible(i)) if a >= i => return true, @@ -242,7 +234,7 @@ impl Decode for MultiAssets { fn decode<I: codec::Input>(input: &mut I) -> Result<Self, parity_scale_codec::Error> { let r = Vec::<MultiAsset>::decode(input)?; if r.is_empty() { return Ok(Self(Vec::new())) } - r.iter().skip(1).try_fold(&r[0], |a, b| { + r.iter().skip(1).try_fold(&r[0], |a, b| -> Result<&MultiAsset, parity_scale_codec::Error> { if a.id < b.id || a < b && (a.is_non_fungible(None) || b.is_non_fungible(None)) { Ok(b) } else { @@ -262,7 +254,7 @@ impl From<MultiAssets> for Vec<OldMultiAsset> { impl TryFrom<Vec<OldMultiAsset>> for MultiAssets { type Error = (); fn try_from(a: Vec<OldMultiAsset>) -> Result<Self, ()> { - a.0.into_iter().map(MultiAsset::try_from).collect() + a.into_iter().map(MultiAsset::try_from).collect::<Result<_, _>>().map(Self) } } @@ -293,7 +285,6 @@ impl MultiAssets { /// Returns true if `self` is a super-set of the given `inner`. pub fn contains(&self, inner: &MultiAsset) -> bool { - use {MultiAsset::*, Fungibility::*}; self.0.iter().any(|i| i.contains(inner)) } @@ -339,19 +330,19 @@ impl Encode for WildMultiAsset { impl Decode for WildMultiAsset { fn decode<I: codec::Input>(input: &mut I) -> Result<Self, parity_scale_codec::Error> { - OldMultiAsset::decode(input).map(Into::into) + OldMultiAsset::decode(input)?.try_into().map_err(|()| "Invalid wildcard item".into()) } } impl From<WildMultiAsset> for OldMultiAsset { fn from(a: WildMultiAsset) -> Self { - use {AssetId::*, Fungibility::*, OldMultiAsset::*, WildMultiAsset::AllOf}; + use {AssetId::*, WildFungibility::*, OldMultiAsset::*, WildMultiAsset::AllOf}; match a { WildMultiAsset::All => All, - AllOf(WildFungibility::Fungible, Concrete(id)) => AllConcreteFungible { id }, - AllOf(WildFungibility::Fungible, Abstract(id)) => AllAbstractFungible { id }, - AllOf(WildFungibility::NonFungible, Concrete(class)) => AllConcreteNonFungible { class }, - AllOf(WildFungibility::NonFungible, Abstract(class)) => AllAbstractNonFungible { class }, + AllOf(Fungible, Concrete(id)) => AllConcreteFungible { id }, + AllOf(Fungible, Abstract(id)) => AllAbstractFungible { id }, + AllOf(NonFungible, Concrete(class)) => AllConcreteNonFungible { class }, + AllOf(NonFungible, Abstract(class)) => AllAbstractNonFungible { class }, } } } @@ -359,13 +350,13 @@ impl From<WildMultiAsset> for OldMultiAsset { impl TryFrom<OldMultiAsset> for WildMultiAsset { type Error = (); fn try_from(a: OldMultiAsset) -> Result<Self, ()> { - use {AssetId::*, Fungibility::*, OldMultiAsset::*, WildMultiAsset::AllOf}; + use {AssetId::*, WildFungibility::*, OldMultiAsset::*, WildMultiAsset::AllOf}; Ok(match a { All => WildMultiAsset::All, - AllConcreteFungible { id } => AllOf(WildFungibility::Fungible, Concrete(id)), - AllAbstractFungible { id } => AllOf(WildFungibility::Fungible, Abstract(id)), - AllConcreteNonFungible { class } => AllOf(WildFungibility::NonFungible, Concrete(class)), - AllAbstractNonFungible { class } => AllOf(WildFungibility::NonFungible, Abstract(class)), + AllConcreteFungible { id } => AllOf(Fungible, Concrete(id)), + AllAbstractFungible { id } => AllOf(Fungible, Abstract(id)), + AllConcreteNonFungible { class } => AllOf(NonFungible, Concrete(class)), + AllAbstractNonFungible { class } => AllOf(NonFungible, Abstract(class)), _ => return Err(()), }) } @@ -379,7 +370,7 @@ impl WildMultiAsset { pub fn contains(&self, inner: &MultiAsset) -> bool { use WildMultiAsset::*; match self { - AllOf(fun, id) => inner.fun.is_kind(*fun) && inner.id == id, + AllOf(fun, id) => inner.fun.is_kind(*fun) && &inner.id == id, All => true, } } @@ -388,7 +379,7 @@ impl WildMultiAsset { pub fn reanchor(&mut self, prepend: &MultiLocation) -> Result<(), ()> { use WildMultiAsset::*; match self { - AllOf(_, ref mut id) => id.prepend_with(prepend.clone()).map_err(|_| ()), + AllOf(_, ref mut id) => id.reanchor(prepend).map_err(|_| ()), _ => Ok(()), } } @@ -418,16 +409,28 @@ impl From<MultiAssetFilter> for Vec<OldMultiAsset> { impl TryFrom<Vec<OldMultiAsset>> for MultiAssetFilter { type Error = (); - fn try_from(old_assets: Vec<OldMultiAsset>) -> Result<Self, ()> { + fn try_from(mut old_assets: Vec<OldMultiAsset>) -> Result<Self, ()> { use MultiAssetFilter::*; if old_assets.is_empty() { return Ok(Assets(MultiAssets::new())) } - if let (1, Ok(wild)) = (old_assets.len(), old_assets[0].try_into()) { - return Ok(Wild(wild)) + if old_assets.len() == 1 && old_assets[0].is_wildcard() { + return old_assets.pop().ok_or(()).and_then(|i| Ok(Wild(i.try_into()?))) } - old_assets.into_iter().map(MultiAsset::try_from).collect() + MultiAssets::try_from(old_assets).map(Self::Assets) + } +} + +impl Encode for MultiAssetFilter { + fn encode(&self) -> Vec<u8> { + Vec::<OldMultiAsset>::from(self.clone()).encode() + } +} + +impl Decode for MultiAssetFilter { + fn decode<I: codec::Input>(input: &mut I) -> Result<Self, parity_scale_codec::Error> { + Vec::<OldMultiAsset>::decode(input)?.try_into().map_err(|()| "Invalid items".into()) } } diff --git a/xcm/xcm-executor/src/assets.rs b/xcm/xcm-executor/src/assets.rs index 97c5fbbc15a5..59a6b9fd81e6 100644 --- a/xcm/xcm-executor/src/assets.rs +++ b/xcm/xcm-executor/src/assets.rs @@ -113,21 +113,7 @@ impl Assets { NonFungible(instance) => self.non_fungible.insert((asset.id, instance)), } } -/* - /// Modify `self` to include a new fungible asset by `id` and `amount`, - /// saturating if necessary. - pub fn saturating_subsume_fungible(&mut self, id: AssetId, amount: u128) { - self.fungible - .entry(id) - .and_modify(|e| *e = e.saturating_add(amount)) - .or_insert(amount); - } - /// Modify `self` to include a new non-fungible asset by `class` and `instance`. - pub fn saturating_subsume_non_fungible(&mut self, class: AssetId, instance: AssetInstance) { - self.non_fungible.insert((class, instance)); - } -*/ /// Swaps two mutable Assets, without deinitializing either one. pub fn swapped(&mut self, mut with: Assets) -> Self { mem::swap(&mut *self, &mut with); From 6fc030eac3753c6519fa0a6f67e5e1b580a2c547 Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Fri, 30 Jul 2021 21:13:15 +0200 Subject: [PATCH 011/166] XCM Executor builds --- xcm/src/v0/mod.rs | 14 +-- xcm/src/v0/multiasset.rs | 12 ++ xcm/xcm-builder/src/weight.rs | 13 +-- xcm/xcm-executor/src/assets.rs | 105 ++++++++++-------- xcm/xcm-executor/src/lib.rs | 42 +++---- xcm/xcm-executor/src/traits/transact_asset.rs | 8 +- xcm/xcm-executor/src/traits/weight.rs | 2 +- 7 files changed, 103 insertions(+), 93 deletions(-) diff --git a/xcm/src/v0/mod.rs b/xcm/src/v0/mod.rs index 8f16bee29b39..2d4c192d3ec0 100644 --- a/xcm/src/v0/mod.rs +++ b/xcm/src/v0/mod.rs @@ -54,7 +54,7 @@ pub mod prelude { pub use super::{Xcm::{self, *}, OriginKind}; } -// TODO: #2841 #XCMENCODE Efficient encodings for Vec<MultiAsset>, Vec<Order>, using initial byte values 128+ to encode +// TODO: #2841 #XCMENCODE Efficient encodings for MultiAssets, Vec<Order>, using initial byte values 128+ to encode // the number of items in the vector. /// Basically just the XCM (more general) version of `ParachainDispatchOrigin`. @@ -84,7 +84,7 @@ pub enum OriginKind { #[derive(Clone, Eq, PartialEq, Encode, Decode, Debug)] pub enum Response { /// Some assets. - Assets(Vec<MultiAsset>), + Assets(MultiAssets), } /// Cross-Consensus Message: A message from one consensus system to another. @@ -110,7 +110,7 @@ pub enum Xcm<Call> { /// /// Errors: #[codec(index = 0)] - WithdrawAsset { assets: Vec<MultiAsset>, effects: Vec<Order<Call>> }, + WithdrawAsset { assets: MultiAssets, effects: Vec<Order<Call>> }, /// Asset(s) (`assets`) have been received into the ownership of this system on the `origin` system. /// @@ -127,7 +127,7 @@ pub enum Xcm<Call> { /// /// Errors: #[codec(index = 1)] - ReserveAssetDeposit { assets: Vec<MultiAsset>, effects: Vec<Order<Call>> }, + ReserveAssetDeposit { assets: MultiAssets, effects: Vec<Order<Call>> }, /// Asset(s) (`assets`) have been destroyed on the `origin` system and equivalent assets should be /// created on this system. @@ -145,7 +145,7 @@ pub enum Xcm<Call> { /// /// Errors: #[codec(index = 2)] - TeleportAsset { assets: Vec<MultiAsset>, effects: Vec<Order<Call>> }, + TeleportAsset { assets: MultiAssets, effects: Vec<Order<Call>> }, /// Indication of the contents of the holding account corresponding to the `QueryHolding` order of `query_id`. /// @@ -172,7 +172,7 @@ pub enum Xcm<Call> { /// /// Errors: #[codec(index = 4)] - TransferAsset { assets: Vec<MultiAsset>, dest: MultiLocation }, + TransferAsset { assets: MultiAssets, dest: MultiLocation }, /// Withdraw asset(s) (`assets`) from the ownership of `origin` and place equivalent assets under the /// ownership of `dest` within this consensus system. @@ -190,7 +190,7 @@ pub enum Xcm<Call> { /// /// Errors: #[codec(index = 5)] - TransferReserveAsset { assets: Vec<MultiAsset>, dest: MultiLocation, effects: Vec<Order<()>> }, + TransferReserveAsset { assets: MultiAssets, dest: MultiLocation, effects: Vec<Order<()>> }, /// Apply the encoded transaction `call`, whose dispatch-origin should be `origin` as expressed by the kind /// of origin `origin_type`. diff --git a/xcm/src/v0/multiasset.rs b/xcm/src/v0/multiasset.rs index 45e19323e04a..3d0ee0d2d00e 100644 --- a/xcm/src/v0/multiasset.rs +++ b/xcm/src/v0/multiasset.rs @@ -245,6 +245,12 @@ impl Decode for MultiAssets { } } +impl From<Vec<MultiAsset>> for MultiAssets { + fn from(x: Vec<MultiAsset>) -> Self { + Self(x) + } +} + impl From<MultiAssets> for Vec<OldMultiAsset> { fn from(a: MultiAssets) -> Self { a.0.into_iter().map(OldMultiAsset::from).collect() @@ -397,6 +403,12 @@ pub enum MultiAssetFilter { Wild(WildMultiAsset), } +impl From<WildMultiAsset> for MultiAssetFilter { + fn from(x: WildMultiAsset) -> Self { + Self::Wild(x) + } +} + impl From<MultiAssetFilter> for Vec<OldMultiAsset> { fn from(a: MultiAssetFilter) -> Self { use MultiAssetFilter::*; diff --git a/xcm/xcm-builder/src/weight.rs b/xcm/xcm-builder/src/weight.rs index e2096afcaa30..26f282abfec7 100644 --- a/xcm/xcm-builder/src/weight.rs +++ b/xcm/xcm-builder/src/weight.rs @@ -110,14 +110,13 @@ impl<T: Get<(MultiLocation, u128)>, R: TakeRevenue> WeightTrader for FixedRateOf Ok(unused) } - fn refund_weight(&mut self, weight: Weight) -> MultiAsset { + fn refund_weight(&mut self, weight: Weight) -> Option<MultiAsset> { let (id, units_per_second) = T::get(); let weight = weight.min(self.0); let amount = units_per_second * (weight as u128) / 1_000_000_000_000u128; self.0 -= weight; self.1 = self.1.saturating_sub(amount); - let result = MultiAsset::ConcreteFungible { amount, id }; - result + Some((id, amount).into()) } } @@ -158,16 +157,12 @@ impl< Ok(unused) } - fn refund_weight(&mut self, weight: Weight) -> MultiAsset { + fn refund_weight(&mut self, weight: Weight) -> Option<MultiAsset> { let weight = weight.min(self.0); let amount = WeightToFee::calc(&weight); self.0 -= weight; self.1 = self.1.saturating_sub(amount); - let result = MultiAsset::ConcreteFungible { - amount: amount.saturated_into(), - id: AssetId::get(), - }; - result + Some(MultiAsset::from((AssetId::get(), amount.saturated_into()))) } } diff --git a/xcm/xcm-executor/src/assets.rs b/xcm/xcm-executor/src/assets.rs index 59a6b9fd81e6..7c2b5410991c 100644 --- a/xcm/xcm-executor/src/assets.rs +++ b/xcm/xcm-executor/src/assets.rs @@ -16,10 +16,8 @@ use sp_std::{prelude::*, mem, collections::{btree_map::BTreeMap, btree_set::BTreeSet}}; use xcm::v0::{ - MultiAsset, MultiAssets, MultiLocation, AssetInstance, - MultiAssetFilter::{self, Assets, Wild}, - AssetId::{self, Concrete, Abstract}, - WildMultiAsset::{self, All, AllOf}, + MultiAsset, MultiAssets, MultiLocation, AssetInstance, MultiAssetFilter, AssetId, + WildMultiAsset::{All, AllOf}, Fungibility::{Fungible, NonFungible}, WildFungibility::{Fungible as WildFungible, NonFungible as WildNonFungible}, }; @@ -32,7 +30,7 @@ pub struct Assets { pub fungible: BTreeMap<AssetId, u128>, /// The non-fungible assets. - // OPTIMIZE: Consider BTreeMap<AssetId, BTreeSet<AssetInstance>> + // TODO: Consider BTreeMap<AssetId, BTreeSet<AssetInstance>> // or even BTreeMap<AssetId, SortedVec<AssetInstance>> pub non_fungible: BTreeSet<(AssetId, AssetInstance)>, } @@ -47,12 +45,24 @@ impl From<Vec<MultiAsset>> for Assets { } } +impl From<MultiAssets> for Assets { + fn from(assets: MultiAssets) -> Assets { + assets.drain().into() + } +} + impl From<Assets> for Vec<MultiAsset> { fn from(a: Assets) -> Self { a.into_assets_iter().collect() } } +impl From<Assets> for MultiAssets { + fn from(a: Assets) -> Self { + a.into_assets_iter().collect::<Vec<MultiAsset>>().into() + } +} + impl From<MultiAsset> for Assets { fn from(asset: MultiAsset) -> Assets { let mut result = Self::default(); @@ -62,6 +72,7 @@ impl From<MultiAsset> for Assets { } /// An error emitted by `take` operations. +#[derive(Debug)] pub enum TakeError { /// There was an attempt to take an asset without saturating (enough of) which did not exist. AssetUnderflow(MultiAsset), @@ -106,11 +117,15 @@ impl Assets { /// Wildcard values of `asset` do nothing. pub fn subsume(&mut self, asset: MultiAsset) { match asset.fun { - Fungible(amount) => self.fungible - .entry(asset.id) - .and_modify(|e| *e = e.saturating_add(amount)) - .or_insert(amount), - NonFungible(instance) => self.non_fungible.insert((asset.id, instance)), + Fungible(amount) => { + self.fungible + .entry(asset.id) + .and_modify(|e| *e = e.saturating_add(amount)) + .or_insert(amount); + } + NonFungible(instance) => { + self.non_fungible.insert((asset.id, instance)); + } } } @@ -128,12 +143,12 @@ impl Assets { let mut fungible = Default::default(); mem::swap(&mut self.fungible, &mut fungible); self.fungible = fungible.into_iter() - .map(|(mut id, amount)| { let _ = id.prepend_location(prepend); (id, amount) }) + .map(|(mut id, amount)| { let _ = id.reanchor(prepend); (id, amount) }) .collect(); let mut non_fungible = Default::default(); mem::swap(&mut self.non_fungible, &mut non_fungible); self.non_fungible = non_fungible.into_iter() - .map(|(mut class, inst)| { let _ = class.prepend_location(prepend); (class, inst) }) + .map(|(mut class, inst)| { let _ = class.reanchor(prepend); (class, inst) }) .collect(); } @@ -144,13 +159,13 @@ impl Assets { match asset { MultiAsset { fun: Fungible(ref amount), ref id } => { if self.fungible.get(id).map_or(true, |a| a < amount) { - return Err(TakeError((id.clone(), amount).into())) + return Err(TakeError::AssetUnderflow((id.clone(), *amount).into())) } } MultiAsset { fun: NonFungible(ref instance), ref id } => { let id_instance = (id.clone(), instance.clone()); if !self.non_fungible.contains(&id_instance) { - return Err(TakeError(id_instance.into())) + return Err(TakeError::AssetUnderflow(id_instance.into())) } } } @@ -162,46 +177,42 @@ impl Assets { /// /// If `saturate` is `true`, then `self` is considered to be masked by `mask`, thereby avoiding any attempt at /// reducing it by assets it does not contain. In this case, the function is infallible. If `saturate` is `false` - /// and `asset` references a definite asset which `self` does not contain then an error is returned. + /// and `mask` references a definite asset which `self` does not contain then an error is returned. /// /// Returns `Ok` with the definite assets token from `self` and mutates `self` to its value minus - /// `asset`. Returns `Err` in the non-saturating case where `self` did not contain (enough of) a definite asset to + /// `mask`. Returns `Err` in the non-saturating case where `self` did not contain (enough of) a definite asset to /// be removed. fn general_take(&mut self, mask: MultiAssetFilter, saturate: bool) -> Result<Assets, TakeError> { + let mut taken = Assets::new(); match mask { - Wild(All) => Ok(self.swapped(Assets::new())), - Wild(AllOf(WildFungible, id)) => { - let mut taken = Assets::new(); + MultiAssetFilter::Wild(All) => return Ok(self.swapped(Assets::new())), + MultiAssetFilter::Wild(AllOf(WildFungible, id)) => { if let Some((id, amount)) = self.fungible.remove_entry(&id) { taken.fungible.insert(id, amount); } - Ok(taken) } - Wild(AllOf(WildNonFungible, id)) => { - let mut taken = Assets::new(); + MultiAssetFilter::Wild(AllOf(WildNonFungible, id)) => { let non_fungible = mem::replace(&mut self.non_fungible, Default::default()); non_fungible.into_iter().for_each(|(c, instance)| { - if &c == id { + if c == id { taken.non_fungible.insert((c, instance)); } else { self.non_fungible.insert((c, instance)); } }); - Ok(taken) } - Assets(assets) => { + MultiAssetFilter::Assets(assets) => { if !saturate { self.ensure_contains(&assets)?; } - let mut taken = Assets::new(); for asset in assets.drain().into_iter() { match asset { - MultiAsset { fun: Fungible(mut amount), id } => { + MultiAsset { fun: Fungible(amount), id } => { let (remove, amount) = match self.fungible.get_mut(&id) { Some(self_amount) => { let amount = amount.min(*self_amount); *self_amount -= amount; - (self_amount == 0, amount) + (*self_amount == 0, amount) } None => (false, 0), }; @@ -222,32 +233,30 @@ impl Assets { } } } + Ok(taken) } - /// Mutates `self` to its original value less `asset` and returns `true` iff it contains at least `asset`. - /// - /// `asset` is interpreted as being masked under `self`. + /// Mutates `self` to its original value less `mask` and returns `true` iff it contains at least `mask`. /// - /// Returns `Ok` with the non-wildcard equivalence of `asset` taken and mutates `self` to its value minus - /// `asset` if `self` contains `asset`, and return `Err` otherwise. + /// Returns `Ok` with the non-wildcard equivalence of `mask` taken and mutates `self` to its value minus + /// `mask` if `self` contains `asset`, and return `Err` otherwise. pub fn saturating_take(&mut self, asset: MultiAssetFilter) -> Assets { - self.general_take(asset, true).expect("general_take never results in error when saturating") + self.general_take(asset, true) + .expect("general_take never results in error when saturating") } - /// Mutates `self` to its original value less `asset` and returns `true` iff it contains at least `asset`. - /// - /// `asset` is interpreted as being masked under `self`. + /// Mutates `self` to its original value less `mask` and returns `true` iff it contains at least `mask`. /// /// Returns `Ok` with the non-wildcard equivalence of `asset` taken and mutates `self` to its value minus /// `asset` if `self` contains `asset`, and return `Err` otherwise. - pub fn try_take(&mut self, asset: MultiAssetFilter) -> Result<Assets, TakeError> { - self.general_take(asset, false) + pub fn try_take(&mut self, mask: MultiAssetFilter) -> Result<Assets, TakeError> { + self.general_take(mask, false) } - /// Consumes `self` and returns its original value excluding `asset` iff it contains at least `asset`, as well as + /// Consumes `self` and returns its original value excluding `mask` iff it contains at least `mask`, as well as /// the assets excluded. - pub fn less(mut self, asset: WildMultiAsset) -> Result<(Assets, Assets), Self> { - match self.try_take(asset) { + pub fn less(mut self, mask: MultiAssetFilter) -> Result<(Assets, Assets), Self> { + match self.try_take(mask) { Ok(taken) => Ok((self, taken)), Err(_) => Err(self), } @@ -277,23 +286,23 @@ impl Assets { /// MultiAsset::AbstractFungible { id: vec![0], amount: 50 }, /// ]); /// ``` - pub fn min(&self, mask: MultiAssetFilter) -> Assets { + pub fn min(&self, mask: &MultiAssetFilter) -> Assets { let mut masked = Assets::new(); match mask { - Wild(All) => Ok(self.clone()), - Wild(AllOf(WildFungible, id)) => { - if let Some(&(ref id, amount)) = self.fungible.get(&id) { + MultiAssetFilter::Wild(All) => return self.clone(), + MultiAssetFilter::Wild(AllOf(WildFungible, id)) => { + if let Some(&amount) = self.fungible.get(&id) { masked.fungible.insert(id.clone(), amount); } } - Wild(AllOf(WildNonFungible, id)) => { + MultiAssetFilter::Wild(AllOf(WildNonFungible, id)) => { self.non_fungible.iter().for_each(|(ref c, ref instance)| { if c == id { masked.non_fungible.insert((c.clone(), instance.clone())); } }); } - Assets(assets) => { + MultiAssetFilter::Assets(assets) => { for asset in assets.inner().iter() { match asset { MultiAsset { fun: Fungible(ref amount), ref id } => { diff --git a/xcm/xcm-executor/src/lib.rs b/xcm/xcm-executor/src/lib.rs index 87b770533db2..b9ec7b4a6e92 100644 --- a/xcm/xcm-executor/src/lib.rs +++ b/xcm/xcm-executor/src/lib.rs @@ -21,10 +21,7 @@ use frame_support::{ ensure, weights::GetDispatchInfo, dispatch::{Weight, Dispatchable} }; -use xcm::v0::{ - ExecuteXcm, SendXcm, Error as XcmError, Outcome, - MultiLocation, MultiAsset, Xcm, Order, Response, -}; +use xcm::v0::{ExecuteXcm, SendXcm, Error as XcmError, Outcome, MultiLocation, MultiAssets, Xcm, Order, Response}; pub mod traits; use traits::{ @@ -33,7 +30,7 @@ use traits::{ }; mod assets; -pub use assets::{Assets, AssetId}; +pub use assets::Assets; mod config; pub use config::Config; @@ -86,10 +83,10 @@ impl<Config: config::Config> ExecuteXcm<Config::Call> for XcmExecutor<Config> { } impl<Config: config::Config> XcmExecutor<Config> { - fn reanchored(mut assets: Assets, dest: &MultiLocation) -> Vec<MultiAsset> { + fn reanchored(mut assets: Assets, dest: &MultiLocation) -> MultiAssets { let inv_dest = Config::LocationInverter::invert_location(&dest); assets.prepend_location(&inv_dest); - assets.into_assets_iter().collect::<Vec<_>>() + assets.into_assets_iter().collect::<Vec<_>>().into() } /// Execute the XCM and return the portion of weight of `shallow_weight + deep_weight` that `message` did not use. @@ -130,8 +127,7 @@ impl<Config: config::Config> XcmExecutor<Config> { (origin, Xcm::WithdrawAsset { assets, effects }) => { // Take `assets` from the origin account (on-chain) and place in holding. let mut holding = Assets::default(); - for asset in assets { - ensure!(!asset.is_wildcard(), XcmError::Wildcard); + for asset in assets.inner() { let withdrawn = Config::AssetTransactor::withdraw_asset(&asset, &origin)?; holding.subsume_assets(withdrawn); } @@ -139,18 +135,16 @@ impl<Config: config::Config> XcmExecutor<Config> { } (origin, Xcm::ReserveAssetDeposit { assets, effects }) => { // check whether we trust origin to be our reserve location for this asset. - for asset in assets.iter() { - ensure!(!asset.is_wildcard(), XcmError::Wildcard); + for asset in assets.inner() { // We only trust the origin to send us assets that they identify as their // sovereign assets. ensure!(Config::IsReserve::filter_asset_location(asset, &origin), XcmError::UntrustedReserveLocation); } - Some((Assets::from(assets), effects)) + Some((assets.into(), effects)) } (origin, Xcm::TransferAsset { assets, dest }) => { // Take `assets` from the origin account (on-chain) and place into dest account. - for asset in assets { - ensure!(!asset.is_wildcard(), XcmError::Wildcard); + for asset in assets.inner() { Config::AssetTransactor::teleport_asset(&asset, &origin, &dest)?; } None @@ -158,18 +152,16 @@ impl<Config: config::Config> XcmExecutor<Config> { (origin, Xcm::TransferReserveAsset { mut assets, dest, effects }) => { // Take `assets` from the origin account (on-chain) and place into dest account. let inv_dest = Config::LocationInverter::invert_location(&dest); - for asset in assets.iter_mut() { - ensure!(!asset.is_wildcard(), XcmError::Wildcard); - Config::AssetTransactor::teleport_asset(&asset, &origin, &dest)?; - asset.reanchor(&inv_dest)?; + for asset in assets.inner() { + Config::AssetTransactor::teleport_asset(asset, &origin, &dest)?; } + assets.reanchor(&inv_dest)?; Config::XcmSender::send_xcm(dest, Xcm::ReserveAssetDeposit { assets, effects })?; None } (origin, Xcm::TeleportAsset { assets, effects }) => { // check whether we trust origin to teleport this asset to us via config trait. - for asset in assets.iter() { - ensure!(!asset.is_wildcard(), XcmError::Wildcard); + for asset in assets.inner() { // We only trust the origin to send us assets that they identify as their // sovereign assets. ensure!(Config::IsTeleporter::filter_asset_location(asset, &origin), XcmError::UntrustedTeleportLocation); @@ -178,7 +170,7 @@ impl<Config: config::Config> XcmExecutor<Config> { // don't want to punish a possibly innocent chain/user). Config::AssetTransactor::can_check_in(&origin, asset)?; } - for asset in assets.iter() { + for asset in assets.inner() { Config::AssetTransactor::check_in(&origin, asset); } Some((Assets::from(assets), effects)) @@ -280,13 +272,13 @@ impl<Config: config::Config> XcmExecutor<Config> { Config::XcmSender::send_xcm(dest, Xcm::TeleportAsset { assets, effects })?; } Order::QueryHolding { query_id, dest, assets } => { - let assets = Self::reanchored(holding.min(assets.iter()), &dest); + let assets = Self::reanchored(holding.min(&assets), &dest); Config::XcmSender::send_xcm(dest, Xcm::QueryResponse { query_id, response: Response::Assets(assets) })?; } Order::BuyExecution { fees, weight, debt, halt_on_error, xcm } => { // pay for `weight` using up to `fees` of the holding account. let purchasing_weight = Weight::from(weight.checked_add(debt).ok_or(XcmError::Overflow)?); - let max_fee = holding.try_take(fees).map_err(|()| XcmError::NotHoldingFees)?; + let max_fee = holding.try_take(fees.into()).map_err(|_| XcmError::NotHoldingFees)?; let unspent = trader.buy_weight(purchasing_weight, max_fee)?; holding.subsume_assets(unspent); @@ -298,7 +290,9 @@ impl<Config: config::Config> XcmExecutor<Config> { Ok(surplus) => { total_surplus += surplus } } } - holding.subsume(trader.refund_weight(remaining_weight)); + if let Some(w) = trader.refund_weight(remaining_weight) { + holding.subsume(w); + } } _ => return Err(XcmError::UnhandledEffect)?, } diff --git a/xcm/xcm-executor/src/traits/transact_asset.rs b/xcm/xcm-executor/src/traits/transact_asset.rs index a967f1f6909a..610f98977ca7 100644 --- a/xcm/xcm-executor/src/traits/transact_asset.rs +++ b/xcm/xcm-executor/src/traits/transact_asset.rs @@ -103,7 +103,7 @@ impl TransactAsset for Tuple { fn can_check_in(origin: &MultiLocation, what: &MultiAsset) -> XcmResult { for_tuples!( #( match Tuple::can_check_in(origin, what) { - Err(XcmError::AssetNotFound | XcmError::Unimplemented) => (), + Err(XcmError::AssetNotFound) | Err(XcmError::Unimplemented) => (), r => return r, } )* ); @@ -131,7 +131,7 @@ impl TransactAsset for Tuple { fn deposit_asset(what: &MultiAsset, who: &MultiLocation) -> XcmResult { for_tuples!( #( match Tuple::deposit_asset(what, who) { - Err(XcmError::AssetNotFound | XcmError::Unimplemented) => (), + Err(XcmError::AssetNotFound) | Err(XcmError::Unimplemented) => (), r => return r, } )* ); @@ -147,7 +147,7 @@ impl TransactAsset for Tuple { fn withdraw_asset(what: &MultiAsset, who: &MultiLocation) -> Result<Assets, XcmError> { for_tuples!( #( match Tuple::withdraw_asset(what, who) { - Err(XcmError::AssetNotFound | XcmError::Unimplemented) => (), + Err(XcmError::AssetNotFound) | Err(XcmError::Unimplemented) => (), r => return r, } )* ); @@ -163,7 +163,7 @@ impl TransactAsset for Tuple { fn transfer_asset(what: &MultiAsset, from: &MultiLocation, to: &MultiLocation) -> Result<Assets, XcmError> { for_tuples!( #( match Tuple::transfer_asset(what, from, to) { - Err(XcmError::AssetNotFound | XcmError::Unimplemented) => (), + Err(XcmError::AssetNotFound) | Err(XcmError::Unimplemented) => (), r => return r, } )* ); diff --git a/xcm/xcm-executor/src/traits/weight.rs b/xcm/xcm-executor/src/traits/weight.rs index dc9589803af5..1844f3b6c7f2 100644 --- a/xcm/xcm-executor/src/traits/weight.rs +++ b/xcm/xcm-executor/src/traits/weight.rs @@ -71,7 +71,7 @@ pub trait WeightTrader: Sized { /// purchased using `buy_weight`. /// /// Default implementation refunds nothing. - fn refund_weight(&mut self, _weight: Weight) -> MultiAsset { MultiAsset::None } + fn refund_weight(&mut self, _weight: Weight) -> Option<MultiAsset> { None } } impl WeightTrader for () { From 8017453bf8ae1edb0c9a3b77c49d04187c079afe Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Sat, 31 Jul 2021 11:39:28 +0200 Subject: [PATCH 012/166] XCM Builder builds --- xcm/src/v0/multiasset.rs | 42 +++++++++++++------- xcm/xcm-builder/src/filter_asset_location.rs | 4 +- xcm/xcm-builder/src/fungibles_adapter.rs | 13 +++--- xcm/xcm-builder/src/matches_fungible.rs | 10 ++--- xcm/xcm-builder/src/weight.rs | 21 +++++----- xcm/xcm-executor/src/assets.rs | 10 +++++ 6 files changed, 61 insertions(+), 39 deletions(-) diff --git a/xcm/src/v0/multiasset.rs b/xcm/src/v0/multiasset.rs index 3d0ee0d2d00e..c877f71a0dc6 100644 --- a/xcm/src/v0/multiasset.rs +++ b/xcm/src/v0/multiasset.rs @@ -64,6 +64,18 @@ pub enum AssetId { Abstract(Vec<u8>), } +impl From<MultiLocation> for AssetId { + fn from(x: MultiLocation) -> Self { + Self::Concrete(x) + } +} + +impl From<Vec<u8>> for AssetId { + fn from(x: Vec<u8>) -> Self { + Self::Abstract(x) + } +} + impl AssetId { /// Prepend a `MultiLocation` to a concrete asset, giving it a new root location. pub fn reanchor(&mut self, prepend: &MultiLocation) -> Result<(), ()> { @@ -137,21 +149,9 @@ impl Ord for MultiAsset { } } -impl From<(AssetId, Fungibility)> for MultiAsset { - fn from((id, fun): (AssetId, Fungibility)) -> MultiAsset { - MultiAsset { fun, id } - } -} - -impl From<(AssetId, u128)> for MultiAsset { - fn from((id, amount): (AssetId, u128)) -> MultiAsset { - MultiAsset { fun: amount.into(), id } - } -} - -impl From<(AssetId, AssetInstance)> for MultiAsset { - fn from((id, instance): (AssetId, AssetInstance)) -> MultiAsset { - MultiAsset { fun: instance.into(), id } +impl<A: Into<AssetId>, B: Into<Fungibility>> From<(A, B)> for MultiAsset { + fn from((id, fun): (A, B)) -> MultiAsset { + MultiAsset { fun: fun.into(), id: id.into() } } } @@ -409,6 +409,18 @@ impl From<WildMultiAsset> for MultiAssetFilter { } } +impl From<MultiAsset> for MultiAssetFilter { + fn from(x: MultiAsset) -> Self { + Self::Assets(vec![x].into()) + } +} + +impl From<MultiAssets> for MultiAssetFilter { + fn from(x: MultiAssets) -> Self { + Self::Assets(x) + } +} + impl From<MultiAssetFilter> for Vec<OldMultiAsset> { fn from(a: MultiAssetFilter) -> Self { use MultiAssetFilter::*; diff --git a/xcm/xcm-builder/src/filter_asset_location.rs b/xcm/xcm-builder/src/filter_asset_location.rs index 9ad4f40aa71c..e095b9dbbc73 100644 --- a/xcm/xcm-builder/src/filter_asset_location.rs +++ b/xcm/xcm-builder/src/filter_asset_location.rs @@ -17,7 +17,7 @@ //! Various implementations of `FilterAssetLocation`. use sp_std::marker::PhantomData; -use xcm::v0::{MultiAsset, MultiLocation}; +use xcm::v0::{MultiAsset, MultiLocation, AssetId::Concrete}; use frame_support::traits::Get; use xcm_executor::traits::FilterAssetLocation; @@ -25,7 +25,7 @@ use xcm_executor::traits::FilterAssetLocation; pub struct NativeAsset; impl FilterAssetLocation for NativeAsset { fn filter_asset_location(asset: &MultiAsset, origin: &MultiLocation) -> bool { - matches!(asset, MultiAsset::ConcreteFungible { ref id, .. } if id == origin) + matches!(asset.id, Concrete(ref id) if id == origin) } } diff --git a/xcm/xcm-builder/src/fungibles_adapter.rs b/xcm/xcm-builder/src/fungibles_adapter.rs index 80cd74c0124d..121d0828f165 100644 --- a/xcm/xcm-builder/src/fungibles_adapter.rs +++ b/xcm/xcm-builder/src/fungibles_adapter.rs @@ -17,7 +17,10 @@ //! Adapters to work with `frame_support::traits::tokens::fungibles` through XCM. use sp_std::{prelude::*, result, marker::PhantomData, borrow::Borrow}; -use xcm::v0::{Error as XcmError, Result, MultiAsset, MultiLocation, Junction}; +use xcm::v0::{ + Error as XcmError, Result, MultiAsset, MultiLocation, Junction, Fungibility::Fungible, + AssetId::{Concrete, Abstract}, +}; use frame_support::traits::{Get, tokens::fungibles, Contains}; use xcm_executor::traits::{TransactAsset, Convert, MatchesFungibles, Error as MatchError}; @@ -61,8 +64,8 @@ impl< ConvertedConcreteAssetId<AssetId, Balance, ConvertAssetId, ConvertBalance> { fn matches_fungibles(a: &MultiAsset) -> result::Result<(AssetId, Balance), MatchError> { - let (id, amount) = match a { - MultiAsset::ConcreteFungible { id, amount } => (id, amount), + let (amount, id) = match (&a.fun, &a.id) { + (Fungible(ref amount), Concrete(ref id)) => (amount, id), _ => return Err(MatchError::AssetNotFound), }; let what = ConvertAssetId::convert_ref(id).map_err(|_| MatchError::AssetIdConversionFailed)?; @@ -83,8 +86,8 @@ impl< ConvertedAbstractAssetId<AssetId, Balance, ConvertAssetId, ConvertBalance> { fn matches_fungibles(a: &MultiAsset) -> result::Result<(AssetId, Balance), MatchError> { - let (id, amount) = match a { - MultiAsset::AbstractFungible { id, amount } => (id, amount), + let (amount, id) = match (&a.fun, &a.id) { + (Fungible(ref amount), Abstract(ref id)) => (amount, id), _ => return Err(MatchError::AssetNotFound), }; let what = ConvertAssetId::convert_ref(id).map_err(|_| MatchError::AssetIdConversionFailed)?; diff --git a/xcm/xcm-builder/src/matches_fungible.rs b/xcm/xcm-builder/src/matches_fungible.rs index 4d76a49b6bd8..8ec1893ee9df 100644 --- a/xcm/xcm-builder/src/matches_fungible.rs +++ b/xcm/xcm-builder/src/matches_fungible.rs @@ -18,7 +18,7 @@ use sp_std::{marker::PhantomData, convert::TryFrom}; use sp_runtime::traits::CheckedConversion; -use xcm::v0::{MultiAsset, MultiLocation}; +use xcm::v0::{MultiAsset, MultiLocation, AssetId::{Abstract, Concrete}, Fungibility::Fungible}; use frame_support::traits::Get; use xcm_executor::traits::MatchesFungible; @@ -46,8 +46,8 @@ use xcm_executor::traits::MatchesFungible; pub struct IsConcrete<T>(PhantomData<T>); impl<T: Get<MultiLocation>, B: TryFrom<u128>> MatchesFungible<B> for IsConcrete<T> { fn matches_fungible(a: &MultiAsset) -> Option<B> { - match a { - MultiAsset::ConcreteFungible { id, amount } if id == &T::get() => + match (&a.id, &a.fun) { + (Concrete(ref id), Fungible(ref amount)) if id == &T::get() => CheckedConversion::checked_from(*amount), _ => None, } @@ -76,8 +76,8 @@ impl<T: Get<MultiLocation>, B: TryFrom<u128>> MatchesFungible<B> for IsConcrete< pub struct IsAbstract<T>(PhantomData<T>); impl<T: Get<&'static [u8]>, B: TryFrom<u128>> MatchesFungible<B> for IsAbstract<T> { fn matches_fungible(a: &MultiAsset) -> Option<B> { - match a { - MultiAsset::AbstractFungible { id, amount } if &id[..] == T::get() => + match (&a.id, &a.fun) { + (Abstract(ref id), Fungible(ref amount)) if id == &T::get() => CheckedConversion::checked_from(*amount), _ => None, } diff --git a/xcm/xcm-builder/src/weight.rs b/xcm/xcm-builder/src/weight.rs index 26f282abfec7..77f28c73f571 100644 --- a/xcm/xcm-builder/src/weight.rs +++ b/xcm/xcm-builder/src/weight.rs @@ -16,7 +16,7 @@ use sp_std::{result::Result, marker::PhantomData, convert::TryInto}; use parity_scale_codec::Decode; -use xcm::v0::{Xcm, Order, MultiAsset, MultiLocation, Error}; +use xcm::v0::{Xcm, Order, MultiAsset, MultiLocation, Error, AssetId::Concrete}; use sp_runtime::traits::{Zero, Saturating, SaturatedConversion}; use frame_support::traits::{Get, OnUnbalanced as OnUnbalancedT, tokens::currency::Currency as CurrencyT}; use frame_support::weights::{Weight, GetDispatchInfo, WeightToFeePolynomial}; @@ -103,8 +103,7 @@ impl<T: Get<(MultiLocation, u128)>, R: TakeRevenue> WeightTrader for FixedRateOf let (id, units_per_second) = T::get(); use frame_support::weights::constants::WEIGHT_PER_SECOND; let amount = units_per_second * (weight as u128) / (WEIGHT_PER_SECOND as u128); - let required = MultiAsset::ConcreteFungible { amount, id }; - let (unused, _) = payment.less(required).map_err(|_| Error::TooExpensive)?; + let unused = payment.checked_sub((id, amount).into()).map_err(|_| Error::TooExpensive)?; self.0 = self.0.saturating_add(weight); self.1 = self.1.saturating_add(amount); Ok(unused) @@ -116,14 +115,13 @@ impl<T: Get<(MultiLocation, u128)>, R: TakeRevenue> WeightTrader for FixedRateOf let amount = units_per_second * (weight as u128) / 1_000_000_000_000u128; self.0 -= weight; self.1 = self.1.saturating_sub(amount); - Some((id, amount).into()) + Some((Concrete(id), amount).into()) } } impl<T: Get<(MultiLocation, u128)>, R: TakeRevenue> Drop for FixedRateOfConcreteFungible<T, R> { fn drop(&mut self) { - let revenue = MultiAsset::ConcreteFungible { amount: self.1, id: T::get().0 }; - R::take_revenue(revenue); + R::take_revenue((Concrete(T::get().0), self.1).into()); } } @@ -147,11 +145,9 @@ impl< fn buy_weight(&mut self, weight: Weight, payment: Assets) -> Result<Assets, Error> { let amount = WeightToFee::calc(&weight); - let required = MultiAsset::ConcreteFungible { - amount: amount.try_into().map_err(|_| Error::Overflow)?, - id: AssetId::get(), - }; - let (unused, _) = payment.less(required).map_err(|_| Error::TooExpensive)?; + let u128_amount: u128 = amount.try_into().map_err(|_| Error::Overflow)?; + let required = (Concrete(AssetId::get()), u128_amount).into(); + let unused = payment.checked_sub(required).map_err(|_| Error::TooExpensive)?; self.0 = self.0.saturating_add(weight); self.1 = self.1.saturating_add(amount); Ok(unused) @@ -162,7 +158,8 @@ impl< let amount = WeightToFee::calc(&weight); self.0 -= weight; self.1 = self.1.saturating_sub(amount); - Some(MultiAsset::from((AssetId::get(), amount.saturated_into()))) + let amount: u128 = amount.saturated_into(); + Some((AssetId::get(), amount).into()) } } diff --git a/xcm/xcm-executor/src/assets.rs b/xcm/xcm-executor/src/assets.rs index 7c2b5410991c..b25b0b3e4637 100644 --- a/xcm/xcm-executor/src/assets.rs +++ b/xcm/xcm-executor/src/assets.rs @@ -253,6 +253,16 @@ impl Assets { self.general_take(mask, false) } + /// Consumes `self` and returns its original value excluding `asset` iff it contains at least `asset`. + pub fn checked_sub(mut self, asset: MultiAsset) -> Result<Assets, Self> { + // TODO: Optimize by doing this operation directly rather than converting into a MultiAssetFilter and + // constructing the unused `_taken` return value. + match self.try_take(asset.into()) { + Ok(_taken) => Ok(self), + Err(_) => Err(self), + } + } + /// Consumes `self` and returns its original value excluding `mask` iff it contains at least `mask`, as well as /// the assets excluded. pub fn less(mut self, mask: MultiAssetFilter) -> Result<(Assets, Assets), Self> { From 72c25814614b865b502681e2e7ab77c5df65bdd9 Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Sat, 31 Jul 2021 04:13:15 -0700 Subject: [PATCH 013/166] Fix xcm-builder tests and compilation --- xcm/xcm-builder/src/barriers.rs | 8 +- xcm/xcm-builder/src/currency_adapter.rs | 4 +- xcm/xcm-builder/src/fungibles_adapter.rs | 12 +- xcm/xcm-builder/src/location_conversion.rs | 111 +++++++++------- xcm/xcm-builder/src/matches_fungible.rs | 6 +- xcm/xcm-builder/src/mock.rs | 34 ++--- xcm/xcm-builder/src/origin_conversion.rs | 74 ++++++----- xcm/xcm-builder/src/tests.rs | 144 +++++++++++---------- 8 files changed, 214 insertions(+), 179 deletions(-) diff --git a/xcm/xcm-builder/src/barriers.rs b/xcm/xcm-builder/src/barriers.rs index ea3d80660940..2d9db1e916f4 100644 --- a/xcm/xcm-builder/src/barriers.rs +++ b/xcm/xcm-builder/src/barriers.rs @@ -17,7 +17,7 @@ //! Various implementations for `ShouldExecute`. use sp_std::{result::Result, marker::PhantomData}; -use xcm::v0::{Xcm, Order, MultiLocation, Junction}; +use xcm::v0::{Xcm, Order, MultiLocation, Junction, Junctions}; use frame_support::{ensure, traits::Contains, weights::Weight}; use xcm_executor::traits::{OnResponse, ShouldExecute}; use polkadot_parachain::primitives::IsSystem; @@ -86,7 +86,11 @@ impl< ParaId: IsSystem + From<u32>, > Contains<MultiLocation> for IsChildSystemParachain<ParaId> { fn contains(l: &MultiLocation) -> bool { - matches!(l, MultiLocation::X1(Junction::Parachain(id)) if ParaId::from(*id).is_system()) + matches!( + l.junctions(), + 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 744835f08959..22a1c4c02a4d 100644 --- a/xcm/xcm-builder/src/currency_adapter.rs +++ b/xcm/xcm-builder/src/currency_adapter.rs @@ -50,7 +50,7 @@ impl From<Error> for XcmError { /// # Example /// ``` /// use frame_support::parameter_types; -/// use xcm::v0::{MultiLocation, Junction}; +/// use xcm::v0::{MultiLocation, Junction, Junctions::*}; /// use xcm_builder::{ParentIsDefault, CurrencyAdapter, IsConcrete}; /// /// /// Our chain's account id. @@ -58,7 +58,7 @@ impl From<Error> for XcmError { /// /// /// Our relay chain's location. /// parameter_types! { -/// RelayChain: MultiLocation = MultiLocation::X1(Junction::Parent); +/// RelayChain: MultiLocation = MultiLocation::new(1, Null).unwrap(); /// CheckingAccount: AccountId = Default::default(); /// } /// diff --git a/xcm/xcm-builder/src/fungibles_adapter.rs b/xcm/xcm-builder/src/fungibles_adapter.rs index 80cd74c0124d..c39b4aa4eae1 100644 --- a/xcm/xcm-builder/src/fungibles_adapter.rs +++ b/xcm/xcm-builder/src/fungibles_adapter.rs @@ -33,10 +33,16 @@ impl< fn convert_ref(id: impl Borrow<MultiLocation>) -> result::Result<AssetId, ()> { 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 + .junctions() + .iter() + .enumerate() + .any(|(index, junction)| id.junctions().at(index) != Some(junction)) + { return Err(()) } - match id.at(prefix.len()) { + match id.junctions().at(prefix.junctions().len()) { Some(Junction::GeneralIndex { id }) => ConvertAssetId::convert_ref(id), _ => Err(()), } @@ -44,7 +50,7 @@ impl< fn reverse_ref(what: impl Borrow<AssetId>) -> result::Result<MultiLocation, ()> { let mut location = Prefix::get(); let id = ConvertAssetId::reverse_ref(what)?; - location.push(Junction::GeneralIndex { id }).map_err(|_| ())?; + location.push_non_parent(Junction::GeneralIndex { id })?; Ok(location) } } diff --git a/xcm/xcm-builder/src/location_conversion.rs b/xcm/xcm-builder/src/location_conversion.rs index cdf0a2bf5171..7c6e9743fbcc 100644 --- a/xcm/xcm-builder/src/location_conversion.rs +++ b/xcm/xcm-builder/src/location_conversion.rs @@ -19,7 +19,7 @@ use sp_io::hashing::blake2_256; use sp_runtime::traits::AccountIdConversion; use frame_support::traits::Get; use parity_scale_codec::Encode; -use xcm::v0::{MultiLocation, NetworkId, Junction}; +use xcm::v0::{Junctions, Junction, MultiLocation, NetworkId}; use xcm_executor::traits::{InvertLocation, Convert}; pub struct Account32Hash<Network, AccountId>(PhantomData<(Network, AccountId)>); @@ -43,7 +43,7 @@ impl< AccountId: Default + Eq + Clone, > Convert<MultiLocation, AccountId> for ParentIsDefault<AccountId> { fn convert_ref(location: impl Borrow<MultiLocation>) -> Result<AccountId, ()> { - if let &MultiLocation::X1(Junction::Parent) = location.borrow() { + if location.borrow().parent_count() == 1 { Ok(AccountId::default()) } else { Err(()) @@ -52,7 +52,7 @@ impl< fn reverse_ref(who: impl Borrow<AccountId>) -> Result<MultiLocation, ()> { if who.borrow() == &AccountId::default() { - Ok(Junction::Parent.into()) + Ok(MultiLocation::new(1, Junctions::Null).expect("well-formed MultiLocation; qed")) } else { Err(()) } @@ -65,10 +65,12 @@ impl< AccountId: Clone, > Convert<MultiLocation, AccountId> for ChildParachainConvertsVia<ParaId, AccountId> { fn convert_ref(location: impl Borrow<MultiLocation>) -> Result<AccountId, ()> { - if let &MultiLocation::X1(Junction::Parachain(id)) = location.borrow() { - Ok(ParaId::from(id).into_account()) - } else { - Err(()) + let location = location.borrow(); + match location.junctions() { + Junctions::X1(Junction::Parachain(id)) if location.parent_count() == 0 => { + Ok(ParaId::from(*id).into_account()) + }, + _ => Err(()), } } @@ -87,16 +89,22 @@ impl< AccountId: Clone, > Convert<MultiLocation, AccountId> for SiblingParachainConvertsVia<ParaId, AccountId> { fn convert_ref(location: impl Borrow<MultiLocation>) -> Result<AccountId, ()> { - if let &MultiLocation::X2(Junction::Parent, Junction::Parachain(id)) = location.borrow() { - Ok(ParaId::from(id).into_account()) - } else { - Err(()) + let location = location.borrow(); + match location.junctions() { + Junctions::X1(Junction::Parachain(id)) if location.parent_count() == 1 => { + Ok(ParaId::from(*id).into_account()) + }, + _ => Err(()), } } fn reverse_ref(who: impl Borrow<AccountId>) -> Result<MultiLocation, ()> { if let Some(id) = ParaId::try_from_account(who.borrow()) { - Ok([Junction::Parent, Junction::Parachain(id.into())].into()) + Ok(MultiLocation::new( + 1, + Junctions::X1(Junction::Parachain(id.into()))) + .expect("well-formed MultiLocation; qed"), + ) } else { Err(()) } @@ -110,10 +118,14 @@ impl< AccountId: From<[u8; 32]> + Into<[u8; 32]> + Clone, > Convert<MultiLocation, AccountId> for AccountId32Aliases<Network, AccountId> { fn convert(location: MultiLocation) -> Result<AccountId, MultiLocation> { - let id = match location { - MultiLocation::X1(Junction::AccountId32 { id, network: NetworkId::Any }) => id, - MultiLocation::X1(Junction::AccountId32 { id, network }) if &network == &Network::get() => id, - l => return Err(l), + let id = match location.junctions() { + Junctions::X1(Junction::AccountId32 { id, network: NetworkId::Any }) + if location.parent_count() == 0 + => *id, + Junctions::X1(Junction::AccountId32 { id, network }) + if network == &Network::get() && location.parent_count() == 0 + => *id, + _ => return Err(location), }; Ok(id.into()) } @@ -129,10 +141,14 @@ impl< AccountId: From<[u8; 20]> + Into<[u8; 20]> + Clone, > Convert<MultiLocation, AccountId> for AccountKey20Aliases<Network, AccountId> { fn convert(location: MultiLocation) -> Result<AccountId, MultiLocation> { - let key = match location { - MultiLocation::X1(Junction::AccountKey20 { key, network: NetworkId::Any }) => key, - MultiLocation::X1(Junction::AccountKey20 { key, network }) if &network == &Network::get() => key, - l => return Err(l), + let key = match location.junctions() { + Junctions::X1(Junction::AccountKey20 { key, network: NetworkId::Any }) + if location.parent_count() == 0 + => *key, + Junctions::X1(Junction::AccountKey20 { key, network }) + if network == &Network::get() && location.parent_count() == 0 + => *key, + _ => return Err(location), }; Ok(key.into()) } @@ -156,7 +172,7 @@ impl< /// ``` /// ```rust /// # use frame_support::parameter_types; -/// # use xcm::v0::{MultiLocation::{self, *}, Junction::*, NetworkId::Any}; +/// # use xcm::v0::{MultiLocation, Junction::*, Junctions::{self, *}, NetworkId::Any}; /// # use xcm_builder::LocationInverter; /// # use xcm_executor::traits::InvertLocation; /// # fn main() { @@ -164,34 +180,31 @@ impl< /// 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() })).unwrap(); /// let inverted = LocationInverter::<Ancestry>::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() }), +/// ).unwrap()); /// # } /// ``` pub struct LocationInverter<Ancestry>(PhantomData<Ancestry>); impl<Ancestry: Get<MultiLocation>> InvertLocation for LocationInverter<Ancestry> { 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 = Junctions::Null; + for _ in 0..location.parent_count() { + junctions = junctions.pushed_with( + ancestry.take_first_non_parent().unwrap_or(Junction::OnlyChild), + ) + .expect("ancestry is well-formed and has less than 8 non-parent junctions; qed"); } - result + let parents = location.junctions().len() as u8; + MultiLocation::new(parents, junctions) + .expect("parents + junctions len must equal location len; qed") } } @@ -200,7 +213,7 @@ mod tests { use super::*; use frame_support::parameter_types; - use xcm::v0::{MultiLocation::*, Junction::*, NetworkId::Any}; + use xcm::v0::{MultiLocation, Junction::*, Junctions::*, NetworkId::Any}; fn account20() -> Junction { AccountKey20 { network: Any, key: Default::default() } @@ -225,12 +238,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())).unwrap(); let inverted = LocationInverter::<Ancestry>::invert_location(&input); - assert_eq!(inverted, X5(Parent, Parent, Parachain(1), account20(), account20())); + assert_eq!(inverted, MultiLocation::new(2, X3(Parachain(1), account20(), account20())).unwrap()); } // Network Topology @@ -240,12 +253,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::new(2, Null).unwrap(); let inverted = LocationInverter::<Ancestry>::invert_location(&input); - assert_eq!(inverted, X2(account20(), account20())); + assert_eq!(inverted, X2(account20(), account20()).into()); } // Network Topology @@ -255,11 +268,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::new(2, Null).unwrap(); let inverted = LocationInverter::<Ancestry>::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 4d76a49b6bd8..b95725e6ceb0 100644 --- a/xcm/xcm-builder/src/matches_fungible.rs +++ b/xcm/xcm-builder/src/matches_fungible.rs @@ -28,16 +28,16 @@ use xcm_executor::traits::MatchesFungible; /// # Example /// /// ``` -/// use xcm::v0::{MultiAsset, MultiLocation, Junction}; +/// use xcm::v0::{MultiAsset, MultiLocation, Junction, Junctions::*}; /// use xcm_builder::IsConcrete; /// use xcm_executor::traits::MatchesFungible; /// /// frame_support::parameter_types! { -/// pub TargetLocation: MultiLocation = MultiLocation::X1(Junction::Parent); +/// pub TargetLocation: MultiLocation = MultiLocation::new(1, Null).unwrap(); /// } /// /// # fn main() { -/// let id = MultiLocation::X1(Junction::Parent); +/// let id = MultiLocation::new(1, Null).unwrap(); /// let asset = MultiAsset::ConcreteFungible { id, amount: 999u128 }; /// // match `asset` if it is a concrete asset in `TargetLocation`. /// assert_eq!(<IsConcrete<TargetLocation> as MatchesFungible<u128>>::matches_fungible(&asset), Some(999)); diff --git a/xcm/xcm-builder/src/mock.rs b/xcm/xcm-builder/src/mock.rs index 56d7d753e49e..efe4f49ee5ce 100644 --- a/xcm/xcm-builder/src/mock.rs +++ b/xcm/xcm-builder/src/mock.rs @@ -18,8 +18,8 @@ pub use sp_std::{fmt::Debug, marker::PhantomData, cell::RefCell}; pub use sp_std::collections::{btree_map::BTreeMap, btree_set::BTreeSet}; pub use parity_scale_codec::{Encode, Decode}; pub use xcm::v0::{ - SendXcm, MultiLocation::*, Junction::*, MultiAsset, Xcm, Order, Result as XcmResult, Error as XcmError, - OriginKind, MultiLocation, Junction, opaque, + SendXcm, Junction::*, Junctions::*, MultiAsset, Xcm, Order, Result as XcmResult, Error as XcmError, + OriginKind, MultiLocation, Junction, Junctions, opaque, }; pub use frame_support::{ ensure, parameter_types, @@ -147,18 +147,18 @@ impl TransactAsset for TestAssetTransactor { pub fn to_account(l: MultiLocation) -> Result<u64, MultiLocation> { - Ok(match l { + Ok(match l.junctions() { // Siblings at 2000+id - X2(Parent, Parachain(id)) => 2000 + id as u64, + X1(Parachain(id)) if l.parent_count() == 1 => 2000 + *id as u64, // Accounts are their number - X1(AccountIndex64 { index, .. }) => index, + X1(AccountIndex64 { index, .. }) if l.parent_count() == 0 => *index, // Children at 1000+id - X1(Parachain(id)) => 1000 + id as u64, + X1(Parachain(id)) if l.parent_count() == 0 => 1000 + *id as u64, // Self at 3000 - Null => 3000, + Null if l.parent_count() == 0 => 3000, // Parent at 3001 - X1(Parent) => 3001, - l => return Err(l), + Null if l.parent_count() == 1 => 3001, + _ => return Err(l), }) } @@ -166,13 +166,13 @@ pub struct TestOriginConverter; impl ConvertOrigin<TestOrigin> for TestOriginConverter { fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result<TestOrigin, MultiLocation> { use OriginKind::*; - match (kind, origin) { + match (kind, origin.junctions()) { (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)), - (_, origin) => Err(origin), + (SovereignAccount, _) => Ok(TestOrigin::Signed(to_account(origin)?)), + (Native, X1(Parachain(id))) if origin.parent_count() == 0 => Ok(TestOrigin::Parachain(*id)), + (Native, Null) if origin.parent_count() == 1 => Ok(TestOrigin::Relay), + (Native, X1(AccountIndex64 {index, ..})) if origin.parent_count() == 0 => Ok(TestOrigin::Signed(*index)), + _ => Err(origin), } } } @@ -248,7 +248,7 @@ pub fn response(query_id: u64) -> Option<Response> { } parameter_types! { - pub TestAncestry: MultiLocation = X1(Parachain(42)); + pub TestAncestry: MultiLocation = X1(Parachain(42)).into(); pub UnitWeightCost: Weight = 10; } parameter_types! { @@ -256,7 +256,7 @@ parameter_types! { pub static AllowUnpaidFrom: Vec<MultiLocation> = vec![]; pub static AllowPaidFrom: Vec<MultiLocation> = vec![]; // 1_000_000_000_000 => 1 unit of asset for 1 unit of Weight. - pub static WeightPrice: (MultiLocation, u128) = (Null, 1_000_000_000_000); + pub static WeightPrice: (MultiLocation, u128) = (Null.into(), 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 79dbf957240c..e675a48274ba 100644 --- a/xcm/xcm-builder/src/origin_conversion.rs +++ b/xcm/xcm-builder/src/origin_conversion.rs @@ -17,7 +17,7 @@ //! Various implementations for `ConvertOrigin`. use sp_std::{marker::PhantomData, convert::TryInto}; -use xcm::v0::{MultiLocation, OriginKind, NetworkId, Junction, BodyId, BodyPart}; +use xcm::v0::{MultiLocation, OriginKind, NetworkId, Junction, Junctions, BodyId, BodyPart}; use xcm_executor::traits::{Convert, ConvertOrigin}; use frame_support::traits::{EnsureOrigin, Get, OriginTrait, GetBacking}; use frame_system::RawOrigin as SystemRawOrigin; @@ -46,10 +46,10 @@ impl< Origin: OriginTrait, > ConvertOrigin<Origin> for ParentAsSuperuser<Origin> { fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result<Origin, MultiLocation> { - match (kind, origin) { - (OriginKind::Superuser, MultiLocation::X1(Junction::Parent)) => - Ok(Origin::root()), - (_, origin) => Err(origin), + if kind == OriginKind::Superuser && origin.parent_count() == 1 { + Ok(Origin::root()) + } else { + Err(origin) } } } @@ -60,11 +60,11 @@ impl< Origin: OriginTrait, > ConvertOrigin<Origin> for ChildSystemParachainAsSuperuser<ParaId, Origin> { fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result<Origin, MultiLocation> { - match (kind, origin) { - (OriginKind::Superuser, MultiLocation::X1(Junction::Parachain(id))) - if ParaId::from(id).is_system() => + match (kind, origin.junctions()) { + (OriginKind::Superuser, Junctions::X1(Junction::Parachain(id))) + if ParaId::from(*id).is_system() && origin.parent_count() == 0 => Ok(Origin::root()), - (_, origin) => Err(origin), + _ => Err(origin), } } } @@ -75,11 +75,11 @@ impl< Origin: OriginTrait > ConvertOrigin<Origin> for SiblingSystemParachainAsSuperuser<ParaId, Origin> { fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result<Origin, MultiLocation> { - match (kind, origin) { - (OriginKind::Superuser, MultiLocation::X2(Junction::Parent, Junction::Parachain(id))) - if ParaId::from(id).is_system() => + match (kind, origin.junctions()) { + (OriginKind::Superuser, Junctions::X1(Junction::Parachain(id))) + if ParaId::from(*id).is_system() && origin.parent_count() == 1 => Ok(Origin::root()), - (_, origin) => Err(origin), + _ => Err(origin), } } } @@ -92,10 +92,10 @@ impl< Origin: From<ParachainOrigin>, > ConvertOrigin<Origin> for ChildParachainAsNative<ParachainOrigin, Origin> { fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result<Origin, MultiLocation> { - match (kind, origin) { - (OriginKind::Native, MultiLocation::X1(Junction::Parachain(id))) - => Ok(Origin::from(ParachainOrigin::from(id))), - (_, origin) => Err(origin), + match (kind, origin.junctions()) { + (OriginKind::Native, Junctions::X1(Junction::Parachain(id))) + => Ok(Origin::from(ParachainOrigin::from(*id))), + _ => Err(origin), } } } @@ -108,10 +108,11 @@ impl< Origin: From<ParachainOrigin>, > ConvertOrigin<Origin> for SiblingParachainAsNative<ParachainOrigin, Origin> { fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result<Origin, MultiLocation> { - match (kind, origin) { - (OriginKind::Native, MultiLocation::X2(Junction::Parent, Junction::Parachain(id))) - => Ok(Origin::from(ParachainOrigin::from(id))), - (_, origin) => Err(origin), + match (kind, origin.junctions()) { + (OriginKind::Native, Junctions::X1(Junction::Parachain(id))) + if origin.parent_count() == 1 => + Ok(Origin::from(ParachainOrigin::from(*id))), + _ => Err(origin), } } } @@ -125,9 +126,10 @@ impl< Origin, > ConvertOrigin<Origin> for RelayChainAsNative<RelayOrigin, Origin> { fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result<Origin, MultiLocation> { - match (kind, origin) { - (OriginKind::Native, MultiLocation::X1(Junction::Parent)) => Ok(RelayOrigin::get()), - (_, origin) => Err(origin), + if kind == OriginKind::Native && origin.parent_count() == 1 { + Ok(RelayOrigin::get()) + } else { + Err(origin) } } } @@ -142,11 +144,12 @@ impl< Origin::AccountId: From<[u8; 32]>, { fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result<Origin, MultiLocation> { - match (kind, origin) { - (OriginKind::Native, MultiLocation::X1(Junction::AccountId32 { id, network })) - if matches!(network, NetworkId::Any) || network == Network::get() - => Ok(Origin::signed(id.into())), - (_, origin) => Err(origin), + match (kind, origin.junctions()) { + (OriginKind::Native, Junctions::X1(Junction::AccountId32 { id, network })) + if (matches!(network, NetworkId::Any) || network == &Network::get()) + && origin.parent_count() == 0 + => Ok(Origin::signed((*id).into())), + _ => Err(origin), } } } @@ -161,13 +164,14 @@ impl< Origin::AccountId: From<[u8; 20]>, { fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result<Origin, MultiLocation> { - match (kind, origin) { - (OriginKind::Native, MultiLocation::X1(Junction::AccountKey20 { key, network })) - if matches!(network, NetworkId::Any) || network == Network::get() => + match (kind, origin.junctions()) { + (OriginKind::Native, Junctions::X1(Junction::AccountKey20 { key, network })) + if (matches!(network, NetworkId::Any) || network == &Network::get()) + && origin.parent_count() == 0 => { - Ok(Origin::signed(key.into())) + Ok(Origin::signed((*key).into())) } - (_, origin) => Err(origin), + _ => Err(origin), } } } @@ -189,7 +193,7 @@ impl< // 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::Null) + Ok(MultiLocation::default()) } else { Err(o) } diff --git a/xcm/xcm-builder/src/tests.rs b/xcm/xcm-builder/src/tests.rs index 0f04b89285d1..073d580491ce 100644 --- a/xcm/xcm-builder/src/tests.rs +++ b/xcm/xcm-builder/src/tests.rs @@ -22,28 +22,31 @@ use xcm_executor::{XcmExecutor, Config, traits::*}; #[test] fn basic_setup_works() { - add_reserve(X1(Parent), AllConcreteFungible { id: X1(Parent) }); + add_reserve( + MultiLocation::new(1, Null).unwrap(), + AllConcreteFungible { id: MultiLocation::new(1, Null).unwrap() }, + ); assert!(<TestConfig as Config>::IsReserve::filter_asset_location( - &ConcreteFungible { id: X1(Parent), amount: 100 }, - &X1(Parent), + &ConcreteFungible { id: MultiLocation::new(1, Null).unwrap(), amount: 100 }, + &MultiLocation::new(1, Null).unwrap(), )); - 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(Null), 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))).unwrap()), Ok(2001)); + assert_eq!(to_account(MultiLocation::new(1, X1(Parachain(50))).unwrap()), Ok(2050)); + assert_eq!(to_account(X1(AccountIndex64{index:1, network:Any}).into()), Ok(1)); + assert_eq!(to_account(X1(AccountIndex64{index:42, network:Any}).into()), Ok(42)); + assert_eq!(to_account(Null.into()), Ok(3000)); } #[test] fn weigher_should_work() { let mut message = opaque::Xcm::ReserveAssetDeposit { - assets: vec![ConcreteFungible { id: X1(Parent), amount: 100 }], + assets: vec![ConcreteFungible { id: MultiLocation::new(1, Null).unwrap(), amount: 100 }], effects: vec![ Order::BuyExecution { fees: All, weight: 0, debt: 30, halt_on_error: true, xcm: vec![] }, - Order::DepositAsset { assets: vec![All], dest: Null }, + Order::DepositAsset { assets: vec![All], dest: Null.into() }, ], }.into(); assert_eq!(<TestConfig as Config>::Weigher::shallow(&mut message), Ok(30)); @@ -52,13 +55,13 @@ fn weigher_should_work() { #[test] fn take_weight_credit_barrier_should_work() { let mut message = opaque::Xcm::TransferAsset { - assets: vec![ConcreteFungible { id: X1(Parent), amount: 100 }], - dest: Null, + assets: vec![ConcreteFungible { id: MultiLocation::new(1, Null).unwrap(), amount: 100 }], + dest: Null.into(), }; let mut weight_credit = 10; let r = TakeWeightCredit::should_execute( - &X1(Parent), + &MultiLocation::new(1, Null).unwrap(), true, &mut message, 10, @@ -68,7 +71,7 @@ fn take_weight_credit_barrier_should_work() { assert_eq!(weight_credit, 0); let r = TakeWeightCredit::should_execute( - &X1(Parent), + &MultiLocation::new(1, Null).unwrap(), true, &mut message, 10, @@ -81,14 +84,14 @@ fn take_weight_credit_barrier_should_work() { #[test] fn allow_unpaid_should_work() { let mut message = opaque::Xcm::TransferAsset { - assets: vec![ConcreteFungible { id: X1(Parent), amount: 100 }], - dest: Null, + assets: vec![ConcreteFungible { id: MultiLocation::new(1, Null).unwrap(), amount: 100 }], + dest: Null.into(), }; - AllowUnpaidFrom::set(vec![ X1(Parent) ]); + AllowUnpaidFrom::set(vec![ MultiLocation::new(1, Null).unwrap() ]); let r = AllowUnpaidExecutionFrom::<IsInVec<AllowUnpaidFrom>>::should_execute( - &X1(Parachain(1)), + &X1(Parachain(1)).into(), true, &mut message, 10, @@ -97,7 +100,7 @@ fn allow_unpaid_should_work() { assert_eq!(r, Err(())); let r = AllowUnpaidExecutionFrom::<IsInVec<AllowUnpaidFrom>>::should_execute( - &X1(Parent), + &MultiLocation::new(1, Null).unwrap(), true, &mut message, 10, @@ -108,15 +111,15 @@ fn allow_unpaid_should_work() { #[test] fn allow_paid_should_work() { - AllowPaidFrom::set(vec![ X1(Parent) ]); + AllowPaidFrom::set(vec![ MultiLocation::new(1, Null).unwrap() ]); let mut message = opaque::Xcm::TransferAsset { - assets: vec![ConcreteFungible { id: X1(Parent), amount: 100 }], - dest: Null, + assets: vec![ConcreteFungible { id: MultiLocation::new(1, Null).unwrap(), amount: 100 }], + dest: Null.into(), }; let r = AllowTopLevelPaidExecutionFrom::<IsInVec<AllowPaidFrom>>::should_execute( - &X1(Parachain(1)), + &X1(Parachain(1)).into(), true, &mut message, 10, @@ -125,15 +128,15 @@ fn allow_paid_should_work() { assert_eq!(r, Err(())); let mut underpaying_message = opaque::Xcm::ReserveAssetDeposit { - assets: vec![ConcreteFungible { id: X1(Parent), amount: 100 }], + assets: vec![ConcreteFungible { id: MultiLocation::new(1, Null).unwrap(), amount: 100 }], effects: vec![ Order::BuyExecution { fees: All, weight: 0, debt: 20, halt_on_error: true, xcm: vec![] }, - Order::DepositAsset { assets: vec![All], dest: Null }, + Order::DepositAsset { assets: vec![All], dest: Null.into() }, ], }; let r = AllowTopLevelPaidExecutionFrom::<IsInVec<AllowPaidFrom>>::should_execute( - &X1(Parent), + &MultiLocation::new(1, Null).unwrap(), true, &mut underpaying_message, 30, @@ -142,15 +145,15 @@ fn allow_paid_should_work() { assert_eq!(r, Err(())); let mut paying_message = opaque::Xcm::ReserveAssetDeposit { - assets: vec![ConcreteFungible { id: X1(Parent), amount: 100 }], + assets: vec![ConcreteFungible { id: MultiLocation::new(1, Null).unwrap(), amount: 100 }], effects: vec![ Order::BuyExecution { fees: All, weight: 0, debt: 30, halt_on_error: true, xcm: vec![] }, - Order::DepositAsset { assets: vec![All], dest: Null }, + Order::DepositAsset { assets: vec![All], dest: Null.into() }, ], }; let r = AllowTopLevelPaidExecutionFrom::<IsInVec<AllowPaidFrom>>::should_execute( - &X1(Parachain(1)), + &X1(Parachain(1)).into(), true, &mut paying_message, 30, @@ -159,7 +162,7 @@ fn allow_paid_should_work() { assert_eq!(r, Err(())); let r = AllowTopLevelPaidExecutionFrom::<IsInVec<AllowPaidFrom>>::should_execute( - &X1(Parent), + &MultiLocation::new(1, Null).unwrap(), true, &mut paying_message, 30, @@ -170,71 +173,74 @@ fn allow_paid_should_work() { #[test] fn paying_reserve_deposit_should_work() { - AllowPaidFrom::set(vec![ X1(Parent) ]); - add_reserve(X1(Parent), AllConcreteFungible { id: X1(Parent) }); - WeightPrice::set((X1(Parent), 1_000_000_000_000)); + AllowPaidFrom::set(vec![ MultiLocation::new(1, Null).unwrap() ]); + add_reserve( + MultiLocation::new(1, Null).unwrap(), + AllConcreteFungible { id: MultiLocation::new(1, Null).unwrap() }, + ); + WeightPrice::set((MultiLocation::new(1, Null).unwrap(), 1_000_000_000_000)); - let origin = X1(Parent); + let origin = MultiLocation::new(1, Null).unwrap(); let message = Xcm::<TestCall>::ReserveAssetDeposit { - assets: vec![ ConcreteFungible { id: X1(Parent), amount: 100 } ], + assets: vec![ ConcreteFungible { id: MultiLocation::new(1, Null).unwrap(), amount: 100 } ], effects: vec![ Order::<TestCall>::BuyExecution { fees: All, weight: 0, debt: 30, halt_on_error: true, xcm: vec![] }, - Order::<TestCall>::DepositAsset { assets: vec![ All ], dest: Null }, + Order::<TestCall>::DepositAsset { assets: vec![ All ], dest: Null.into() }, ], }; let weight_limit = 50; let r = XcmExecutor::<TestConfig>::execute_xcm(origin, message, weight_limit); assert_eq!(r, Outcome::Complete(30)); - assert_eq!(assets(3000), vec![ ConcreteFungible { id: X1(Parent), amount: 70 } ]); + assert_eq!(assets(3000), vec![ ConcreteFungible { id: MultiLocation::new(1, Null).unwrap(), amount: 70 } ]); } #[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, ConcreteFungible { id: Null, amount: 1000 }); + add_asset(1001, ConcreteFungible { id: Null.into(), amount: 1000 }); // They want to transfer 100 of them to their sibling parachain #2 let r = XcmExecutor::<TestConfig>::execute_xcm( - X1(Parachain(1)), + X1(Parachain(1)).into(), Xcm::TransferAsset { - assets: vec![ ConcreteFungible { id: Null, amount: 100 } ], - dest: X1(AccountIndex64{index:3, network:Any}), + assets: vec![ ConcreteFungible { id: Null.into(), amount: 100 } ], + dest: X1(AccountIndex64{index:3, network:Any}).into(), }, 50, ); assert_eq!(r, Outcome::Complete(10)); - assert_eq!(assets(3), vec![ ConcreteFungible { id: Null, amount: 100 } ]); - assert_eq!(assets(1001), vec![ ConcreteFungible { id: Null, amount: 900 } ]); + assert_eq!(assets(3), vec![ ConcreteFungible { id: Null.into(), amount: 100 } ]); + assert_eq!(assets(1001), vec![ ConcreteFungible { id: Null.into(), amount: 900 } ]); assert_eq!(sent_xcm(), vec![]); } #[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, ConcreteFungible { id: Null, amount: 1000 }); + add_asset(1001, ConcreteFungible { id: Null.into(), amount: 1000 }); // 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::<TestConfig>::execute_xcm( - X1(Parachain(1)), + X1(Parachain(1)).into(), Xcm::TransferReserveAsset { - assets: vec![ ConcreteFungible { id: Null, amount: 100 } ], - dest: X1(Parachain(2)), + assets: vec![ ConcreteFungible { id: Null.into(), amount: 100 } ], + dest: X1(Parachain(2)).into(), effects: vec![ Order::DepositAsset { assets: vec![ All ], dest: three.clone() } ], }, 50, ); assert_eq!(r, Outcome::Complete(10)); - assert_eq!(assets(1002), vec![ ConcreteFungible { id: Null, amount: 100 } ]); + assert_eq!(assets(1002), vec![ ConcreteFungible { id: Null.into(), amount: 100 } ]); assert_eq!(sent_xcm(), vec![( - X1(Parachain(2)), + X1(Parachain(2)).into(), Xcm::ReserveAssetDeposit { - assets: vec![ ConcreteFungible { id: X1(Parent), amount: 100 } ], + assets: vec![ ConcreteFungible { id: MultiLocation::new(1, Null).unwrap(), amount: 100 } ], effects: vec![ Order::DepositAsset { assets: vec![ All ], dest: three } ], }) ]); @@ -242,9 +248,9 @@ fn reserve_transfer_should_work() { #[test] fn transacting_should_work() { - AllowUnpaidFrom::set(vec![ X1(Parent) ]); + AllowUnpaidFrom::set(vec![ MultiLocation::new(1, Null).unwrap() ]); - let origin = X1(Parent); + let origin = MultiLocation::new(1, Null).unwrap(); let message = Xcm::<TestCall>::Transact { origin_type: OriginKind::Native, require_weight_at_most: 50, @@ -257,9 +263,9 @@ fn transacting_should_work() { #[test] fn transacting_should_respect_max_weight_requirement() { - AllowUnpaidFrom::set(vec![ X1(Parent) ]); + AllowUnpaidFrom::set(vec![ MultiLocation::new(1, Null).unwrap() ]); - let origin = X1(Parent); + let origin = MultiLocation::new(1, Null).unwrap(); let message = Xcm::<TestCall>::Transact { origin_type: OriginKind::Native, require_weight_at_most: 40, @@ -272,9 +278,9 @@ fn transacting_should_respect_max_weight_requirement() { #[test] fn transacting_should_refund_weight() { - AllowUnpaidFrom::set(vec![ X1(Parent) ]); + AllowUnpaidFrom::set(vec![ MultiLocation::new(1, Null).unwrap() ]); - let origin = X1(Parent); + let origin = MultiLocation::new(1, Null).unwrap(); let message = Xcm::<TestCall>::Transact { origin_type: OriginKind::Native, require_weight_at_most: 50, @@ -287,14 +293,14 @@ 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, ConcreteFungible { id: X1(Parent), amount: 100 }); - WeightPrice::set((X1(Parent), 1_000_000_000_000)); + add_asset(1, ConcreteFungible { id: MultiLocation::new(1, Null).unwrap(), amount: 100 }); + WeightPrice::set((MultiLocation::new(1, Null).unwrap(), 1_000_000_000_000)); let origin = one.clone(); let message = Xcm::<TestCall>::WithdrawAsset { - assets: vec![ ConcreteFungible { id: X1(Parent), amount: 100 } ], // enough for 100 units of weight. + assets: vec![ ConcreteFungible { id: MultiLocation::new(1, Null).unwrap(), amount: 100 } ], // enough for 100 units of weight. effects: vec![ Order::<TestCall>::BuyExecution { fees: All, weight: 70, debt: 30, halt_on_error: true, xcm: vec![ Xcm::<TestCall>::Transact { @@ -310,17 +316,19 @@ fn paid_transacting_should_refund_payment_for_unused_weight() { let weight_limit = 100; let r = XcmExecutor::<TestConfig>::execute_xcm(origin, message, weight_limit); assert_eq!(r, Outcome::Complete(50)); - assert_eq!(assets(1), vec![ ConcreteFungible { id: X1(Parent), amount: 50 } ]); + assert_eq!(assets(1), vec![ ConcreteFungible { id: MultiLocation::new(1, Null).unwrap(), amount: 50 } ]); } #[test] fn prepaid_result_of_query_should_get_free_execution() { let query_id = 33; - let origin = X1(Parent); + let origin = MultiLocation::new(1, Null).unwrap(); // 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(vec![ ConcreteFungible { id: X1(Parent), amount: 100 } ]); + let the_response = Response::Assets( + vec![ ConcreteFungible { id: MultiLocation::new(1, Null).unwrap(), amount: 100 } ], + ); let message = Xcm::<TestCall>::QueryResponse { query_id, response: the_response.clone(), From c4a2d6853f906e39ce614fca2da79d642fcfcb38 Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Sat, 31 Jul 2021 08:06:50 -0700 Subject: [PATCH 014/166] Make pallet-xcm compile --- xcm/pallet-xcm/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/xcm/pallet-xcm/src/lib.rs b/xcm/pallet-xcm/src/lib.rs index a99d630fefe3..f390f0bb60a4 100644 --- a/xcm/pallet-xcm/src/lib.rs +++ b/xcm/pallet-xcm/src/lib.rs @@ -250,9 +250,9 @@ pub mod pallet { /// Relay an XCM `message` from a given `interior` location in this context to a given `dest` /// location. A null `dest` is not handled. pub fn send_xcm(interior: MultiLocation, dest: MultiLocation, message: Xcm<()>) -> Result<(), XcmError> { - let message = match interior { - MultiLocation::Null => message, - who => Xcm::<()>::RelayedFrom { who, message: Box::new(message) }, + let message = match interior.junctions() { + Junctions::Null => message, + _ => Xcm::<()>::RelayedFrom { who: interior, message: Box::new(message) }, }; log::trace!(target: "xcm::send_xcm", "dest: {:?}, message: {:?}", &dest, &message); T::XcmRouter::send_xcm(dest, message) From 9f64f61226aed2421bea658ce47bed88c88a6109 Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Sat, 31 Jul 2021 08:50:06 -0700 Subject: [PATCH 015/166] Use MultiLocation::default() --- xcm/pallet-xcm/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xcm/pallet-xcm/src/lib.rs b/xcm/pallet-xcm/src/lib.rs index f390f0bb60a4..0bbe0bff4b4a 100644 --- a/xcm/pallet-xcm/src/lib.rs +++ b/xcm/pallet-xcm/src/lib.rs @@ -323,7 +323,7 @@ impl<O: OriginTrait + From<Origin>, F: Filter<MultiLocation>> EnsureOrigin<O> fo #[cfg(feature = "runtime-benchmarks")] fn successful_origin() -> O { - O::from(Origin::Xcm(MultiLocation::Null)) + O::from(Origin::Xcm(MultiLocation::default())) } } From 15b1ec99db524a2f50b6d44078e51fb9a6f952ac Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Sat, 31 Jul 2021 10:06:54 -0700 Subject: [PATCH 016/166] Make polkadot-runtime-common compile --- runtime/common/src/xcm_sender.rs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/runtime/common/src/xcm_sender.rs b/runtime/common/src/xcm_sender.rs index eb301a53ea30..2c93884e6b3e 100644 --- a/runtime/common/src/xcm_sender.rs +++ b/runtime/common/src/xcm_sender.rs @@ -18,7 +18,10 @@ use parity_scale_codec::Encode; use sp_std::marker::PhantomData; -use xcm::opaque::{VersionedXcm, v0::{SendXcm, MultiLocation, Junction, Xcm, Result, Error}}; +use xcm::opaque::{ + VersionedXcm, + v0::{SendXcm, MultiLocation, Junction, Junctions, Xcm, Result, Error}, +}; use runtime_parachains::{configuration, dmp}; /// XCM sender for relay chain. It only sends downward message. @@ -26,18 +29,18 @@ pub struct ChildParachainRouter<T>(PhantomData<T>); impl<T: configuration::Config + dmp::Config> SendXcm for ChildParachainRouter<T> { fn send_xcm(dest: MultiLocation, msg: Xcm) -> Result { - match dest { - MultiLocation::X1(Junction::Parachain(id)) => { + match dest.junctions() { + Junctions::X1(Junction::Parachain(id)) if dest.parent_count() == 0 => { // Downward message passing. let config = <configuration::Pallet<T>>::config(); <dmp::Pallet<T>>::queue_downward_message( &config, - id.into(), + (*id).into(), VersionedXcm::from(msg).encode(), ).map_err(Into::<Error>::into)?; Ok(()) } - d => Err(Error::CannotReachDestination(d, msg)), + _ => Err(Error::CannotReachDestination(dest, msg)), } } } From 2370c397a640b0d784747901f8d36da7ecb1c0a4 Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Sun, 1 Aug 2021 06:23:46 -0700 Subject: [PATCH 017/166] Make rococo-runtime compile --- runtime/rococo/src/lib.rs | 38 ++++++++++++++++------------- xcm/src/v0/multi_location.rs | 47 ++++++++++++++++++++++++++++++------ 2 files changed, 60 insertions(+), 25 deletions(-) diff --git a/runtime/rococo/src/lib.rs b/runtime/rococo/src/lib.rs index 790248daf644..3afe89df664d 100644 --- a/runtime/rococo/src/lib.rs +++ b/runtime/rococo/src/lib.rs @@ -584,9 +584,9 @@ impl parachains_paras::Config for Runtime { } parameter_types! { - pub const RocLocation: MultiLocation = MultiLocation::Null; + pub const RocLocation: MultiLocation = MultiLocation::empty(); pub const RococoNetwork: NetworkId = NetworkId::Polkadot; - pub const Ancestry: MultiLocation = MultiLocation::Null; + pub const Ancestry: MultiLocation = MultiLocation::empty(); pub CheckAccount: AccountId = XcmPallet::check_account(); } @@ -627,16 +627,16 @@ pub type XcmRouter = ( xcm_sender::ChildParachainRouter<Runtime>, ); -use xcm::v0::{MultiAsset, MultiAsset::AllConcreteFungible, MultiLocation::{Null, X1}, Junction::Parachain}; +use xcm::v0::{MultiAsset, MultiAsset::AllConcreteFungible, Junctions::{Null, X1}, Junction::Parachain}; parameter_types! { pub const RococoForTick: (MultiAsset, MultiLocation) = - (AllConcreteFungible { id: Null }, X1(Parachain(100))); + (AllConcreteFungible { id: MultiLocation::empty() }, MultiLocation::with_parachain_interior(100)); pub const RococoForTrick: (MultiAsset, MultiLocation) = - (AllConcreteFungible { id: Null }, X1(Parachain(110))); + (AllConcreteFungible { id: MultiLocation::empty() }, MultiLocation::with_parachain_interior(110)); pub const RococoForTrack: (MultiAsset, MultiLocation) = - (AllConcreteFungible { id: Null }, X1(Parachain(120))); + (AllConcreteFungible { id: MultiLocation::empty() }, MultiLocation::with_parachain_interior(120)); pub const RococoForStatemint: (MultiAsset, MultiLocation) = - (AllConcreteFungible { id: Null }, X1(Parachain(1001))); + (AllConcreteFungible { id: MultiLocation::empty() }, MultiLocation::with_parachain_interior(1001)); } pub type TrustedTeleporters = ( xcm_builder::Case<RococoForTick>, @@ -648,10 +648,10 @@ pub type TrustedTeleporters = ( parameter_types! { pub AllowUnpaidFrom: Vec<MultiLocation> = vec![ - X1(Parachain(100)), - X1(Parachain(110)), - X1(Parachain(120)), - X1(Parachain(1001)) + MultiLocation::with_parachain_interior(100), + MultiLocation::with_parachain_interior(110), + MultiLocation::with_parachain_interior(120), + MultiLocation::with_parachain_interior(1001), ]; } @@ -698,10 +698,10 @@ impl frame_support::traits::Contains<(MultiLocation, Xcm<Call>)> for OnlyWithdra Xcm::WithdrawAsset, Order::{BuyExecution, InitiateTeleport, DepositAsset}, MultiAsset::{All, ConcreteFungible}, Junction::{AccountId32, Plurality}, }; - match origin { + match origin.junctions() { // Root and collective are allowed to execute anything. - Null | X1(Plurality { .. }) => true, - X1(AccountId32 { .. }) => { + Null | X1(Plurality { .. }) if origin.parent_count() == 0 => true, + X1(AccountId32 { .. }) if origin.parent_count() == 0 => { // An account ID trying to send a message. We ensure that it's sensible. // This checks that it's of the form: // WithdrawAsset { @@ -717,16 +717,20 @@ impl frame_support::traits::Contains<(MultiLocation, Xcm<Call>)> for OnlyWithdra // } matches!(msg, WithdrawAsset { ref assets, ref effects } if assets.len() == 1 - && matches!(assets[0], ConcreteFungible { id: Null, .. }) + && matches!(assets[0], ConcreteFungible { ref id, .. } if id.is_empty()) && effects.len() == 2 && matches!(effects[0], BuyExecution { .. }) - && matches!(effects[1], InitiateTeleport { ref assets, dest: X1(Parachain(..)), ref effects } + && matches!(effects[1], InitiateTeleport { ref assets, ref dest, ref effects } if assets.len() == 1 + && matches!(dest.junctions(), X1(Parachain(..))) + && dest.parent_count() == 0 && matches!(assets[0], All) && effects.len() == 2 && matches!(effects[0], BuyExecution { .. }) - && matches!(effects[1], DepositAsset { ref assets, dest: X1(AccountId32{..}) } + && matches!(effects[1], DepositAsset { ref assets, ref dest } if assets.len() == 1 + && matches!(dest.junctions(), X1(AccountId32{..})) + && dest.parent_count() == 0 && matches!(assets[0], All) ) ) diff --git a/xcm/src/v0/multi_location.rs b/xcm/src/v0/multi_location.rs index ff2cb40c5a45..cb7f7daa2c5d 100644 --- a/xcm/src/v0/multi_location.rs +++ b/xcm/src/v0/multi_location.rs @@ -52,10 +52,7 @@ pub struct MultiLocation { impl Default for MultiLocation { fn default() -> Self { - MultiLocation { - parents: 0, - interior: Junctions::Null, - } + Self::empty() } } @@ -115,6 +112,40 @@ impl MultiLocation { }) } + /// Creates a new `MultiLocation` with 0 parents and a `Null` interior. + pub const fn empty() -> MultiLocation { + MultiLocation { + parents: 0, + interior: Junctions::Null, + } + } + + /// Creates a new `MultiLocation` with the specified number of parents and a `Null` interior. + /// Returns an error if `parents` is greater than `MAX_MULTILOCATION_LENGTH`. + pub const fn with_parents(parents: u8) -> result::Result<MultiLocation, ()> { + if parents as usize > MAX_MULTILOCATION_LENGTH { + return Err(()) + } + Ok(MultiLocation { + parents, + interior: Junctions::Null, + }) + } + + /// Creates a new `MultiLocation` with no parents and a single `Parachain` interior junction + /// specified by `para_id`. + pub const fn with_parachain_interior(para_id: u32) -> MultiLocation { + MultiLocation { + parents: 0, + interior: Junctions::X1(Junction::Parachain(para_id)), + } + } + + /// Whether or not the `MultiLocation` has no parents and has a `Null` interior. + pub const fn is_empty(&self) -> bool { + self.parents == 0 && self.interior.len() == 0 + } + /// Return a reference to the interior field. pub fn junctions(&self) -> &Junctions { &self.interior @@ -126,12 +157,12 @@ impl MultiLocation { } /// Returns the number of `Parent` junctions at the beginning of `self`. - pub fn parent_count(&self) -> usize { + pub const fn parent_count(&self) -> usize { self.parents as usize } /// Returns the number of parents and junctions in `self`. - pub fn len(&self) -> usize { + pub const fn len(&self) -> usize { self.parent_count() + self.interior.len() } @@ -159,7 +190,7 @@ impl MultiLocation { } /// 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 or that `self` only contains parents. + /// (second item in tuple) or `None` if it was empty or if `self` only contains parents. pub fn split_last(self) -> (MultiLocation, Option<Junction>) { let MultiLocation { parents, interior: junctions } = self; let (prefix, suffix) = junctions.split_last(); @@ -722,7 +753,7 @@ impl Junctions { } /// Returns the number of junctions in `self`. - pub fn len(&self) -> usize { + pub const fn len(&self) -> usize { match &self { Junctions::Null => 0, Junctions::X1(..) => 1, From 6aaa81b1541c11ff5ed39dbee66616631358aaea Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Sun, 1 Aug 2021 06:26:03 -0700 Subject: [PATCH 018/166] Change return type of parent_count to u8 --- xcm/src/v0/multi_location.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/xcm/src/v0/multi_location.rs b/xcm/src/v0/multi_location.rs index cb7f7daa2c5d..fce98efb3c20 100644 --- a/xcm/src/v0/multi_location.rs +++ b/xcm/src/v0/multi_location.rs @@ -157,13 +157,13 @@ impl MultiLocation { } /// Returns the number of `Parent` junctions at the beginning of `self`. - pub const fn parent_count(&self) -> usize { - self.parents as usize + pub const fn parent_count(&self) -> u8 { + self.parents } /// Returns the number of parents and junctions in `self`. pub const fn len(&self) -> usize { - self.parent_count() + self.interior.len() + self.parent_count() as usize + self.interior.len() } /// Returns first junction that is not a parent, or `None` if the location is empty or @@ -369,7 +369,7 @@ impl MultiLocation { pub fn prepend_with(&mut self, mut prefix: MultiLocation) -> Result<(), MultiLocation> { let self_parents = self.parent_count(); let prepend_len = (self_parents as isize - prefix.interior.len() as isize).abs() as usize; - if self.interior.len() + prefix.parent_count() + prepend_len > MAX_MULTILOCATION_LENGTH { + if self.interior.len() + prefix.parent_count() as usize + prepend_len > MAX_MULTILOCATION_LENGTH { return Err(prefix) } From 59e59357af8a252c75576df6f60ca31b56dcce86 Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Sun, 1 Aug 2021 06:32:44 -0700 Subject: [PATCH 019/166] Change MAX_MULTILOCATION_LENGTH to 255 --- xcm/src/v0/multi_location.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/xcm/src/v0/multi_location.rs b/xcm/src/v0/multi_location.rs index fce98efb3c20..9b5f83f5cc09 100644 --- a/xcm/src/v0/multi_location.rs +++ b/xcm/src/v0/multi_location.rs @@ -58,7 +58,7 @@ impl Default for MultiLocation { impl Encode for MultiLocation { fn encode_to<T: Output + ?Sized>(&self, dest: &mut T) { - // 8 items max, but we cannot return an error, so we ap silently. + // 255 items max, but we cannot return an error, so we truncate silently. let parents = self.parents.min( MAX_MULTILOCATION_LENGTH.saturating_sub(self.interior.len()) as u8, ); @@ -97,7 +97,7 @@ impl Decode for MultiLocation { } /// Maximum number of junctions a `MultiLocation` can contain. -pub const MAX_MULTILOCATION_LENGTH: usize = 8; +pub const MAX_MULTILOCATION_LENGTH: usize = 255; impl MultiLocation { /// Creates a new `MultiLocation`, ensuring that the length of it does not exceed the maximum, @@ -945,7 +945,7 @@ mod tests { // cannot append to create overly long multilocation let acc = AccountIndex64 { network: Any, index: 23 }; - let mut m = MultiLocation { parents: 6, interior: X1(Parachain(42)) }; + let mut m = MultiLocation { parents: 254, interior: X1(Parachain(42)) }; let suffix = MultiLocation::from(X2(PalletInstance(3), acc.clone())); assert_eq!(m.append_with(suffix.clone()), Err(suffix)); } @@ -957,12 +957,12 @@ mod tests { assert_eq!(m, MultiLocation { parents: 1, interior: X2(Parachain(42), AccountIndex64 { network: Any, index: 23 }) }); // cannot prepend to create overly long multilocation - let mut m = MultiLocation { parents: 6, interior: X1(Parachain(42)) }; + let mut m = MultiLocation { parents: 253, interior: X1(Parachain(42)) }; let prefix = MultiLocation { parents: 2, interior: Null }; assert_eq!(m.prepend_with(prefix.clone()), Err(prefix)); let prefix = MultiLocation { parents: 1, interior: Null }; assert_eq!(m.prepend_with(prefix), Ok(())); - assert_eq!(m, MultiLocation { parents: 7, interior: X1(Parachain(42)) }); + assert_eq!(m, MultiLocation { parents: 254, interior: X1(Parachain(42)) }); } } From 85a61a52fc2e45e7b4912299b233d3f3fac885da Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Sun, 1 Aug 2021 06:48:34 -0700 Subject: [PATCH 020/166] Make kusama-runtime compile --- runtime/kusama/src/lib.rs | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/runtime/kusama/src/lib.rs b/runtime/kusama/src/lib.rs index 3d0ab1ebd099..6171a8c60df3 100644 --- a/runtime/kusama/src/lib.rs +++ b/runtime/kusama/src/lib.rs @@ -54,7 +54,7 @@ use runtime_parachains::scheduler as parachains_scheduler; use runtime_parachains::reward_points as parachains_reward_points; use runtime_parachains::runtime_api_impl::v1 as parachains_runtime_api_impl; -use xcm::v0::{MultiLocation::{self, Null, X1}, NetworkId, BodyId, Xcm, Junction::Parachain}; +use xcm::v0::{MultiLocation, Junctions::{Null, X1}, NetworkId, BodyId, Xcm, Junction::Parachain}; use xcm::v0::MultiAsset::{self, AllConcreteFungible}; use xcm_builder::{ AccountId32Aliases, ChildParachainConvertsVia, SovereignSignedViaLocation, CurrencyAdapter as XcmCurrencyAdapter, @@ -1198,12 +1198,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 `Null` location, which means "equivalent to /// the context". - pub const KsmLocation: MultiLocation = MultiLocation::Null; + pub const KsmLocation: MultiLocation = MultiLocation::empty(); /// 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::Null; + pub const Ancestry: MultiLocation = MultiLocation::empty(); /// The check account, which holds any native assets that have been teleported out and not back in (yet). pub CheckAccount: AccountId = XcmPallet::check_account(); } @@ -1261,7 +1261,7 @@ pub type XcmRouter = ( parameter_types! { pub const KusamaForStatemint: (MultiAsset, MultiLocation) = - (AllConcreteFungible { id: Null }, X1(Parachain(1000))); + (AllConcreteFungible { id: MultiLocation::empty() }, MultiLocation::with_parachain_interior(1000)); } pub type TrustedTeleporters = ( xcm_builder::Case<KusamaForStatemint>, @@ -1314,10 +1314,10 @@ impl frame_support::traits::Contains<(MultiLocation, Xcm<Call>)> for OnlyWithdra Xcm::WithdrawAsset, Order::{BuyExecution, InitiateTeleport, DepositAsset}, MultiAsset::{All, ConcreteFungible}, Junction::{AccountId32, Plurality}, }; - match origin { + match origin.junctions() { // Root and council are are allowed to execute anything. - Null | X1(Plurality { .. }) => true, - X1(AccountId32 { .. }) => { + Null | X1(Plurality { .. }) if origin.parent_count() == 0 => true, + X1(AccountId32 { .. }) if origin.parent_count() == 0 => { // An account ID trying to send a message. We ensure that it's sensible. // This checks that it's of the form: // WithdrawAsset { @@ -1333,17 +1333,21 @@ impl frame_support::traits::Contains<(MultiLocation, Xcm<Call>)> for OnlyWithdra // } matches!(msg, WithdrawAsset { ref assets, ref effects } if assets.len() == 1 - && matches!(assets[0], ConcreteFungible { id: Null, .. }) + && matches!(assets[0], ConcreteFungible { ref id, .. } if id.is_empty()) && effects.len() == 2 && matches!(effects[0], BuyExecution { .. }) - && matches!(effects[1], InitiateTeleport { ref assets, dest: X1(Parachain(..)), ref effects } + && matches!(effects[1], InitiateTeleport { ref assets, ref dest, ref effects } if assets.len() == 1 + && matches!(dest.junctions(), X1(Parachain(..))) + && dest.parent_count() == 0 && matches!(assets[0], All) && effects.len() == 2 && matches!(effects[0], BuyExecution { .. }) - && matches!(effects[1], DepositAsset { ref assets, dest: X1(AccountId32{..}) } + && matches!(effects[1], DepositAsset { ref assets, ref dest } if assets.len() == 1 && matches!(assets[0], All) + && dest.parent_count() == 0 + && matches!(dest.junctions(), X1(AccountId32{..})) ) ) ) From dba0ed9479052646126ad64152dae8c396455035 Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Sun, 1 Aug 2021 06:50:03 -0700 Subject: [PATCH 021/166] Fix logic in pallet-xcm --- xcm/pallet-xcm/src/lib.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/xcm/pallet-xcm/src/lib.rs b/xcm/pallet-xcm/src/lib.rs index 0bbe0bff4b4a..b13256639032 100644 --- a/xcm/pallet-xcm/src/lib.rs +++ b/xcm/pallet-xcm/src/lib.rs @@ -250,9 +250,10 @@ pub mod pallet { /// Relay an XCM `message` from a given `interior` location in this context to a given `dest` /// location. A null `dest` is not handled. pub fn send_xcm(interior: MultiLocation, dest: MultiLocation, message: Xcm<()>) -> Result<(), XcmError> { - let message = match interior.junctions() { - Junctions::Null => message, - _ => Xcm::<()>::RelayedFrom { who: interior, message: Box::new(message) }, + let message = if interior.is_empty() { + 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) From e1ec296e2afc4d7c9710e2105ae339417fb352fe Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Sun, 1 Aug 2021 06:50:51 -0700 Subject: [PATCH 022/166] Use MultiLocation::empty() --- xcm/pallet-xcm/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xcm/pallet-xcm/src/lib.rs b/xcm/pallet-xcm/src/lib.rs index b13256639032..79dd9fece8b5 100644 --- a/xcm/pallet-xcm/src/lib.rs +++ b/xcm/pallet-xcm/src/lib.rs @@ -324,7 +324,7 @@ impl<O: OriginTrait + From<Origin>, F: Filter<MultiLocation>> EnsureOrigin<O> fo #[cfg(feature = "runtime-benchmarks")] fn successful_origin() -> O { - O::from(Origin::Xcm(MultiLocation::default())) + O::from(Origin::Xcm(MultiLocation::empty())) } } From 980763944272ef52d7862d1ac5a0156cbf54a735 Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Sun, 1 Aug 2021 06:55:57 -0700 Subject: [PATCH 023/166] Fix logic in location_conversion --- xcm/xcm-builder/src/location_conversion.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xcm/xcm-builder/src/location_conversion.rs b/xcm/xcm-builder/src/location_conversion.rs index 7c6e9743fbcc..60bfde4da9fe 100644 --- a/xcm/xcm-builder/src/location_conversion.rs +++ b/xcm/xcm-builder/src/location_conversion.rs @@ -43,7 +43,7 @@ impl< AccountId: Default + Eq + Clone, > Convert<MultiLocation, AccountId> for ParentIsDefault<AccountId> { fn convert_ref(location: impl Borrow<MultiLocation>) -> Result<AccountId, ()> { - if location.borrow().parent_count() == 1 { + if location.borrow().parent_count() == 1 && location.borrow().junctions().len() == 0 { Ok(AccountId::default()) } else { Err(()) @@ -52,7 +52,7 @@ impl< fn reverse_ref(who: impl Borrow<AccountId>) -> Result<MultiLocation, ()> { if who.borrow() == &AccountId::default() { - Ok(MultiLocation::new(1, Junctions::Null).expect("well-formed MultiLocation; qed")) + Ok(MultiLocation::with_parents(1).expect("well-formed MultiLocation; qed")) } else { Err(()) } From 57bd83ad534132c3c3374f13cc4d787da60687cd Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Sun, 1 Aug 2021 07:02:06 -0700 Subject: [PATCH 024/166] Fix logic in origin_conversion.rs --- xcm/xcm-builder/src/origin_conversion.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/xcm/xcm-builder/src/origin_conversion.rs b/xcm/xcm-builder/src/origin_conversion.rs index e675a48274ba..76782c6515a0 100644 --- a/xcm/xcm-builder/src/origin_conversion.rs +++ b/xcm/xcm-builder/src/origin_conversion.rs @@ -46,7 +46,7 @@ impl< Origin: OriginTrait, > ConvertOrigin<Origin> for ParentAsSuperuser<Origin> { fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result<Origin, MultiLocation> { - if kind == OriginKind::Superuser && origin.parent_count() == 1 { + if kind == OriginKind::Superuser && origin.parent_count() == 1 && origin.junctions().len() == 0 { Ok(Origin::root()) } else { Err(origin) @@ -126,7 +126,7 @@ impl< Origin, > ConvertOrigin<Origin> for RelayChainAsNative<RelayOrigin, Origin> { fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result<Origin, MultiLocation> { - if kind == OriginKind::Native && origin.parent_count() == 1 { + if kind == OriginKind::Native && origin.parent_count() == 1 && origin.junctions().len() == 0 { Ok(RelayOrigin::get()) } else { Err(origin) @@ -193,7 +193,7 @@ impl< // 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::default()) + Ok(MultiLocation::empty()) } else { Err(o) } From 5a4dc4f76b7daa31e4257ad5924cf74c78e717ef Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Sun, 1 Aug 2021 07:42:01 -0700 Subject: [PATCH 025/166] Make westend-runtime compile --- runtime/westend/src/lib.rs | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/runtime/westend/src/lib.rs b/runtime/westend/src/lib.rs index cdc849a10429..506e57f84584 100644 --- a/runtime/westend/src/lib.rs +++ b/runtime/westend/src/lib.rs @@ -53,7 +53,7 @@ use runtime_parachains::scheduler as parachains_scheduler; use runtime_parachains::reward_points as parachains_reward_points; use runtime_parachains::runtime_api_impl::v1 as parachains_runtime_api_impl; -use xcm::v0::{MultiLocation::{self, Null, X1}, NetworkId, Xcm, Junction::Parachain}; +use xcm::v0::{MultiLocation, Junctions::{Null, X1}, NetworkId, Xcm, Junction::Parachain}; use xcm::v0::MultiAsset::{self, AllConcreteFungible}; use xcm_executor::XcmExecutor; use xcm_builder::{ @@ -863,8 +863,8 @@ impl auctions::Config for Runtime { } parameter_types! { - pub const WndLocation: MultiLocation = MultiLocation::Null; - pub const Ancestry: MultiLocation = MultiLocation::Null; + pub const WndLocation: MultiLocation = MultiLocation::empty(); + pub const Ancestry: MultiLocation = MultiLocation::empty(); 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: (MultiAsset, MultiLocation) = - (AllConcreteFungible { id: Null }, X1(Parachain(1000))); + (AllConcreteFungible { id: MultiLocation::empty() }, MultiLocation::with_parachain_interior(1000)); } pub type TrustedTeleporters = ( xcm_builder::Case<WestendForWestmint>, @@ -953,10 +953,10 @@ impl frame_support::traits::Contains<(MultiLocation, Xcm<Call>)> for OnlyWithdra Xcm::WithdrawAsset, Order::{BuyExecution, InitiateTeleport, DepositAsset}, MultiAsset::{All, ConcreteFungible}, Junction::AccountId32, }; - match origin { + match origin.junctions() { // Root is allowed to execute anything. - Null => true, - X1(AccountId32 { .. }) => { + Null if origin.parent_count() == 0 => true, + X1(AccountId32 { .. }) if origin.parent_count() == 0 => { // An account ID trying to send a message. We ensure that it's sensible. // This checks that it's of the form: // WithdrawAsset { @@ -972,17 +972,21 @@ impl frame_support::traits::Contains<(MultiLocation, Xcm<Call>)> for OnlyWithdra // } matches!(msg, WithdrawAsset { ref assets, ref effects } if assets.len() == 1 - && matches!(assets[0], ConcreteFungible { id: Null, .. }) + && matches!(assets[0], ConcreteFungible { ref id, .. } if id.is_empty()) && effects.len() == 2 && matches!(effects[0], BuyExecution { .. }) - && matches!(effects[1], InitiateTeleport { ref assets, dest: X1(Parachain(..)), ref effects } + && matches!(effects[1], InitiateTeleport { ref assets, ref dest, ref effects } if assets.len() == 1 && matches!(assets[0], All) + && dest.parent_count() == 0 + && matches!(dest.junctions(), X1(Parachain(..))) && effects.len() == 2 && matches!(effects[0], BuyExecution { .. }) - && matches!(effects[1], DepositAsset { ref assets, dest: X1(AccountId32{..}) } + && matches!(effects[1], DepositAsset { ref assets, ref dest } if assets.len() == 1 && matches!(assets[0], All) + && dest.parent_count() == 0 + && matches!(dest.junctions(), X1(AccountId32{..})) ) ) ) From f313fc4fc7cd91390c809c2ac709c59148d854d8 Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Sun, 1 Aug 2021 08:39:51 -0700 Subject: [PATCH 026/166] Rename prefixes and suffixes variables --- xcm/src/v0/multi_location.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/xcm/src/v0/multi_location.rs b/xcm/src/v0/multi_location.rs index 9b5f83f5cc09..a76bae8f1dbc 100644 --- a/xcm/src/v0/multi_location.rs +++ b/xcm/src/v0/multi_location.rs @@ -181,24 +181,24 @@ impl MultiLocation { /// and the first element (second item in tuple) or `None` if it was empty. pub fn split_first_non_parent(self) -> (MultiLocation, Option<Junction>) { let MultiLocation { parents, interior: junctions } = self; - let (prefix, suffix) = junctions.split_first(); + let (suffix, first) = junctions.split_first(); let multilocation = MultiLocation { parents, - interior: prefix, + interior: suffix, }; - (multilocation, suffix) + (multilocation, first) } /// 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 or if `self` only contains parents. pub fn split_last(self) -> (MultiLocation, Option<Junction>) { let MultiLocation { parents, interior: junctions } = self; - let (prefix, suffix) = junctions.split_last(); + let (prefix, last) = junctions.split_last(); let multilocation = MultiLocation { parents, interior: prefix, }; - (multilocation, suffix) + (multilocation, last) } /// Bumps the parent count up by 1. Returns `Err` in case of overflow. From 8cdf6c1ca17d169adde01f6b910fc3e70b407c85 Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Sun, 1 Aug 2021 08:41:27 -0700 Subject: [PATCH 027/166] Rename non_parent to interior --- xcm/src/v0/multi_location.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/xcm/src/v0/multi_location.rs b/xcm/src/v0/multi_location.rs index a76bae8f1dbc..1ad6f378535e 100644 --- a/xcm/src/v0/multi_location.rs +++ b/xcm/src/v0/multi_location.rs @@ -210,8 +210,8 @@ impl MultiLocation { Ok(()) } - /// Mutates `self`, suffixing its non-parent junctions with `new`. Returns `Err` in case of overflow. - pub fn push_non_parent(&mut self, new: Junction) -> result::Result<(), ()> { + /// 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::Null; mem::swap(&mut self.interior, &mut n); match n.pushed_with(new) { @@ -220,8 +220,8 @@ impl MultiLocation { } } - /// Mutates `self`, prefixing its non-parent junctions with `new`. Returns `Err` in case of overflow. - pub fn push_front_non_parent(&mut self, new: Junction) -> result::Result<(), ()> { + /// 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::Null; mem::swap(&mut self.interior, &mut n); match n.pushed_front_with(new) { @@ -244,7 +244,7 @@ impl MultiLocation { /// 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_non_parent(self, new: Junction) -> result::Result<Self, Self> { + pub fn pushed_with_interior(self, new: Junction) -> result::Result<Self, Self> { if self.len() >= MAX_MULTILOCATION_LENGTH { return Err(self) } @@ -256,7 +256,7 @@ impl MultiLocation { /// 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_non_parent(self, new: Junction) -> result::Result<Self, Self> { + pub fn pushed_front_with_interior(self, new: Junction) -> result::Result<Self, Self> { if self.len() >= MAX_MULTILOCATION_LENGTH { return Err(self) } @@ -291,13 +291,13 @@ impl MultiLocation { self.parents = self.parents.saturating_sub(1); } - /// Removes the first non-parent element from `self`, returning it + /// 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_non_parent(&mut self) -> Option<Junction> { + pub fn take_first_interior(&mut self) -> Option<Junction> { self.interior.take_first() } - /// Removes the last element from `junctions`, returning it (or `None` if it was empty or if + /// 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<Junction> { self.interior.take_last() @@ -386,7 +386,7 @@ impl MultiLocation { self.parents = final_parent_count; for j in prefix.interior.into_iter_rev() { - self.push_front_non_parent(j).expect( + self.push_front_interior(j).expect( "self junctions len + prefix parent count + prepend len is less than max length; qed" ); } From 595621635d25355a2ce10826b51807fe48c976c8 Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Sun, 1 Aug 2021 09:36:59 -0700 Subject: [PATCH 028/166] Rename non_parent to interior --- xcm/xcm-builder/src/fungibles_adapter.rs | 2 +- xcm/xcm-builder/src/location_conversion.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/xcm/xcm-builder/src/fungibles_adapter.rs b/xcm/xcm-builder/src/fungibles_adapter.rs index c39b4aa4eae1..99807f2098f8 100644 --- a/xcm/xcm-builder/src/fungibles_adapter.rs +++ b/xcm/xcm-builder/src/fungibles_adapter.rs @@ -50,7 +50,7 @@ impl< fn reverse_ref(what: impl Borrow<AssetId>) -> result::Result<MultiLocation, ()> { let mut location = Prefix::get(); let id = ConvertAssetId::reverse_ref(what)?; - location.push_non_parent(Junction::GeneralIndex { id })?; + 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 60bfde4da9fe..d3528eb275ae 100644 --- a/xcm/xcm-builder/src/location_conversion.rs +++ b/xcm/xcm-builder/src/location_conversion.rs @@ -198,7 +198,7 @@ impl<Ancestry: Get<MultiLocation>> InvertLocation for LocationInverter<Ancestry> let mut junctions = Junctions::Null; for _ in 0..location.parent_count() { junctions = junctions.pushed_with( - ancestry.take_first_non_parent().unwrap_or(Junction::OnlyChild), + ancestry.take_first_interior().unwrap_or(Junction::OnlyChild), ) .expect("ancestry is well-formed and has less than 8 non-parent junctions; qed"); } From 46aea44a5056b7b7762f8382adb96ffbb38ebb5d Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Sun, 1 Aug 2021 09:37:38 -0700 Subject: [PATCH 029/166] Add test for encode/decode roundtrip and fix decode algorithm --- xcm/src/v0/junction.rs | 8 ++++++++ xcm/src/v0/multi_location.rs | 24 ++++++++++++++++++++++-- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/xcm/src/v0/junction.rs b/xcm/src/v0/junction.rs index d26cecf08b21..3aa98126b639 100644 --- a/xcm/src/v0/junction.rs +++ b/xcm/src/v0/junction.rs @@ -100,40 +100,48 @@ pub enum Junction { /// the context. /// /// Generally used when the context is a Substrate-based chain. + #[codec(index = 2)] 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. + #[codec(index = 3)] 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. + #[codec(index = 4)] 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. + #[codec(index = 5)] 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. + #[codec(index = 6)] GeneralIndex { #[codec(compact)] id: 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. + #[codec(index = 7)] GeneralKey(Vec<u8>), /// The unambiguous child. /// /// Not currently used except as a fallback when deriving ancestry. + #[codec(index = 8)] 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. + #[codec(index = 9)] Plurality { id: BodyId, part: BodyPart }, } diff --git a/xcm/src/v0/multi_location.rs b/xcm/src/v0/multi_location.rs index 1ad6f378535e..c44381713e83 100644 --- a/xcm/src/v0/multi_location.rs +++ b/xcm/src/v0/multi_location.rs @@ -88,8 +88,18 @@ impl Decode for MultiLocation { } parents = parents.saturating_add(1); } else { - interior = interior.pushed_with(Junction::decode(&mut &[b][..])?) - .map_err(|_| parity_scale_codec::Error::from("Interior too long"))?; + let mut bytes = [b].to_vec(); + loop { + if let Ok(junction) = Junction::decode(&mut &bytes[..]) { + interior = interior.pushed_with(junction) + .map_err(|_| parity_scale_codec::Error::from("Interior too long"))?; + break; + } else { + // a single byte may not be enough to decode a `Junction`, so keep reading + // the next byte until a `Junction` can successfully be decoded + bytes.push(input.read_byte()?); + } + } } } Ok(MultiLocation { parents, interior }) @@ -922,9 +932,19 @@ impl TryFrom<VersionedMultiLocation> for MultiLocation { #[cfg(test)] mod tests { + use parity_scale_codec::{Decode, Encode}; use super::{Junctions::*, MultiLocation}; use crate::opaque::v0::{Junction::*, NetworkId::Any}; + #[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, [3, 0, 1, 168, 3, 0, 92].to_vec()); + let decoded = MultiLocation::decode(&mut &encoded[..]); + assert_eq!(decoded, Ok(m)); + } + #[test] fn match_and_split_works() { let m = MultiLocation { parents: 1, interior: X2(Parachain(42), AccountIndex64 { network: Any, index: 23 }) }; From 5445d0675c6fabbed58ef02e6db55b01ed81449a Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Sun, 1 Aug 2021 20:00:31 +0200 Subject: [PATCH 030/166] API changes making their way throughout --- runtime/kusama/src/lib.rs | 51 +-- runtime/rococo/src/lib.rs | 66 +--- runtime/westend/src/lib.rs | 57 +-- xcm/pallet-xcm/src/lib.rs | 20 +- xcm/src/v0/mod.rs | 22 +- xcm/src/v0/multi_asset.rs | 337 ------------------ xcm/src/v0/multiasset.rs | 171 ++------- xcm/src/v0/order.rs | 8 +- xcm/src/v0/traits.rs | 2 +- xcm/xcm-builder/src/barriers.rs | 8 +- xcm/xcm-builder/src/filter_asset_location.rs | 4 +- xcm/xcm-builder/src/tests.rs | 10 +- xcm/xcm-builder/src/weight.rs | 4 +- xcm/xcm-executor/src/assets.rs | 13 +- xcm/xcm-executor/src/lib.rs | 12 +- xcm/xcm-executor/src/traits/transact_asset.rs | 2 +- 16 files changed, 88 insertions(+), 699 deletions(-) delete mode 100644 xcm/src/v0/multi_asset.rs diff --git a/runtime/kusama/src/lib.rs b/runtime/kusama/src/lib.rs index 3d0ab1ebd099..8b307d392843 100644 --- a/runtime/kusama/src/lib.rs +++ b/runtime/kusama/src/lib.rs @@ -1307,61 +1307,14 @@ pub type LocalOriginToLocation = ( SignedToAccountId32<Origin, AccountId, KusamaNetwork>, ); -pub struct OnlyWithdrawTeleportForAccounts; -impl frame_support::traits::Contains<(MultiLocation, Xcm<Call>)> for OnlyWithdrawTeleportForAccounts { - fn contains((ref origin, ref msg): &(MultiLocation, Xcm<Call>)) -> bool { - use xcm::v0::{ - Xcm::WithdrawAsset, Order::{BuyExecution, InitiateTeleport, DepositAsset}, - MultiAsset::{All, ConcreteFungible}, Junction::{AccountId32, Plurality}, - }; - match origin { - // Root and council are are allowed to execute anything. - Null | X1(Plurality { .. }) => true, - X1(AccountId32 { .. }) => { - // An account ID trying to send a message. We ensure that it's sensible. - // This checks that it's of the form: - // WithdrawAsset { - // assets: [ ConcreteFungible { id: Null } ], - // effects: [ BuyExecution, InitiateTeleport { - // assets: All, - // dest: Parachain, - // effects: [ BuyExecution, DepositAssets { - // assets: All, - // dest: AccountId32, - // } ] - // } ] - // } - matches!(msg, WithdrawAsset { ref assets, ref effects } - if assets.len() == 1 - && matches!(assets[0], ConcreteFungible { id: Null, .. }) - && effects.len() == 2 - && matches!(effects[0], BuyExecution { .. }) - && matches!(effects[1], InitiateTeleport { ref assets, dest: X1(Parachain(..)), ref effects } - if assets.len() == 1 - && matches!(assets[0], All) - && effects.len() == 2 - && matches!(effects[0], BuyExecution { .. }) - && matches!(effects[1], DepositAsset { ref assets, dest: X1(AccountId32{..}) } - if assets.len() == 1 - && matches!(assets[0], All) - ) - ) - ) - } - // Nobody else is allowed to execute anything. - _ => false, - } - } -} - impl pallet_xcm::Config for Runtime { type Event = Event; type SendXcmOrigin = xcm_builder::EnsureXcmOrigin<Origin, LocalOriginToLocation>; type XcmRouter = XcmRouter; // Anyone can execute XCM messages locally... type ExecuteXcmOrigin = xcm_builder::EnsureXcmOrigin<Origin, LocalOriginToLocation>; - // ...but they must match our filter, which requires them to be a simple withdraw + teleport. - type XcmExecuteFilter = OnlyWithdrawTeleportForAccounts; + // ...but they must match our filter, which rejects all. + type XcmExecuteFilter = (); type XcmExecutor = XcmExecutor<XcmConfig>; type XcmTeleportFilter = All<(MultiLocation, Vec<MultiAsset>)>; type XcmReserveTransferFilter = All<(MultiLocation, Vec<MultiAsset>)>; diff --git a/runtime/rococo/src/lib.rs b/runtime/rococo/src/lib.rs index 790248daf644..7000c291a1ff 100644 --- a/runtime/rococo/src/lib.rs +++ b/runtime/rococo/src/lib.rs @@ -627,16 +627,13 @@ pub type XcmRouter = ( xcm_sender::ChildParachainRouter<Runtime>, ); -use xcm::v0::{MultiAsset, MultiAsset::AllConcreteFungible, MultiLocation::{Null, X1}, Junction::Parachain}; +use xcm::v0::prelude::*; parameter_types! { - pub const RococoForTick: (MultiAsset, MultiLocation) = - (AllConcreteFungible { id: Null }, X1(Parachain(100))); - pub const RococoForTrick: (MultiAsset, MultiLocation) = - (AllConcreteFungible { id: Null }, X1(Parachain(110))); - pub const RococoForTrack: (MultiAsset, MultiLocation) = - (AllConcreteFungible { id: Null }, X1(Parachain(120))); - pub const RococoForStatemint: (MultiAsset, MultiLocation) = - (AllConcreteFungible { id: Null }, X1(Parachain(1001))); + pub const Rococo: MultiAssetFilter = Wild(AllOf(Concrete(RocLocation::get()), WildFungible)); + 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 type TrustedTeleporters = ( xcm_builder::Case<RococoForTick>, @@ -691,61 +688,14 @@ pub type LocalOriginToLocation = ( SignedToAccountId32<Origin, AccountId, RococoNetwork>, ); -pub struct OnlyWithdrawTeleportForAccounts; -impl frame_support::traits::Contains<(MultiLocation, Xcm<Call>)> for OnlyWithdrawTeleportForAccounts { - fn contains((ref origin, ref msg): &(MultiLocation, Xcm<Call>)) -> bool { - use xcm::v0::{ - Xcm::WithdrawAsset, Order::{BuyExecution, InitiateTeleport, DepositAsset}, - MultiAsset::{All, ConcreteFungible}, Junction::{AccountId32, Plurality}, - }; - match origin { - // Root and collective are allowed to execute anything. - Null | X1(Plurality { .. }) => true, - X1(AccountId32 { .. }) => { - // An account ID trying to send a message. We ensure that it's sensible. - // This checks that it's of the form: - // WithdrawAsset { - // assets: [ ConcreteFungible { id: Null } ], - // effects: [ BuyExecution, InitiateTeleport { - // assets: All, - // dest: Parachain, - // effects: [ BuyExecution, DepositAssets { - // assets: All, - // dest: AccountId32, - // } ] - // } ] - // } - matches!(msg, WithdrawAsset { ref assets, ref effects } - if assets.len() == 1 - && matches!(assets[0], ConcreteFungible { id: Null, .. }) - && effects.len() == 2 - && matches!(effects[0], BuyExecution { .. }) - && matches!(effects[1], InitiateTeleport { ref assets, dest: X1(Parachain(..)), ref effects } - if assets.len() == 1 - && matches!(assets[0], All) - && effects.len() == 2 - && matches!(effects[0], BuyExecution { .. }) - && matches!(effects[1], DepositAsset { ref assets, dest: X1(AccountId32{..}) } - if assets.len() == 1 - && matches!(assets[0], All) - ) - ) - ) - } - // Nobody else is allowed to execute anything. - _ => false, - } - } -} - impl pallet_xcm::Config for Runtime { type Event = Event; type SendXcmOrigin = xcm_builder::EnsureXcmOrigin<Origin, LocalOriginToLocation>; type XcmRouter = XcmRouter; // Anyone can execute XCM messages locally... type ExecuteXcmOrigin = xcm_builder::EnsureXcmOrigin<Origin, LocalOriginToLocation>; - // ...but they must match our filter, which requires them to be a simple withdraw + teleport. - type XcmExecuteFilter = OnlyWithdrawTeleportForAccounts; + // ...but they must match our filter, which right now rejects everything. + type XcmExecuteFilter = (); type XcmExecutor = XcmExecutor<XcmConfig>; type XcmTeleportFilter = All<(MultiLocation, Vec<MultiAsset>)>; type XcmReserveTransferFilter = All<(MultiLocation, Vec<MultiAsset>)>; diff --git a/runtime/westend/src/lib.rs b/runtime/westend/src/lib.rs index cdc849a10429..1e0f16918a72 100644 --- a/runtime/westend/src/lib.rs +++ b/runtime/westend/src/lib.rs @@ -53,8 +53,7 @@ use runtime_parachains::scheduler as parachains_scheduler; use runtime_parachains::reward_points as parachains_reward_points; use runtime_parachains::runtime_api_impl::v1 as parachains_runtime_api_impl; -use xcm::v0::{MultiLocation::{self, Null, X1}, NetworkId, Xcm, Junction::Parachain}; -use xcm::v0::MultiAsset::{self, AllConcreteFungible}; +use xcm::v0::prelude::*; use xcm_executor::XcmExecutor; use xcm_builder::{ AccountId32Aliases, ChildParachainConvertsVia, SovereignSignedViaLocation, CurrencyAdapter as XcmCurrencyAdapter, @@ -907,8 +906,8 @@ pub type XcmRouter = ( ); parameter_types! { - pub const WestendForWestmint: (MultiAsset, MultiLocation) = - (AllConcreteFungible { id: Null }, X1(Parachain(1000))); + pub const WestendForWestmint: (MultiAssetFilter, MultiLocation) = + (Wild(AllOf(WildFungible, Concrete(WndLocation::get()))), X1(Parachain(1000))); } pub type TrustedTeleporters = ( xcm_builder::Case<WestendForWestmint>, @@ -946,52 +945,6 @@ pub type LocalOriginToLocation = ( SignedToAccountId32<Origin, AccountId, WestendNetwork>, ); -pub struct OnlyWithdrawTeleportForAccounts; -impl frame_support::traits::Contains<(MultiLocation, Xcm<Call>)> for OnlyWithdrawTeleportForAccounts { - fn contains((ref origin, ref msg): &(MultiLocation, Xcm<Call>)) -> bool { - use xcm::v0::{ - Xcm::WithdrawAsset, Order::{BuyExecution, InitiateTeleport, DepositAsset}, - MultiAsset::{All, ConcreteFungible}, Junction::AccountId32, - }; - match origin { - // Root is allowed to execute anything. - Null => true, - X1(AccountId32 { .. }) => { - // An account ID trying to send a message. We ensure that it's sensible. - // This checks that it's of the form: - // WithdrawAsset { - // assets: [ ConcreteFungible { id: Null } ], - // effects: [ BuyExecution, InitiateTeleport { - // assets: All, - // dest: Parachain, - // effects: [ BuyExecution, DepositAssets { - // assets: All, - // dest: AccountId32, - // } ] - // } ] - // } - matches!(msg, WithdrawAsset { ref assets, ref effects } - if assets.len() == 1 - && matches!(assets[0], ConcreteFungible { id: Null, .. }) - && effects.len() == 2 - && matches!(effects[0], BuyExecution { .. }) - && matches!(effects[1], InitiateTeleport { ref assets, dest: X1(Parachain(..)), ref effects } - if assets.len() == 1 - && matches!(assets[0], All) - && effects.len() == 2 - && matches!(effects[0], BuyExecution { .. }) - && matches!(effects[1], DepositAsset { ref assets, dest: X1(AccountId32{..}) } - if assets.len() == 1 - && matches!(assets[0], All) - ) - ) - ) - } - // Nobody else is allowed to execute anything. - _ => false, - } - } -} impl pallet_xcm::Config for Runtime { type Event = Event; @@ -999,8 +952,8 @@ impl pallet_xcm::Config for Runtime { type XcmRouter = XcmRouter; // Anyone can execute XCM messages locally... type ExecuteXcmOrigin = xcm_builder::EnsureXcmOrigin<Origin, LocalOriginToLocation>; - // ...but they must match our filter, which requires them to be a simple withdraw + teleport. - type XcmExecuteFilter = OnlyWithdrawTeleportForAccounts; + // ...but they must match our filter, which rejects everything. + type XcmExecuteFilter = (); type XcmExecutor = XcmExecutor<XcmConfig>; type XcmTeleportFilter = All<(MultiLocation, Vec<MultiAsset>)>; type XcmReserveTransferFilter = All<(MultiLocation, Vec<MultiAsset>)>; diff --git a/xcm/pallet-xcm/src/lib.rs b/xcm/pallet-xcm/src/lib.rs index a99d630fefe3..77c004b58844 100644 --- a/xcm/pallet-xcm/src/lib.rs +++ b/xcm/pallet-xcm/src/lib.rs @@ -123,7 +123,7 @@ pub mod pallet { let mut message = Xcm::WithdrawAsset { assets: assets.clone(), effects: sp_std::vec![ InitiateTeleport { - assets: sp_std::vec![ All ], + assets: Wild(All), dest: dest.clone(), effects: sp_std::vec![], } ] @@ -134,18 +134,19 @@ pub mod pallet { origin: OriginFor<T>, dest: MultiLocation, beneficiary: MultiLocation, - assets: Vec<MultiAsset>, + assets: MultiAssets, dest_weight: Weight, ) -> DispatchResult { let origin_location = T::ExecuteXcmOrigin::ensure_origin(origin)?; - let value = (origin_location, assets); + let value = (origin_location, assets.drain()); ensure!(T::XcmTeleportFilter::contains(&value), Error::<T>::Filtered); let (origin_location, assets) = value; + let assets = assets.into(); let mut message = Xcm::WithdrawAsset { assets, effects: vec![ InitiateTeleport { - assets: vec![ All ], + assets: Wild(All), dest, effects: vec![ BuyExecution { @@ -156,7 +157,7 @@ pub mod pallet { halt_on_error: false, xcm: vec![], }, - DepositAsset { assets: vec![ All ], dest: beneficiary }, + DepositAsset { assets: Wild(All), dest: beneficiary }, ], }, ], @@ -179,7 +180,7 @@ pub mod pallet { /// - `assets`: The assets to be withdrawn. This should include the assets used to pay the fee on the /// `dest` side. /// - `dest_weight`: Equal to the total weight on `dest` of the XCM message - /// `ReserveAssetDeposit { assets, effects: [ BuyExecution{..}, DepositAsset{..} ] }`. + /// `ReserveAssetDeposited { assets, effects: [ BuyExecution{..}, DepositAsset{..} ] }`. #[pallet::weight({ let mut message = Xcm::TransferReserveAsset { assets: assets.clone(), @@ -192,13 +193,14 @@ pub mod pallet { origin: OriginFor<T>, dest: MultiLocation, beneficiary: MultiLocation, - assets: Vec<MultiAsset>, + assets: MultiAssets, dest_weight: Weight, ) -> DispatchResult { let origin_location = T::ExecuteXcmOrigin::ensure_origin(origin)?; - let value = (origin_location, assets); + let value = (origin_location, assets.drain()); ensure!(T::XcmReserveTransferFilter::contains(&value), Error::<T>::Filtered); let (origin_location, assets) = value; + let assets = assets.into(); let mut message = Xcm::TransferReserveAsset { assets, dest, @@ -211,7 +213,7 @@ pub mod pallet { halt_on_error: false, xcm: vec![], }, - DepositAsset { assets: vec![ All ], dest: beneficiary }, + DepositAsset { assets: Wild(All), dest: beneficiary }, ], }; let weight = T::Weigher::weight(&mut message) diff --git a/xcm/src/v0/mod.rs b/xcm/src/v0/mod.rs index 2d4c192d3ec0..38d940a16a19 100644 --- a/xcm/src/v0/mod.rs +++ b/xcm/src/v0/mod.rs @@ -23,7 +23,6 @@ use parity_scale_codec::{self, Encode, Decode}; use crate::{DoubleEncoded, VersionedXcm}; mod junction; -mod multi_asset; mod multi_location; mod order; mod traits; @@ -41,7 +40,8 @@ pub use traits::{Error, Result, SendXcm, ExecuteXcm, Outcome}; pub mod prelude { pub use super::junction::{Junction::*, NetworkId, BodyId, BodyPart}; pub use super::multiasset::{ - AssetId, MultiAssets, MultiAsset, + MultiAssets, MultiAsset, + AssetId::{self, *}, AssetInstance::{self, *}, MultiAssetFilter::{self, *}, Fungibility::{self, *}, @@ -104,7 +104,7 @@ pub enum Xcm<Call> { /// orders (`effects`). /// /// - `assets`: The asset(s) to be withdrawn into holding. - /// - `effects`: The order(s) to execute on the holding account. + /// - `effects`: The order(s) to execute on the holding register. /// /// Kind: *Instruction*. /// @@ -118,7 +118,7 @@ pub enum Xcm<Call> { /// been placed into `holding`. /// /// - `assets`: The asset(s) that are minted into holding. - /// - `effects`: The order(s) to execute on the holding account. + /// - `effects`: The order(s) to execute on the holding register. /// /// Safety: `origin` must be trusted to have received and be storing `assets` such that they may later be /// withdrawn should this system send a corresponding message. @@ -127,7 +127,7 @@ pub enum Xcm<Call> { /// /// Errors: #[codec(index = 1)] - ReserveAssetDeposit { assets: MultiAssets, effects: Vec<Order<Call>> }, + ReserveAssetDeposited { assets: MultiAssets, effects: Vec<Order<Call>> }, /// Asset(s) (`assets`) have been destroyed on the `origin` system and equivalent assets should be /// created on this system. @@ -136,7 +136,7 @@ pub enum Xcm<Call> { /// been placed into `holding`. /// /// - `assets`: The asset(s) that are minted into holding. - /// - `effects`: The order(s) to execute on the holding account. + /// - `effects`: The order(s) to execute on the holding register. /// /// Safety: `origin` must be trusted to have irrevocably destroyed the `assets` prior as a consequence of /// sending this message. @@ -147,7 +147,7 @@ pub enum Xcm<Call> { #[codec(index = 2)] TeleportAsset { assets: MultiAssets, effects: Vec<Order<Call>> }, - /// Indication of the contents of the holding account corresponding to the `QueryHolding` order of `query_id`. + /// Indication of the contents of the holding register corresponding to the `QueryHolding` order of `query_id`. /// /// - `query_id`: The identifier of the query that resulted in this message being sent. /// - `assets`: The message content. @@ -177,11 +177,11 @@ pub enum Xcm<Call> { /// Withdraw asset(s) (`assets`) from the ownership of `origin` and place equivalent assets under the /// ownership of `dest` within this consensus system. /// - /// Send an onward XCM message to `dest` of `ReserveAssetDeposit` with the given `effects`. + /// Send an onward XCM message to `dest` of `ReserveAssetDeposited` with the given `effects`. /// /// - `assets`: The asset(s) to be withdrawn. /// - `dest`: The new owner for the assets. - /// - `effects`: The orders that should be contained in the `ReserveAssetDeposit` which is sent onwards to + /// - `effects`: The orders that should be contained in the `ReserveAssetDeposited` which is sent onwards to /// `dest`. /// /// Safety: No concerns. @@ -294,8 +294,8 @@ impl<Call> Xcm<Call> { match xcm { WithdrawAsset { assets, effects } => WithdrawAsset { assets, effects: effects.into_iter().map(Order::into).collect() }, - ReserveAssetDeposit { assets, effects } - => ReserveAssetDeposit { assets, effects: effects.into_iter().map(Order::into).collect() }, + ReserveAssetDeposited { assets, effects } + => ReserveAssetDeposited { assets, effects: effects.into_iter().map(Order::into).collect() }, TeleportAsset { assets, effects } => TeleportAsset { assets, effects: effects.into_iter().map(Order::into).collect() }, QueryResponse { query_id: u64, response } diff --git a/xcm/src/v0/multi_asset.rs b/xcm/src/v0/multi_asset.rs deleted file mode 100644 index fe53f6905aa5..000000000000 --- a/xcm/src/v0/multi_asset.rs +++ /dev/null @@ -1,337 +0,0 @@ -// 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 <http://www.gnu.org/licenses/>. - -//! Cross-Consensus Message format data structures. - -use alloc::vec::Vec; - -use parity_scale_codec::{self, Encode, Decode}; -use super::{MultiLocation, AssetInstance}; - -/// A single general identifier for an asset. -/// -/// Represents both fungible and non-fungible assets. May only be used to represent a single asset class. -/// -/// Wildcards may or may not be allowed by the interpreting context. -/// -/// Assets classes may be identified in one of two ways: either an abstract identifier or a concrete identifier. -/// Implementations may support only one of these. A single asset may be referenced from multiple asset identifiers, -/// though will tend to have only a single *preferred* identifier. -/// -/// ### Abstract identifiers -/// -/// Abstract identifiers are absolute identifiers that represent a notional asset which can exist within multiple -/// consensus systems. These tend to be simpler to deal with since their broad meaning is unchanged regardless stay of -/// the consensus system in which it is interpreted. -/// -/// However, in the attempt to provide uniformity across consensus systems, they may conflate different instantiations -/// of some notional asset (e.g. the reserve asset and a local reserve-backed derivative of it) under the same name, -/// leading to confusion. It also implies that one notional asset is accounted for locally in only one way. This may not -/// be the case, e.g. where there are multiple bridge instances each providing a bridged "BTC" token yet none being -/// fungible between the others. -/// -/// Since they are meant to be absolute and universal, a global registry is needed to ensure that name collisions do not -/// occur. -/// -/// An abstract identifier is represented as a simple variable-size byte string. As of writing, no global registry -/// exists and no proposals have been put forth for asset labeling. -/// -/// ### Concrete identifiers -/// -/// Concrete identifiers are *relative identifiers* that specifically identify a single asset through its location in a -/// consensus system relative to the context interpreting. Use of a `MultiLocation` ensures that similar but non -/// fungible variants of the same underlying asset can be properly distinguished, and obviates the need for any kind of -/// central registry. -/// -/// The limitation is that the asset identifier cannot be trivially copied between consensus systems and must instead be -/// "re-anchored" whenever being moved to a new consensus system, using the two systems' relative paths. -/// -/// Throughout XCM, messages are authored such that *when interpreted from the receiver's point of view* they will have -/// the desired meaning/effect. This means that relative paths should always by constructed to be read from the point of -/// view of the receiving system, *which may be have a completely different meaning in the authoring system*. -/// -/// Concrete identifiers are the preferred way of identifying an asset since they are entirely unambiguous. -/// -/// A concrete identifier is represented by a `MultiLocation`. If a system has an unambiguous primary asset (such as -/// Bitcoin with BTC or Ethereum with ETH), then it will conventionally be identified as the chain itself. Alternative -/// and more specific ways of referring to an asset within a system include: -/// -/// - `<chain>/PalletInstance(<id>)` for a Frame chain with a single-asset pallet instance (such as an instance of the -/// Balances pallet). -/// - `<chain>/PalletInstance(<id>)/GeneralIndex(<index>)` for a Frame chain with an indexed multi-asset pallet instance -/// (such as an instance of the Assets pallet). -/// - `<chain>/AccountId32` for an ERC-20-style single-asset smart-contract on a Frame-based contracts chain. -/// - `<chain>/AccountKey20` for an ERC-20-style single-asset smart-contract on an Ethereum-like chain. -/// -#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug)] -pub enum MultiAsset { - /// No assets. Rarely used. - None, - - /// All assets. Typically used for the subset of assets to be used for an `Order`, and in that context means - /// "all assets currently in holding". - All, - - /// All fungible assets. Typically used for the subset of assets to be used for an `Order`, and in that context - /// means "all fungible assets currently in holding". - AllFungible, - - /// All non-fungible assets. Typically used for the subset of assets to be used for an `Order`, and in that - /// context means "all non-fungible assets currently in holding". - AllNonFungible, - - /// All fungible assets of a given abstract asset `id`entifier. - AllAbstractFungible { id: Vec<u8> }, - - /// All non-fungible assets of a given abstract asset `class`. - AllAbstractNonFungible { class: Vec<u8> }, - - /// All fungible assets of a given concrete asset `id`entifier. - AllConcreteFungible { id: MultiLocation }, - - /// All non-fungible assets of a given concrete asset `class`. - AllConcreteNonFungible { class: MultiLocation }, - - /// Some specific `amount` of the fungible asset identified by an abstract `id`. - AbstractFungible { id: Vec<u8>, #[codec(compact)] amount: u128 }, - - /// Some specific `instance` of the non-fungible asset whose `class` is identified abstractly. - AbstractNonFungible { class: Vec<u8>, instance: AssetInstance }, - - /// Some specific `amount` of the fungible asset identified by an concrete `id`. - ConcreteFungible { id: MultiLocation, #[codec(compact)] amount: u128 }, - - /// Some specific `instance` of the non-fungible asset whose `class` is identified concretely. - ConcreteNonFungible { class: MultiLocation, instance: AssetInstance }, -} - -impl MultiAsset { - /// Returns `true` if the `MultiAsset` is a wildcard and can refer to classes of assets, instead of just one. - /// - /// Typically can also be inferred by the name starting with `All`. - pub fn is_wildcard(&self) -> bool { - match self { - MultiAsset::None - | MultiAsset::AbstractFungible {..} - | MultiAsset::AbstractNonFungible {..} - | MultiAsset::ConcreteFungible {..} - | MultiAsset::ConcreteNonFungible {..} - => false, - - MultiAsset::All - | MultiAsset::AllFungible - | MultiAsset::AllNonFungible - | MultiAsset::AllAbstractFungible {..} - | MultiAsset::AllConcreteFungible {..} - | MultiAsset::AllAbstractNonFungible {..} - | MultiAsset::AllConcreteNonFungible {..} - => true, - } - } - - fn is_none(&self) -> bool { - match self { - MultiAsset::None - | MultiAsset::AbstractFungible { amount: 0, .. } - | MultiAsset::ConcreteFungible { amount: 0, .. } - => true, - - _ => false, - } - } - - fn is_fungible(&self) -> bool { - match self { - MultiAsset::All - | MultiAsset::AllFungible - | MultiAsset::AllAbstractFungible {..} - | MultiAsset::AllConcreteFungible {..} - | MultiAsset::AbstractFungible {..} - | MultiAsset::ConcreteFungible {..} - => true, - - _ => false, - } - } - - fn is_non_fungible(&self) -> bool { - match self { - MultiAsset::All - | MultiAsset::AllNonFungible - | MultiAsset::AllAbstractNonFungible {..} - | MultiAsset::AllConcreteNonFungible {..} - | MultiAsset::AbstractNonFungible {..} - | MultiAsset::ConcreteNonFungible {..} - => true, - - _ => false, - } - } - - fn is_concrete_fungible(&self, id: &MultiLocation) -> bool { - match self { - MultiAsset::AllFungible => true, - MultiAsset::AllConcreteFungible { id: i } - | MultiAsset::ConcreteFungible { id: i, .. } - => i == id, - - _ => false, - } - } - - fn is_abstract_fungible(&self, id: &[u8]) -> bool { - match self { - MultiAsset::AllFungible => true, - MultiAsset::AllAbstractFungible { id: i } - | MultiAsset::AbstractFungible { id: i, .. } - => i == id, - _ => false, - } - } - - fn is_concrete_non_fungible(&self, class: &MultiLocation) -> bool { - match self { - MultiAsset::AllNonFungible => true, - MultiAsset::AllConcreteNonFungible { class: i } - | MultiAsset::ConcreteNonFungible { class: i, .. } - => i == class, - _ => false, - } - } - - fn is_abstract_non_fungible(&self, class: &[u8]) -> bool { - match self { - MultiAsset::AllNonFungible => true, - MultiAsset::AllAbstractNonFungible { class: i } - | MultiAsset::AbstractNonFungible { class: i, .. } - => i == class, - _ => false, - } - } - - fn is_all(&self) -> bool { matches!(self, MultiAsset::All) } - - /// Returns true if `self` is a super-set of the given `inner`. - /// - /// Typically, any wildcard is never contained in anything else, and a wildcard can contain any other non-wildcard. - /// For more details, see the implementation and tests. - pub fn contains(&self, inner: &MultiAsset) -> bool { - use MultiAsset::*; - - // Inner cannot be wild - if inner.is_wildcard() { return false } - // Everything contains nothing. - if inner.is_none() { return true } - - // Everything contains anything. - if self.is_all() { return true } - // Nothing contains nothing. - if self.is_none() { return false } - - match self { - // Anything fungible contains "all fungibles" - AllFungible => inner.is_fungible(), - // Anything non-fungible contains "all non-fungibles" - AllNonFungible => inner.is_non_fungible(), - - AllConcreteFungible { id } => inner.is_concrete_fungible(id), - AllAbstractFungible { id } => inner.is_abstract_fungible(id), - AllConcreteNonFungible { class } => inner.is_concrete_non_fungible(class), - AllAbstractNonFungible { class } => inner.is_abstract_non_fungible(class), - - ConcreteFungible { id, amount } => matches!( - inner, - ConcreteFungible { id: inner_id , amount: inner_amount } if inner_id == id && amount >= inner_amount - ), - AbstractFungible { id, amount } => matches!( - inner, - AbstractFungible { id: inner_id , amount: inner_amount } if inner_id == id && amount >= inner_amount - ), - ConcreteNonFungible { .. } => self == inner, - AbstractNonFungible { .. } => self == inner, - _ => false, - } - } - - pub fn reanchor(&mut self, prepend: &MultiLocation) -> Result<(), ()> { - use MultiAsset::*; - match self { - AllConcreteFungible { ref mut id } - | AllConcreteNonFungible { class: ref mut id } - | ConcreteFungible { ref mut id, .. } - | ConcreteNonFungible { class: ref mut id, .. } - => id.prepend_with(prepend.clone()).map_err(|_| ()), - _ => Ok(()), - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn contains_works() { - use alloc::vec; - use MultiAsset::*; - // trivial case: all contains any non-wildcard. - assert!(All.contains(&None)); - assert!(All.contains(&AbstractFungible { id: alloc::vec![99u8], amount: 1 })); - - // trivial case: none contains nothing, except itself. - assert!(None.contains(&None)); - assert!(!None.contains(&AllFungible)); - assert!(!None.contains(&All)); - - // A bit more sneaky: Nothing can contain wildcard, even All ir the thing itself. - assert!(!All.contains(&All)); - assert!(!All.contains(&AllFungible)); - assert!(!AllFungible.contains(&AllFungible)); - assert!(!AllNonFungible.contains(&AllNonFungible)); - - // For fungibles, containing is basically equality, or equal id with higher amount. - assert!( - !AbstractFungible { id: vec![99u8], amount: 99 } - .contains(&AbstractFungible { id: vec![1u8], amount: 99 }) - ); - assert!( - AbstractFungible { id: vec![99u8], amount: 99 } - .contains(&AbstractFungible { id: vec![99u8], amount: 99 }) - ); - assert!( - AbstractFungible { id: vec![99u8], amount: 99 } - .contains(&AbstractFungible { id: vec![99u8], amount: 9 }) - ); - assert!( - !AbstractFungible { id: vec![99u8], amount: 99 } - .contains(&AbstractFungible { id: vec![99u8], amount: 100 }) - ); - - // For non-fungibles, containing is equality. - assert!( - !AbstractNonFungible {class: vec![99u8], instance: AssetInstance::Index { id: 9 } } - .contains(&AbstractNonFungible { class: vec![98u8], instance: AssetInstance::Index { id: 9 } }) - ); - assert!( - !AbstractNonFungible { class: vec![99u8], instance: AssetInstance::Index { id: 8 } } - .contains(&AbstractNonFungible { class: vec![99u8], instance: AssetInstance::Index { id: 9 } }) - ); - assert!( - AbstractNonFungible { class: vec![99u8], instance: AssetInstance::Index { id: 9 } } - .contains(&AbstractNonFungible { class: vec![99u8], instance: AssetInstance::Index { id: 9 } }) - ); - } -} diff --git a/xcm/src/v0/multiasset.rs b/xcm/src/v0/multiasset.rs index c877f71a0dc6..32b36f73a296 100644 --- a/xcm/src/v0/multiasset.rs +++ b/xcm/src/v0/multiasset.rs @@ -23,13 +23,10 @@ //! - `MultiAssetFilter`: A combination of `Wild` and `MultiAssets` designed for efficiently filtering an XCM holding //! account. -use core::convert::{TryFrom, TryInto}; +use core::cmp::Ordering; use alloc::{vec, vec::Vec}; use parity_scale_codec::{self as codec, Encode, Decode}; -use super::{ - MultiLocation, multi_asset::MultiAsset as OldMultiAsset, -}; -use core::cmp::Ordering; +use super::MultiLocation; /// A general identifier for an instance of a non-fungible asset class. #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug)] @@ -58,7 +55,7 @@ pub enum AssetInstance { } /// Classification of an asset being concrete or abstract. -#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)] +#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, Decode)] pub enum AssetId { Concrete(MultiLocation), Abstract(Vec<u8>), @@ -98,7 +95,7 @@ impl AssetId { } /// Classification of whether an asset is fungible or not, along with an mandatory amount or instance. -#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)] +#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, Decode)] pub enum Fungibility { Fungible(u128), NonFungible(AssetInstance), @@ -127,7 +124,7 @@ impl From<AssetInstance> for Fungibility { -#[derive(Clone, Eq, PartialEq, Debug)] +#[derive(Clone, Eq, PartialEq, Debug, Encode, Decode)] pub struct MultiAsset { pub id: AssetId, pub fun: Fungibility, @@ -155,45 +152,6 @@ impl<A: Into<AssetId>, B: Into<Fungibility>> From<(A, B)> for MultiAsset { } } -impl From<MultiAsset> for OldMultiAsset { - fn from(a: MultiAsset) -> Self { - use {AssetId::*, Fungibility::*, OldMultiAsset::*}; - match (a.fun, a.id) { - (Fungible(amount), Concrete(id)) => ConcreteFungible { id, amount }, - (Fungible(amount), Abstract(id)) => AbstractFungible { id, amount }, - (NonFungible(instance), Concrete(class)) => ConcreteNonFungible { class, instance }, - (NonFungible(instance), Abstract(class)) => AbstractNonFungible { class, instance }, - } - } -} - -impl TryFrom<OldMultiAsset> for MultiAsset { - type Error = (); - fn try_from(a: OldMultiAsset) -> Result<Self, ()> { - use {AssetId::*, Fungibility::*, OldMultiAsset::*}; - let (fun, id) = match a { - ConcreteFungible { id, amount } if amount > 0 => (Fungible(amount), Concrete(id)), - AbstractFungible { id, amount } if amount > 0 => (Fungible(amount), Abstract(id)), - ConcreteNonFungible { class, instance } => (NonFungible(instance), Concrete(class)), - AbstractNonFungible { class, instance } => (NonFungible(instance), Abstract(class)), - _ => return Err(()), - }; - Ok(MultiAsset { fun, id }) - } -} - -impl Encode for MultiAsset { - fn encode(&self) -> Vec<u8> { - OldMultiAsset::from(self.clone()).encode() - } -} - -impl Decode for MultiAsset { - fn decode<I: codec::Input>(input: &mut I) -> Result<Self, parity_scale_codec::Error> { - OldMultiAsset::decode(input)?.try_into().map_err(|_| "Unsupported wildcard".into()) - } -} - impl MultiAsset { pub fn is_fungible(&self, maybe_id: Option<AssetId>) -> bool { use Fungibility::*; @@ -238,7 +196,7 @@ impl Decode for MultiAssets { if a.id < b.id || a < b && (a.is_non_fungible(None) || b.is_non_fungible(None)) { Ok(b) } else { - Err("Unsupported wildcard".into()) + Err("Out of order".into()) } })?; Ok(Self(r)) @@ -251,19 +209,6 @@ impl From<Vec<MultiAsset>> for MultiAssets { } } -impl From<MultiAssets> for Vec<OldMultiAsset> { - fn from(a: MultiAssets) -> Self { - a.0.into_iter().map(OldMultiAsset::from).collect() - } -} - -impl TryFrom<Vec<OldMultiAsset>> for MultiAssets { - type Error = (); - fn try_from(a: Vec<OldMultiAsset>) -> Result<Self, ()> { - a.into_iter().map(MultiAsset::try_from).collect::<Result<_, _>>().map(Self) - } -} - impl MultiAssets { /// A new (empty) value. pub fn new() -> Self { @@ -315,59 +260,23 @@ impl MultiAssets { /// Classification of whether an asset is fungible or not, along with an optional amount or instance. -#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug)] +#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, Decode)] pub enum WildFungibility { Fungible, NonFungible, } -#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)] +#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, Decode)] pub enum WildMultiAsset { + /// All assets in the holding register, up to usize individual assets (different instances of non-fungibles could + /// as separate assets). All, // TODO: AllOf { fun: WildFungibility, id: AssetId } + /// All assets in the holding register of a given fungibility and ID. If operating on non-fungibles, then a limit + /// is provided for the maximum amount of matching instances. AllOf(WildFungibility, AssetId), } -impl Encode for WildMultiAsset { - fn encode(&self) -> Vec<u8> { - OldMultiAsset::from(self.clone()).encode() - } -} - -impl Decode for WildMultiAsset { - fn decode<I: codec::Input>(input: &mut I) -> Result<Self, parity_scale_codec::Error> { - OldMultiAsset::decode(input)?.try_into().map_err(|()| "Invalid wildcard item".into()) - } -} - -impl From<WildMultiAsset> for OldMultiAsset { - fn from(a: WildMultiAsset) -> Self { - use {AssetId::*, WildFungibility::*, OldMultiAsset::*, WildMultiAsset::AllOf}; - match a { - WildMultiAsset::All => All, - AllOf(Fungible, Concrete(id)) => AllConcreteFungible { id }, - AllOf(Fungible, Abstract(id)) => AllAbstractFungible { id }, - AllOf(NonFungible, Concrete(class)) => AllConcreteNonFungible { class }, - AllOf(NonFungible, Abstract(class)) => AllAbstractNonFungible { class }, - } - } -} - -impl TryFrom<OldMultiAsset> for WildMultiAsset { - type Error = (); - fn try_from(a: OldMultiAsset) -> Result<Self, ()> { - use {AssetId::*, WildFungibility::*, OldMultiAsset::*, WildMultiAsset::AllOf}; - Ok(match a { - All => WildMultiAsset::All, - AllConcreteFungible { id } => AllOf(Fungible, Concrete(id)), - AllAbstractFungible { id } => AllOf(Fungible, Abstract(id)), - AllConcreteNonFungible { class } => AllOf(NonFungible, Concrete(class)), - AllAbstractNonFungible { class } => AllOf(NonFungible, Abstract(class)), - _ => return Err(()), - }) - } -} - impl WildMultiAsset { /// Returns true if `self` is a super-set of the given `inner`. /// @@ -391,15 +300,20 @@ impl WildMultiAsset { } } +impl<A: Into<AssetId>, B: Into<WildFungibility>> From<(A, B)> for WildMultiAsset { + fn from((id, fun): (A, B)) -> WildMultiAsset { + WildMultiAsset::AllOf(fun.into(), id.into()) + } +} /// `MultiAsset` collection, either `MultiAssets` or a single wildcard. Note: vectors of wildcards /// whose encoding is supported in XCM v0 are unsupported in this implementation and will result in a decode error. -#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)] +#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, Decode)] pub enum MultiAssetFilter { - Assets(MultiAssets), + Definite(MultiAssets), Wild(WildMultiAsset), } @@ -411,50 +325,13 @@ impl From<WildMultiAsset> for MultiAssetFilter { impl From<MultiAsset> for MultiAssetFilter { fn from(x: MultiAsset) -> Self { - Self::Assets(vec![x].into()) + Self::Definite(vec![x].into()) } } impl From<MultiAssets> for MultiAssetFilter { fn from(x: MultiAssets) -> Self { - Self::Assets(x) - } -} - -impl From<MultiAssetFilter> for Vec<OldMultiAsset> { - fn from(a: MultiAssetFilter) -> Self { - use MultiAssetFilter::*; - match a { - Assets(assets) => assets.0.into_iter().map(OldMultiAsset::from).collect(), - Wild(wild) => vec![wild.into()], - } - } -} - -impl TryFrom<Vec<OldMultiAsset>> for MultiAssetFilter { - type Error = (); - fn try_from(mut old_assets: Vec<OldMultiAsset>) -> Result<Self, ()> { - use MultiAssetFilter::*; - if old_assets.is_empty() { - return Ok(Assets(MultiAssets::new())) - } - if old_assets.len() == 1 && old_assets[0].is_wildcard() { - return old_assets.pop().ok_or(()).and_then(|i| Ok(Wild(i.try_into()?))) - } - - MultiAssets::try_from(old_assets).map(Self::Assets) - } -} - -impl Encode for MultiAssetFilter { - fn encode(&self) -> Vec<u8> { - Vec::<OldMultiAsset>::from(self.clone()).encode() - } -} - -impl Decode for MultiAssetFilter { - fn decode<I: codec::Input>(input: &mut I) -> Result<Self, parity_scale_codec::Error> { - Vec::<OldMultiAsset>::decode(input)?.try_into().map_err(|()| "Invalid items".into()) + Self::Definite(x) } } @@ -471,7 +348,7 @@ impl MultiAssetFilter { /// Returns `true` if this definitely represents no asset. pub fn is_none(&self) -> bool { - matches!(self, MultiAssetFilter::Assets(a) if a.is_none()) + matches!(self, MultiAssetFilter::Definite(a) if a.is_none()) } /// Returns true if `self` is a super-set of the given `inner`. @@ -480,7 +357,7 @@ impl MultiAssetFilter { /// For more details, see the implementation and tests. pub fn contains(&self, inner: &MultiAsset) -> bool { match self { - MultiAssetFilter::Assets(ref assets) => assets.contains(inner), + MultiAssetFilter::Definite(ref assets) => assets.contains(inner), MultiAssetFilter::Wild(ref wild) => wild.contains(inner), } } @@ -488,7 +365,7 @@ impl MultiAssetFilter { /// Prepend a `MultiLocation` to any concrete asset components, giving it a new root location. pub fn reanchor(&mut self, prepend: &MultiLocation) -> Result<(), ()> { match self { - MultiAssetFilter::Assets(ref mut assets) => assets.reanchor(prepend), + MultiAssetFilter::Definite(ref mut assets) => assets.reanchor(prepend), MultiAssetFilter::Wild(ref mut wild) => wild.reanchor(prepend), } } diff --git a/xcm/src/v0/order.rs b/xcm/src/v0/order.rs index fa8aa6df3393..6ee6eb20f9bc 100644 --- a/xcm/src/v0/order.rs +++ b/xcm/src/v0/order.rs @@ -44,11 +44,11 @@ pub enum Order<Call> { /// Remove the asset(s) (`assets`) from holding and place equivalent assets under the ownership of `dest` within /// this consensus system. /// - /// Send an onward XCM message to `dest` of `ReserveAssetDeposit` with the given `effects`. + /// Send an onward XCM message to `dest` of `ReserveAssetDeposited` with the given `effects`. /// /// - `assets`: The asset(s) to remove from holding. /// - `dest`: The new owner for the assets. - /// - `effects`: The orders that should be contained in the `ReserveAssetDeposit` which is sent onwards to + /// - `effects`: The orders that should be contained in the `ReserveAssetDeposited` which is sent onwards to /// `dest`. /// /// Errors: @@ -93,7 +93,7 @@ pub enum Order<Call> { /// - `query_id`: An identifier that will be replicated into the returned XCM message. /// - `dest`: A valid destination for the returned XCM message. This may be limited to the current origin. /// - `assets`: A filter for the assets that should be reported back. The assets reported back will be, asset- - /// wise, *the lesser of this value and the holding account*. No wildcards will be used when reporting assets + /// wise, *the lesser of this value and the holding register*. No wildcards will be used when reporting assets /// back. /// /// Errors: @@ -101,7 +101,7 @@ pub enum Order<Call> { QueryHolding { #[codec(compact)] query_id: u64, dest: MultiLocation, assets: MultiAssetFilter }, /// Pay for the execution of some XCM with up to `weight` picoseconds of execution time, paying for this with - /// up to `fees` from the holding account. + /// up to `fees` from the holding register. /// /// - `fees`: The asset(s) to remove from holding to pay for fees. /// diff --git a/xcm/src/v0/traits.rs b/xcm/src/v0/traits.rs index 9a01f227e766..24bfe84db853 100644 --- a/xcm/src/v0/traits.rs +++ b/xcm/src/v0/traits.rs @@ -62,7 +62,7 @@ pub enum Error { /// Used by: /// - `Transact` TooMuchWeightRequired, - /// The fees specified by the XCM message were not found in the holding account. + /// The fees specified by the XCM message were not found in the holding register. /// /// Used by: /// - `BuyExecution` diff --git a/xcm/xcm-builder/src/barriers.rs b/xcm/xcm-builder/src/barriers.rs index ea3d80660940..0a48ad6c42e2 100644 --- a/xcm/xcm-builder/src/barriers.rs +++ b/xcm/xcm-builder/src/barriers.rs @@ -53,11 +53,11 @@ impl<T: Contains<MultiLocation>> ShouldExecute for AllowTopLevelPaidExecutionFro match message { Xcm::TeleportAsset { effects, .. } | Xcm::WithdrawAsset { effects, ..} - | Xcm::ReserveAssetDeposit { effects, ..} + | Xcm::ReserveAssetDeposited { effects, ..} if matches!( - effects.first(), - Some(Order::BuyExecution { debt, ..}) if *debt >= shallow_weight - ) + effects.first(), + Some(Order::BuyExecution { debt, ..}) if *debt >= shallow_weight + ) => Ok(()), _ => Err(()), } diff --git a/xcm/xcm-builder/src/filter_asset_location.rs b/xcm/xcm-builder/src/filter_asset_location.rs index e095b9dbbc73..462b9421e35a 100644 --- a/xcm/xcm-builder/src/filter_asset_location.rs +++ b/xcm/xcm-builder/src/filter_asset_location.rs @@ -17,7 +17,7 @@ //! Various implementations of `FilterAssetLocation`. use sp_std::marker::PhantomData; -use xcm::v0::{MultiAsset, MultiLocation, AssetId::Concrete}; +use xcm::v0::{MultiAsset, MultiAssetFilter, MultiLocation, AssetId::Concrete}; use frame_support::traits::Get; use xcm_executor::traits::FilterAssetLocation; @@ -31,7 +31,7 @@ impl FilterAssetLocation for NativeAsset { /// Accepts an asset if it is contained in the given `T`'s `Get` implementation. pub struct Case<T>(PhantomData<T>); -impl<T: Get<(MultiAsset, MultiLocation)>> FilterAssetLocation for Case<T> { +impl<T: Get<(MultiAssetFilter, MultiLocation)>> FilterAssetLocation for Case<T> { fn filter_asset_location(asset: &MultiAsset, origin: &MultiLocation) -> bool { let (a, o) = T::get(); a.contains(asset) && &o == origin diff --git a/xcm/xcm-builder/src/tests.rs b/xcm/xcm-builder/src/tests.rs index 0f04b89285d1..79235427be62 100644 --- a/xcm/xcm-builder/src/tests.rs +++ b/xcm/xcm-builder/src/tests.rs @@ -39,7 +39,7 @@ fn basic_setup_works() { #[test] fn weigher_should_work() { - let mut message = opaque::Xcm::ReserveAssetDeposit { + let mut message = opaque::Xcm::ReserveAssetDeposited { assets: vec![ConcreteFungible { id: X1(Parent), amount: 100 }], effects: vec![ Order::BuyExecution { fees: All, weight: 0, debt: 30, halt_on_error: true, xcm: vec![] }, @@ -124,7 +124,7 @@ fn allow_paid_should_work() { ); assert_eq!(r, Err(())); - let mut underpaying_message = opaque::Xcm::ReserveAssetDeposit { + let mut underpaying_message = opaque::Xcm::ReserveAssetDeposited { assets: vec![ConcreteFungible { id: X1(Parent), amount: 100 }], effects: vec![ Order::BuyExecution { fees: All, weight: 0, debt: 20, halt_on_error: true, xcm: vec![] }, @@ -141,7 +141,7 @@ fn allow_paid_should_work() { ); assert_eq!(r, Err(())); - let mut paying_message = opaque::Xcm::ReserveAssetDeposit { + let mut paying_message = opaque::Xcm::ReserveAssetDeposited { assets: vec![ConcreteFungible { id: X1(Parent), amount: 100 }], effects: vec![ Order::BuyExecution { fees: All, weight: 0, debt: 30, halt_on_error: true, xcm: vec![] }, @@ -175,7 +175,7 @@ fn paying_reserve_deposit_should_work() { WeightPrice::set((X1(Parent), 1_000_000_000_000)); let origin = X1(Parent); - let message = Xcm::<TestCall>::ReserveAssetDeposit { + let message = Xcm::<TestCall>::ReserveAssetDeposited { assets: vec![ ConcreteFungible { id: X1(Parent), amount: 100 } ], effects: vec![ Order::<TestCall>::BuyExecution { fees: All, weight: 0, debt: 30, halt_on_error: true, xcm: vec![] }, @@ -233,7 +233,7 @@ fn reserve_transfer_should_work() { assert_eq!(assets(1002), vec![ ConcreteFungible { id: Null, amount: 100 } ]); assert_eq!(sent_xcm(), vec![( X1(Parachain(2)), - Xcm::ReserveAssetDeposit { + Xcm::ReserveAssetDeposited { assets: vec![ ConcreteFungible { id: X1(Parent), amount: 100 } ], effects: vec![ Order::DepositAsset { assets: vec![ All ], dest: three } ], }) diff --git a/xcm/xcm-builder/src/weight.rs b/xcm/xcm-builder/src/weight.rs index 77f28c73f571..ef18fcf99783 100644 --- a/xcm/xcm-builder/src/weight.rs +++ b/xcm/xcm-builder/src/weight.rs @@ -31,7 +31,7 @@ impl<T: Get<Weight>, C: Decode + GetDispatchInfo> WeightBounds<C> for FixedWeigh } Xcm::RelayedFrom { ref mut message, .. } => T::get().saturating_add(Self::shallow(message.as_mut())?), Xcm::WithdrawAsset { effects, .. } - | Xcm::ReserveAssetDeposit { effects, .. } + | Xcm::ReserveAssetDeposited { effects, .. } | Xcm::TeleportAsset { effects, .. } => { let inner: Weight = effects.iter_mut() @@ -55,7 +55,7 @@ impl<T: Get<Weight>, C: Decode + GetDispatchInfo> WeightBounds<C> for FixedWeigh Ok(match message { Xcm::RelayedFrom { ref mut message, .. } => Self::deep(message.as_mut())?, Xcm::WithdrawAsset { effects, .. } - | Xcm::ReserveAssetDeposit { effects, .. } + | Xcm::ReserveAssetDeposited { effects, .. } | Xcm::TeleportAsset { effects, .. } => { let mut extra = 0; diff --git a/xcm/xcm-executor/src/assets.rs b/xcm/xcm-executor/src/assets.rs index b25b0b3e4637..5846185189f9 100644 --- a/xcm/xcm-executor/src/assets.rs +++ b/xcm/xcm-executor/src/assets.rs @@ -201,7 +201,7 @@ impl Assets { } }); } - MultiAssetFilter::Assets(assets) => { + MultiAssetFilter::Definite(assets) => { if !saturate { self.ensure_contains(&assets)?; } @@ -263,15 +263,6 @@ impl Assets { } } - /// Consumes `self` and returns its original value excluding `mask` iff it contains at least `mask`, as well as - /// the assets excluded. - pub fn less(mut self, mask: MultiAssetFilter) -> Result<(Assets, Assets), Self> { - match self.try_take(mask) { - Ok(taken) => Ok((self, taken)), - Err(_) => Err(self), - } - } - /// Return the assets in `self`, but (asset-wise) of no greater value than `assets`. /// /// Result is undefined if `assets` includes elements which match to the same asset more than once. @@ -312,7 +303,7 @@ impl Assets { } }); } - MultiAssetFilter::Assets(assets) => { + MultiAssetFilter::Definite(assets) => { for asset in assets.inner().iter() { match asset { MultiAsset { fun: Fungible(ref amount), ref id } => { diff --git a/xcm/xcm-executor/src/lib.rs b/xcm/xcm-executor/src/lib.rs index b9ec7b4a6e92..a12d714cac6c 100644 --- a/xcm/xcm-executor/src/lib.rs +++ b/xcm/xcm-executor/src/lib.rs @@ -133,7 +133,7 @@ impl<Config: config::Config> XcmExecutor<Config> { } Some((holding, effects)) } - (origin, Xcm::ReserveAssetDeposit { assets, effects }) => { + (origin, Xcm::ReserveAssetDeposited { assets, effects }) => { // check whether we trust origin to be our reserve location for this asset. for asset in assets.inner() { // We only trust the origin to send us assets that they identify as their @@ -145,7 +145,7 @@ impl<Config: config::Config> XcmExecutor<Config> { (origin, Xcm::TransferAsset { assets, dest }) => { // Take `assets` from the origin account (on-chain) and place into dest account. for asset in assets.inner() { - Config::AssetTransactor::teleport_asset(&asset, &origin, &dest)?; + Config::AssetTransactor::beam_asset(&asset, &origin, &dest)?; } None } @@ -153,10 +153,10 @@ impl<Config: config::Config> XcmExecutor<Config> { // Take `assets` from the origin account (on-chain) and place into dest account. let inv_dest = Config::LocationInverter::invert_location(&dest); for asset in assets.inner() { - Config::AssetTransactor::teleport_asset(asset, &origin, &dest)?; + Config::AssetTransactor::beam_asset(asset, &origin, &dest)?; } assets.reanchor(&inv_dest)?; - Config::XcmSender::send_xcm(dest, Xcm::ReserveAssetDeposit { assets, effects })?; + Config::XcmSender::send_xcm(dest, Xcm::ReserveAssetDeposited { assets, effects })?; None } (origin, Xcm::TeleportAsset { assets, effects }) => { @@ -256,7 +256,7 @@ impl<Config: config::Config> XcmExecutor<Config> { Config::AssetTransactor::deposit_asset(&asset, &dest)?; } let assets = Self::reanchored(deposited, &dest); - Config::XcmSender::send_xcm(dest, Xcm::ReserveAssetDeposit { assets, effects })?; + Config::XcmSender::send_xcm(dest, Xcm::ReserveAssetDeposited { assets, effects })?; }, Order::InitiateReserveWithdraw { assets, reserve, effects} => { let assets = Self::reanchored(holding.saturating_take(assets), &reserve); @@ -276,7 +276,7 @@ impl<Config: config::Config> XcmExecutor<Config> { Config::XcmSender::send_xcm(dest, Xcm::QueryResponse { query_id, response: Response::Assets(assets) })?; } Order::BuyExecution { fees, weight, debt, halt_on_error, xcm } => { - // pay for `weight` using up to `fees` of the holding account. + // pay for `weight` using up to `fees` of the holding register. let purchasing_weight = Weight::from(weight.checked_add(debt).ok_or(XcmError::Overflow)?); let max_fee = holding.try_take(fees.into()).map_err(|_| XcmError::NotHoldingFees)?; let unspent = trader.buy_weight(purchasing_weight, max_fee)?; diff --git a/xcm/xcm-executor/src/traits/transact_asset.rs b/xcm/xcm-executor/src/traits/transact_asset.rs index 610f98977ca7..736990775a23 100644 --- a/xcm/xcm-executor/src/traits/transact_asset.rs +++ b/xcm/xcm-executor/src/traits/transact_asset.rs @@ -85,7 +85,7 @@ pub trait TransactAsset { /// Move an `asset` `from` one location in `to` another location. /// /// Attempts to use `transfer_asset` and if not available then falls back to using a two-part withdraw/deposit. - fn teleport_asset(asset: &MultiAsset, from: &MultiLocation, to: &MultiLocation) -> Result<Assets, XcmError> { + fn beam_asset(asset: &MultiAsset, from: &MultiLocation, to: &MultiLocation) -> Result<Assets, XcmError> { match Self::transfer_asset(asset, from, to) { Err(XcmError::Unimplemented) => { let assets = Self::withdraw_asset(asset, from)?; From 958d79a2140b9b1040ba10aac85cf3c49a239438 Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Sun, 1 Aug 2021 20:03:10 +0200 Subject: [PATCH 031/166] Some TODOs --- xcm/src/v0/order.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/xcm/src/v0/order.rs b/xcm/src/v0/order.rs index 6ee6eb20f9bc..fbeb4a5c9608 100644 --- a/xcm/src/v0/order.rs +++ b/xcm/src/v0/order.rs @@ -39,6 +39,7 @@ pub enum Order<Call> { /// /// Errors: #[codec(index = 1)] + // TODO: https://github.com/paritytech/polkadot/issues/3547 introduce `, max_assets: u32` DepositAsset { assets: MultiAssetFilter, dest: MultiLocation }, /// Remove the asset(s) (`assets`) from holding and place equivalent assets under the ownership of `dest` within @@ -53,6 +54,7 @@ pub enum Order<Call> { /// /// Errors: #[codec(index = 2)] + // TODO: https://github.com/paritytech/polkadot/issues/3547 introduce `, max_assets: u32` DepositReserveAsset { assets: MultiAssetFilter, dest: MultiLocation, effects: Vec<Order<()>> }, /// Remove the asset(s) (`give`) from holding and replace them with alternative assets. @@ -107,7 +109,7 @@ pub enum Order<Call> { /// /// Errors: #[codec(index = 7)] - BuyExecution { fees: WildMultiAsset, weight: u64, debt: u64, halt_on_error: bool, xcm: Vec<Xcm<Call>> }, + BuyExecution { fees: MultiAsset, weight: u64, debt: u64, halt_on_error: bool, xcm: Vec<Xcm<Call>> }, } pub mod opaque { From 7d47d21bcc9f4948dc53de098fad34a15e811be0 Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Sun, 1 Aug 2021 20:26:39 +0200 Subject: [PATCH 032/166] Further build fixes --- runtime/kusama/src/lib.rs | 7 +++---- runtime/rococo/src/lib.rs | 2 +- xcm/pallet-xcm/src/lib.rs | 12 ++++++++---- xcm/src/v0/order.rs | 2 +- 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/runtime/kusama/src/lib.rs b/runtime/kusama/src/lib.rs index 8b307d392843..a69e46f8ef8a 100644 --- a/runtime/kusama/src/lib.rs +++ b/runtime/kusama/src/lib.rs @@ -54,8 +54,7 @@ use runtime_parachains::scheduler as parachains_scheduler; use runtime_parachains::reward_points as parachains_reward_points; use runtime_parachains::runtime_api_impl::v1 as parachains_runtime_api_impl; -use xcm::v0::{MultiLocation::{self, Null, X1}, NetworkId, BodyId, Xcm, Junction::Parachain}; -use xcm::v0::MultiAsset::{self, AllConcreteFungible}; +use xcm::v0::prelude::*; use xcm_builder::{ AccountId32Aliases, ChildParachainConvertsVia, SovereignSignedViaLocation, CurrencyAdapter as XcmCurrencyAdapter, ChildParachainAsNative, SignedAccountId32AsNative, ChildSystemParachainAsSuperuser, LocationInverter, @@ -1260,8 +1259,8 @@ pub type XcmRouter = ( ); parameter_types! { - pub const KusamaForStatemint: (MultiAsset, MultiLocation) = - (AllConcreteFungible { id: Null }, X1(Parachain(1000))); + pub const Kusama: MultiAssetFilter = Wild(AllOf(WildFungible, Concrete(KsmLocation::get()))); + pub const KusamaForStatemint: (MultiAssetFilter, MultiLocation) = (Kusama::get(), X1(Parachain(1000))); } pub type TrustedTeleporters = ( xcm_builder::Case<KusamaForStatemint>, diff --git a/runtime/rococo/src/lib.rs b/runtime/rococo/src/lib.rs index 7000c291a1ff..9d4dbdc1c53f 100644 --- a/runtime/rococo/src/lib.rs +++ b/runtime/rococo/src/lib.rs @@ -629,7 +629,7 @@ pub type XcmRouter = ( use xcm::v0::prelude::*; parameter_types! { - pub const Rococo: MultiAssetFilter = Wild(AllOf(Concrete(RocLocation::get()), WildFungible)); + pub const Rococo: MultiAssetFilter = Wild(AllOf(WildFungible, 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))); diff --git a/xcm/pallet-xcm/src/lib.rs b/xcm/pallet-xcm/src/lib.rs index 77c004b58844..99341c2a0e85 100644 --- a/xcm/pallet-xcm/src/lib.rs +++ b/xcm/pallet-xcm/src/lib.rs @@ -89,6 +89,8 @@ pub mod pallet { Filtered, /// The message's weight could not be determined. UnweighableMessage, + /// The assets to be sent are empty. + Empty, } #[pallet::hooks] @@ -115,8 +117,8 @@ pub mod pallet { /// from parachain to parachain, or `X1(Parachain(..))` to send from relay to parachain. /// - `beneficiary`: A beneficiary location for the assets in the context of `dest`. Will generally be /// an `AccountId32` value. - /// - `assets`: The assets to be withdrawn. This should include the assets used to pay the fee on the - /// `dest` side. + /// - `assets`: The assets to be withdrawn. The first item should be the currency used to to pay the fee on the + /// `dest` side. May not be empty. /// - `dest_weight`: Equal to the total weight on `dest` of the XCM message /// `Teleport { assets, effects: [ BuyExecution{..}, DepositAsset{..} ] }`. #[pallet::weight({ @@ -141,6 +143,7 @@ pub mod pallet { let value = (origin_location, assets.drain()); ensure!(T::XcmTeleportFilter::contains(&value), Error::<T>::Filtered); let (origin_location, assets) = value; + let fees = assets.first().ok_or(Error::<T>::Empty)?.clone(); let assets = assets.into(); let mut message = Xcm::WithdrawAsset { assets, @@ -150,7 +153,7 @@ pub mod pallet { dest, effects: vec![ BuyExecution { - fees: All, + fees, // Zero weight for additional XCM (since there are none to execute) weight: 0, debt: dest_weight, @@ -200,13 +203,14 @@ pub mod pallet { let value = (origin_location, assets.drain()); ensure!(T::XcmReserveTransferFilter::contains(&value), Error::<T>::Filtered); let (origin_location, assets) = value; + let fees = assets.first().ok_or(Error::<T>::Empty)?.clone(); let assets = assets.into(); let mut message = Xcm::TransferReserveAsset { assets, dest, effects: vec![ BuyExecution { - fees: All, + fees, // Zero weight for additional XCM (since there are none to execute) weight: 0, debt: dest_weight, diff --git a/xcm/src/v0/order.rs b/xcm/src/v0/order.rs index fbeb4a5c9608..6162581f7e28 100644 --- a/xcm/src/v0/order.rs +++ b/xcm/src/v0/order.rs @@ -19,7 +19,7 @@ use alloc::vec::Vec; use derivative::Derivative; use parity_scale_codec::{self, Encode, Decode}; -use super::{MultiAsset, WildMultiAsset, MultiAssetFilter, MultiLocation, Xcm}; +use super::{MultiAsset, MultiAssetFilter, MultiLocation, Xcm}; /// An instruction to be executed on some or all of the assets in holding, used by asset-related XCM messages. #[derive(Derivative, Encode, Decode)] From 6ce9f1ddbf233a881564eb13ed6abb3d4eeb9e82 Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Sun, 1 Aug 2021 11:59:36 -0700 Subject: [PATCH 033/166] Rename non_parent/junctions to interior --- runtime/common/src/xcm_sender.rs | 2 +- runtime/kusama/src/lib.rs | 6 +++--- runtime/rococo/src/lib.rs | 6 +++--- runtime/westend/src/lib.rs | 6 +++--- xcm/src/v0/multi_location.rs | 14 +++++++------- xcm/src/v0/traits.rs | 4 ++-- xcm/xcm-builder/src/barriers.rs | 2 +- xcm/xcm-builder/src/fungibles_adapter.rs | 6 +++--- xcm/xcm-builder/src/location_conversion.rs | 12 ++++++------ xcm/xcm-builder/src/mock.rs | 4 ++-- xcm/xcm-builder/src/origin_conversion.rs | 16 ++++++++-------- xcm/xcm-executor/src/traits/conversion.rs | 4 ++-- 12 files changed, 41 insertions(+), 41 deletions(-) diff --git a/runtime/common/src/xcm_sender.rs b/runtime/common/src/xcm_sender.rs index 2c93884e6b3e..21b3743a5560 100644 --- a/runtime/common/src/xcm_sender.rs +++ b/runtime/common/src/xcm_sender.rs @@ -29,7 +29,7 @@ pub struct ChildParachainRouter<T>(PhantomData<T>); impl<T: configuration::Config + dmp::Config> SendXcm for ChildParachainRouter<T> { fn send_xcm(dest: MultiLocation, msg: Xcm) -> Result { - match dest.junctions() { + match dest.interior() { Junctions::X1(Junction::Parachain(id)) if dest.parent_count() == 0 => { // Downward message passing. let config = <configuration::Pallet<T>>::config(); diff --git a/runtime/kusama/src/lib.rs b/runtime/kusama/src/lib.rs index 6171a8c60df3..bad21bdd1fcc 100644 --- a/runtime/kusama/src/lib.rs +++ b/runtime/kusama/src/lib.rs @@ -1314,7 +1314,7 @@ impl frame_support::traits::Contains<(MultiLocation, Xcm<Call>)> for OnlyWithdra Xcm::WithdrawAsset, Order::{BuyExecution, InitiateTeleport, DepositAsset}, MultiAsset::{All, ConcreteFungible}, Junction::{AccountId32, Plurality}, }; - match origin.junctions() { + match origin.interior() { // Root and council are are allowed to execute anything. Null | X1(Plurality { .. }) if origin.parent_count() == 0 => true, X1(AccountId32 { .. }) if origin.parent_count() == 0 => { @@ -1338,7 +1338,7 @@ impl frame_support::traits::Contains<(MultiLocation, Xcm<Call>)> for OnlyWithdra && matches!(effects[0], BuyExecution { .. }) && matches!(effects[1], InitiateTeleport { ref assets, ref dest, ref effects } if assets.len() == 1 - && matches!(dest.junctions(), X1(Parachain(..))) + && matches!(dest.interior(), X1(Parachain(..))) && dest.parent_count() == 0 && matches!(assets[0], All) && effects.len() == 2 @@ -1347,7 +1347,7 @@ impl frame_support::traits::Contains<(MultiLocation, Xcm<Call>)> for OnlyWithdra if assets.len() == 1 && matches!(assets[0], All) && dest.parent_count() == 0 - && matches!(dest.junctions(), X1(AccountId32{..})) + && matches!(dest.interior(), X1(AccountId32{..})) ) ) ) diff --git a/runtime/rococo/src/lib.rs b/runtime/rococo/src/lib.rs index 3afe89df664d..3972c5adb2eb 100644 --- a/runtime/rococo/src/lib.rs +++ b/runtime/rococo/src/lib.rs @@ -698,7 +698,7 @@ impl frame_support::traits::Contains<(MultiLocation, Xcm<Call>)> for OnlyWithdra Xcm::WithdrawAsset, Order::{BuyExecution, InitiateTeleport, DepositAsset}, MultiAsset::{All, ConcreteFungible}, Junction::{AccountId32, Plurality}, }; - match origin.junctions() { + match origin.interior() { // Root and collective are allowed to execute anything. Null | X1(Plurality { .. }) if origin.parent_count() == 0 => true, X1(AccountId32 { .. }) if origin.parent_count() == 0 => { @@ -722,14 +722,14 @@ impl frame_support::traits::Contains<(MultiLocation, Xcm<Call>)> for OnlyWithdra && matches!(effects[0], BuyExecution { .. }) && matches!(effects[1], InitiateTeleport { ref assets, ref dest, ref effects } if assets.len() == 1 - && matches!(dest.junctions(), X1(Parachain(..))) + && matches!(dest.interior(), X1(Parachain(..))) && dest.parent_count() == 0 && matches!(assets[0], All) && effects.len() == 2 && matches!(effects[0], BuyExecution { .. }) && matches!(effects[1], DepositAsset { ref assets, ref dest } if assets.len() == 1 - && matches!(dest.junctions(), X1(AccountId32{..})) + && matches!(dest.interior(), X1(AccountId32{..})) && dest.parent_count() == 0 && matches!(assets[0], All) ) diff --git a/runtime/westend/src/lib.rs b/runtime/westend/src/lib.rs index 506e57f84584..4f877d533c11 100644 --- a/runtime/westend/src/lib.rs +++ b/runtime/westend/src/lib.rs @@ -953,7 +953,7 @@ impl frame_support::traits::Contains<(MultiLocation, Xcm<Call>)> for OnlyWithdra Xcm::WithdrawAsset, Order::{BuyExecution, InitiateTeleport, DepositAsset}, MultiAsset::{All, ConcreteFungible}, Junction::AccountId32, }; - match origin.junctions() { + match origin.interior() { // Root is allowed to execute anything. Null if origin.parent_count() == 0 => true, X1(AccountId32 { .. }) if origin.parent_count() == 0 => { @@ -979,14 +979,14 @@ impl frame_support::traits::Contains<(MultiLocation, Xcm<Call>)> for OnlyWithdra if assets.len() == 1 && matches!(assets[0], All) && dest.parent_count() == 0 - && matches!(dest.junctions(), X1(Parachain(..))) + && matches!(dest.interior(), X1(Parachain(..))) && effects.len() == 2 && matches!(effects[0], BuyExecution { .. }) && matches!(effects[1], DepositAsset { ref assets, ref dest } if assets.len() == 1 && matches!(assets[0], All) && dest.parent_count() == 0 - && matches!(dest.junctions(), X1(AccountId32{..})) + && matches!(dest.interior(), X1(AccountId32{..})) ) ) ) diff --git a/xcm/src/v0/multi_location.rs b/xcm/src/v0/multi_location.rs index c44381713e83..56262195367e 100644 --- a/xcm/src/v0/multi_location.rs +++ b/xcm/src/v0/multi_location.rs @@ -157,12 +157,12 @@ impl MultiLocation { } /// Return a reference to the interior field. - pub fn junctions(&self) -> &Junctions { + pub fn interior(&self) -> &Junctions { &self.interior } /// Return a mutable reference to the interior field. - pub fn junctions_mut(&mut self) -> &mut Junctions { + pub fn interior_mut(&mut self) -> &mut Junctions { &mut self.interior } @@ -176,9 +176,9 @@ impl MultiLocation { self.parent_count() as usize + self.interior.len() } - /// Returns first junction that is not a parent, or `None` if the location is empty or - /// contains only parents. - pub fn first_non_parent(&self) -> Option<&Junction> { + /// 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() } @@ -187,9 +187,9 @@ impl MultiLocation { self.interior.last() } - /// Splits off the first non-parent junction, returning the remaining suffix (first item in tuple) + /// 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_non_parent(self) -> (MultiLocation, Option<Junction>) { + pub fn split_first_interior(self) -> (MultiLocation, Option<Junction>) { let MultiLocation { parents, interior: junctions } = self; let (suffix, first) = junctions.split_first(); let multilocation = MultiLocation { diff --git a/xcm/src/v0/traits.rs b/xcm/src/v0/traits.rs index 9f8bab7f7d19..24362d8e3d31 100644 --- a/xcm/src/v0/traits.rs +++ b/xcm/src/v0/traits.rs @@ -199,7 +199,7 @@ impl<C> ExecuteXcm<C> for () { /// struct Sender2; /// impl SendXcm for Sender2 { /// fn send_xcm(destination: MultiLocation, message: Xcm<()>) -> Result { -/// if matches!(destination.junctions(), Junctions::X2(j1, j2)) +/// if matches!(destination.interior(), Junctions::X2(j1, j2)) /// && destination.parent_count() == 0 /// { /// Ok(()) @@ -213,7 +213,7 @@ impl<C> ExecuteXcm<C> for () { /// struct Sender3; /// impl SendXcm for Sender3 { /// fn send_xcm(destination: MultiLocation, message: Xcm<()>) -> Result { -/// if matches!(destination.junctions(), Junctions::Null) +/// if matches!(destination.interior(), Junctions::Null) /// && destination.parent_count() == 1 /// { /// Ok(()) diff --git a/xcm/xcm-builder/src/barriers.rs b/xcm/xcm-builder/src/barriers.rs index 2d9db1e916f4..1e71cd497b67 100644 --- a/xcm/xcm-builder/src/barriers.rs +++ b/xcm/xcm-builder/src/barriers.rs @@ -87,7 +87,7 @@ impl< > Contains<MultiLocation> for IsChildSystemParachain<ParaId> { fn contains(l: &MultiLocation) -> bool { matches!( - l.junctions(), + l.interior(), Junctions::X1(Junction::Parachain(id)) if ParaId::from(*id).is_system() && l.parent_count() == 0, ) diff --git a/xcm/xcm-builder/src/fungibles_adapter.rs b/xcm/xcm-builder/src/fungibles_adapter.rs index 99807f2098f8..80ba164b70c9 100644 --- a/xcm/xcm-builder/src/fungibles_adapter.rs +++ b/xcm/xcm-builder/src/fungibles_adapter.rs @@ -35,14 +35,14 @@ impl< let id = id.borrow(); if prefix.parent_count() != id.parent_count() || prefix - .junctions() + .interior() .iter() .enumerate() - .any(|(index, junction)| id.junctions().at(index) != Some(junction)) + .any(|(index, junction)| id.interior().at(index) != Some(junction)) { return Err(()) } - match id.junctions().at(prefix.junctions().len()) { + match id.interior().at(prefix.interior().len()) { Some(Junction::GeneralIndex { id }) => ConvertAssetId::convert_ref(id), _ => Err(()), } diff --git a/xcm/xcm-builder/src/location_conversion.rs b/xcm/xcm-builder/src/location_conversion.rs index d3528eb275ae..f30529b1cad6 100644 --- a/xcm/xcm-builder/src/location_conversion.rs +++ b/xcm/xcm-builder/src/location_conversion.rs @@ -43,7 +43,7 @@ impl< AccountId: Default + Eq + Clone, > Convert<MultiLocation, AccountId> for ParentIsDefault<AccountId> { fn convert_ref(location: impl Borrow<MultiLocation>) -> Result<AccountId, ()> { - if location.borrow().parent_count() == 1 && location.borrow().junctions().len() == 0 { + if location.borrow().parent_count() == 1 && location.borrow().interior().len() == 0 { Ok(AccountId::default()) } else { Err(()) @@ -66,7 +66,7 @@ impl< > Convert<MultiLocation, AccountId> for ChildParachainConvertsVia<ParaId, AccountId> { fn convert_ref(location: impl Borrow<MultiLocation>) -> Result<AccountId, ()> { let location = location.borrow(); - match location.junctions() { + match location.interior() { Junctions::X1(Junction::Parachain(id)) if location.parent_count() == 0 => { Ok(ParaId::from(*id).into_account()) }, @@ -90,7 +90,7 @@ impl< > Convert<MultiLocation, AccountId> for SiblingParachainConvertsVia<ParaId, AccountId> { fn convert_ref(location: impl Borrow<MultiLocation>) -> Result<AccountId, ()> { let location = location.borrow(); - match location.junctions() { + match location.interior() { Junctions::X1(Junction::Parachain(id)) if location.parent_count() == 1 => { Ok(ParaId::from(*id).into_account()) }, @@ -118,7 +118,7 @@ impl< AccountId: From<[u8; 32]> + Into<[u8; 32]> + Clone, > Convert<MultiLocation, AccountId> for AccountId32Aliases<Network, AccountId> { fn convert(location: MultiLocation) -> Result<AccountId, MultiLocation> { - let id = match location.junctions() { + let id = match location.interior() { Junctions::X1(Junction::AccountId32 { id, network: NetworkId::Any }) if location.parent_count() == 0 => *id, @@ -141,7 +141,7 @@ impl< AccountId: From<[u8; 20]> + Into<[u8; 20]> + Clone, > Convert<MultiLocation, AccountId> for AccountKey20Aliases<Network, AccountId> { fn convert(location: MultiLocation) -> Result<AccountId, MultiLocation> { - let key = match location.junctions() { + let key = match location.interior() { Junctions::X1(Junction::AccountKey20 { key, network: NetworkId::Any }) if location.parent_count() == 0 => *key, @@ -202,7 +202,7 @@ impl<Ancestry: Get<MultiLocation>> InvertLocation for LocationInverter<Ancestry> ) .expect("ancestry is well-formed and has less than 8 non-parent junctions; qed"); } - let parents = location.junctions().len() as u8; + let parents = location.interior().len() as u8; MultiLocation::new(parents, junctions) .expect("parents + junctions len must equal location len; qed") } diff --git a/xcm/xcm-builder/src/mock.rs b/xcm/xcm-builder/src/mock.rs index efe4f49ee5ce..4f307d397ac5 100644 --- a/xcm/xcm-builder/src/mock.rs +++ b/xcm/xcm-builder/src/mock.rs @@ -147,7 +147,7 @@ impl TransactAsset for TestAssetTransactor { pub fn to_account(l: MultiLocation) -> Result<u64, MultiLocation> { - Ok(match l.junctions() { + Ok(match l.interior() { // Siblings at 2000+id X1(Parachain(id)) if l.parent_count() == 1 => 2000 + *id as u64, // Accounts are their number @@ -166,7 +166,7 @@ pub struct TestOriginConverter; impl ConvertOrigin<TestOrigin> for TestOriginConverter { fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result<TestOrigin, MultiLocation> { use OriginKind::*; - match (kind, origin.junctions()) { + match (kind, origin.interior()) { (Superuser, _) => Ok(TestOrigin::Root), (SovereignAccount, _) => Ok(TestOrigin::Signed(to_account(origin)?)), (Native, X1(Parachain(id))) if origin.parent_count() == 0 => Ok(TestOrigin::Parachain(*id)), diff --git a/xcm/xcm-builder/src/origin_conversion.rs b/xcm/xcm-builder/src/origin_conversion.rs index 76782c6515a0..74a282f14b0a 100644 --- a/xcm/xcm-builder/src/origin_conversion.rs +++ b/xcm/xcm-builder/src/origin_conversion.rs @@ -46,7 +46,7 @@ impl< Origin: OriginTrait, > ConvertOrigin<Origin> for ParentAsSuperuser<Origin> { fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result<Origin, MultiLocation> { - if kind == OriginKind::Superuser && origin.parent_count() == 1 && origin.junctions().len() == 0 { + if kind == OriginKind::Superuser && origin.parent_count() == 1 && origin.interior().len() == 0 { Ok(Origin::root()) } else { Err(origin) @@ -60,7 +60,7 @@ impl< Origin: OriginTrait, > ConvertOrigin<Origin> for ChildSystemParachainAsSuperuser<ParaId, Origin> { fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result<Origin, MultiLocation> { - match (kind, origin.junctions()) { + match (kind, origin.interior()) { (OriginKind::Superuser, Junctions::X1(Junction::Parachain(id))) if ParaId::from(*id).is_system() && origin.parent_count() == 0 => Ok(Origin::root()), @@ -75,7 +75,7 @@ impl< Origin: OriginTrait > ConvertOrigin<Origin> for SiblingSystemParachainAsSuperuser<ParaId, Origin> { fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result<Origin, MultiLocation> { - match (kind, origin.junctions()) { + match (kind, origin.interior()) { (OriginKind::Superuser, Junctions::X1(Junction::Parachain(id))) if ParaId::from(*id).is_system() && origin.parent_count() == 1 => Ok(Origin::root()), @@ -92,7 +92,7 @@ impl< Origin: From<ParachainOrigin>, > ConvertOrigin<Origin> for ChildParachainAsNative<ParachainOrigin, Origin> { fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result<Origin, MultiLocation> { - match (kind, origin.junctions()) { + match (kind, origin.interior()) { (OriginKind::Native, Junctions::X1(Junction::Parachain(id))) => Ok(Origin::from(ParachainOrigin::from(*id))), _ => Err(origin), @@ -108,7 +108,7 @@ impl< Origin: From<ParachainOrigin>, > ConvertOrigin<Origin> for SiblingParachainAsNative<ParachainOrigin, Origin> { fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result<Origin, MultiLocation> { - match (kind, origin.junctions()) { + match (kind, origin.interior()) { (OriginKind::Native, Junctions::X1(Junction::Parachain(id))) if origin.parent_count() == 1 => Ok(Origin::from(ParachainOrigin::from(*id))), @@ -126,7 +126,7 @@ impl< Origin, > ConvertOrigin<Origin> for RelayChainAsNative<RelayOrigin, Origin> { fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result<Origin, MultiLocation> { - if kind == OriginKind::Native && origin.parent_count() == 1 && origin.junctions().len() == 0 { + if kind == OriginKind::Native && origin.parent_count() == 1 && origin.interior().len() == 0 { Ok(RelayOrigin::get()) } else { Err(origin) @@ -144,7 +144,7 @@ impl< Origin::AccountId: From<[u8; 32]>, { fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result<Origin, MultiLocation> { - match (kind, origin.junctions()) { + match (kind, origin.interior()) { (OriginKind::Native, Junctions::X1(Junction::AccountId32 { id, network })) if (matches!(network, NetworkId::Any) || network == &Network::get()) && origin.parent_count() == 0 @@ -164,7 +164,7 @@ impl< Origin::AccountId: From<[u8; 20]>, { fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result<Origin, MultiLocation> { - match (kind, origin.junctions()) { + match (kind, origin.interior()) { (OriginKind::Native, Junctions::X1(Junction::AccountKey20 { key, network })) if (matches!(network, NetworkId::Any) || network == &Network::get()) && origin.parent_count() == 0 => diff --git a/xcm/xcm-executor/src/traits/conversion.rs b/xcm/xcm-executor/src/traits/conversion.rs index 72d9fd979672..467541cb2c3c 100644 --- a/xcm/xcm-executor/src/traits/conversion.rs +++ b/xcm/xcm-executor/src/traits/conversion.rs @@ -131,7 +131,7 @@ impl<T: Clone + Encode + Decode> Convert<Vec<u8>, T> for Decoded { /// struct BumpParaId; /// impl ConvertOrigin<u32> for BumpParaId { /// fn convert_origin(origin: MultiLocation, _: OriginKind) -> Result<u32, MultiLocation> { -/// match origin.junctions() { +/// match origin.interior() { /// Junctions::X1(Junction::Parachain(id)) if origin.parent_count() == 0 => { /// Err(Junctions::X1(Junction::Parachain(id + 1)).into()) /// } @@ -143,7 +143,7 @@ impl<T: Clone + Encode + Decode> Convert<Vec<u8>, T> for Decoded { /// struct AcceptPara7; /// impl ConvertOrigin<u32> for AcceptPara7 { /// fn convert_origin(origin: MultiLocation, _: OriginKind) -> Result<u32, MultiLocation> { -/// match origin.junctions() { +/// match origin.interior() { /// Junctions::X1(Junction::Parachain(id)) if id == &7 && origin.parent_count() == 0 => { /// Ok(7) /// } From bb5bf44d6c89261b4e6d87603bd5c6c1dc1fff73 Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Sun, 1 Aug 2021 23:47:48 +0200 Subject: [PATCH 034/166] Basic compile builds --- runtime/rococo/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/rococo/src/lib.rs b/runtime/rococo/src/lib.rs index 9d4dbdc1c53f..f25ce35baa84 100644 --- a/runtime/rococo/src/lib.rs +++ b/runtime/rococo/src/lib.rs @@ -87,7 +87,7 @@ pub use pallet_balances::Call as BalancesCall; use polkadot_parachain::primitives::Id as ParaId; -use xcm::v0::{Xcm, MultiLocation, NetworkId, BodyId}; +use xcm::v0::{MultiLocation, NetworkId, BodyId}; use xcm_executor::XcmExecutor; use xcm_builder::{ AccountId32Aliases, ChildParachainConvertsVia, SovereignSignedViaLocation, From acef3195286d12427d097bf6e104874ad6c51bdf Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Mon, 2 Aug 2021 00:09:41 +0200 Subject: [PATCH 035/166] First test fixed --- xcm/src/v0/multiasset.rs | 12 +++++-- xcm/xcm-executor/src/assets.rs | 34 ++++++++++--------- xcm/xcm-executor/src/traits/transact_asset.rs | 10 +++--- 3 files changed, 33 insertions(+), 23 deletions(-) diff --git a/xcm/src/v0/multiasset.rs b/xcm/src/v0/multiasset.rs index 32b36f73a296..88cfa8c75364 100644 --- a/xcm/src/v0/multiasset.rs +++ b/xcm/src/v0/multiasset.rs @@ -323,9 +323,15 @@ impl From<WildMultiAsset> for MultiAssetFilter { } } -impl From<MultiAsset> for MultiAssetFilter { - fn from(x: MultiAsset) -> Self { - Self::Definite(vec![x].into()) +impl<T: Into<MultiAsset>> From<T> for MultiAssetFilter { + fn from(x: T) -> Self { + Self::Definite(vec![x.into()].into()) + } +} + +impl From<Vec<MultiAsset>> for MultiAssetFilter { + fn from(x: Vec<MultiAsset>) -> Self { + Self::Definite(x.into()) } } diff --git a/xcm/xcm-executor/src/assets.rs b/xcm/xcm-executor/src/assets.rs index 5846185189f9..13e7c209e9f9 100644 --- a/xcm/xcm-executor/src/assets.rs +++ b/xcm/xcm-executor/src/assets.rs @@ -328,30 +328,32 @@ impl Assets { #[cfg(test)] mod tests { use super::*; + use xcm::v0::prelude::*; + use MultiLocation::Null; #[allow(non_snake_case)] fn AF(id: u8, amount: u128) -> MultiAsset { - MultiAsset::AbstractFungible { id: vec![id], amount } + (vec![id], amount).into() } #[allow(non_snake_case)] fn ANF(class: u8, instance_id: u128) -> MultiAsset { - MultiAsset::AbstractNonFungible { class: vec![class], instance: AssetInstance::Index { id: instance_id } } + (vec![class], AssetInstance::Index { id: instance_id }).into() } #[allow(non_snake_case)] fn CF(amount: u128) -> MultiAsset { - MultiAsset::ConcreteFungible { id: MultiLocation::Null, amount } + (Null, amount).into() } #[allow(non_snake_case)] fn CNF(instance_id: u128) -> MultiAsset { - MultiAsset::ConcreteNonFungible { class: MultiLocation::Null, instance: AssetInstance::Index { id: instance_id } } + (Null, AssetInstance::Index { id: instance_id }).into() } fn test_assets() -> Assets { - let mut assets_vec: Vec<MultiAsset> = Vec::new(); - assets_vec.push(AF(1, 100)); - assets_vec.push(ANF(2, 200)); - assets_vec.push(CF(300)); - assets_vec.push(CNF(400)); - assets_vec.into() + let mut assets = Assets::new(); + assets.subsume(AF(1, 100)); + assets.subsume(ANF(2, 200)); + assets.subsume(CF(300)); + assets.subsume(CNF(400)); + assets } #[test] @@ -393,15 +395,15 @@ mod tests { #[test] fn min_all_and_none_works() { let assets = test_assets(); - let none = vec![MultiAsset::None]; - let all = vec![MultiAsset::All]; + let none = MultiAssets::new().into(); + let all = All.into(); - let none_min = assets.min(none.iter()); + let none_min = assets.min(&none); assert_eq!(None, none_min.assets_iter().next()); - let all_min = assets.min(all.iter()); + let all_min = assets.min(&all); assert!(all_min.assets_iter().eq(assets.assets_iter())); } - +/* #[test] fn min_all_fungible_and_all_non_fungible_works() { let assets = test_assets(); @@ -549,5 +551,5 @@ mod tests { let assets = assets1.into_assets_iter().collect::<Vec<_>>(); assert_eq!(assets, vec![AF(1, 50), ANF(2, 200)]); - } + }*/ } diff --git a/xcm/xcm-executor/src/traits/transact_asset.rs b/xcm/xcm-executor/src/traits/transact_asset.rs index 736990775a23..d4ff17ce8496 100644 --- a/xcm/xcm-executor/src/traits/transact_asset.rs +++ b/xcm/xcm-executor/src/traits/transact_asset.rs @@ -181,6 +181,8 @@ impl TransactAsset for Tuple { #[cfg(test)] mod tests { use super::*; + use xcm::v0::prelude::*; + use MultiLocation::Null; pub struct UnimplementedTransactor; impl TransactAsset for UnimplementedTransactor {} @@ -246,27 +248,27 @@ mod tests { fn defaults_to_asset_not_found() { type MultiTransactor = (UnimplementedTransactor, NotFoundTransactor, UnimplementedTransactor); - assert_eq!(MultiTransactor::deposit_asset(&MultiAsset::All, &MultiLocation::Null), Err(XcmError::AssetNotFound)); + assert_eq!(MultiTransactor::deposit_asset(&(Null, 1).into(), &Null), Err(XcmError::AssetNotFound)); } #[test] fn unimplemented_and_not_found_continue_iteration() { type MultiTransactor = (UnimplementedTransactor, NotFoundTransactor, SuccessfulTransactor); - assert_eq!(MultiTransactor::deposit_asset(&MultiAsset::All, &MultiLocation::Null), Ok(())); + assert_eq!(MultiTransactor::deposit_asset(&(Null, 1).into(), &Null), Ok(())); } #[test] fn unexpected_error_stops_iteration() { type MultiTransactor = (OverflowTransactor, SuccessfulTransactor); - assert_eq!(MultiTransactor::deposit_asset(&MultiAsset::All, &MultiLocation::Null), Err(XcmError::Overflow)); + assert_eq!(MultiTransactor::deposit_asset(&(Null, 1).into(), &Null), Err(XcmError::Overflow)); } #[test] fn success_stops_iteration() { type MultiTransactor = (SuccessfulTransactor, OverflowTransactor); - assert_eq!(MultiTransactor::deposit_asset(&MultiAsset::All, &MultiLocation::Null), Ok(())); + assert_eq!(MultiTransactor::deposit_asset(&(Null, 1).into(), &Null), Ok(())); } } From 7d700b62fe409e19522b1546252328a444cafdf9 Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Mon, 2 Aug 2021 00:28:03 +0200 Subject: [PATCH 036/166] All executor tests fixed --- xcm/xcm-executor/src/assets.rs | 89 ++++++------------- xcm/xcm-executor/src/traits/transact_asset.rs | 1 - 2 files changed, 29 insertions(+), 61 deletions(-) diff --git a/xcm/xcm-executor/src/assets.rs b/xcm/xcm-executor/src/assets.rs index 13e7c209e9f9..3064a4a7312a 100644 --- a/xcm/xcm-executor/src/assets.rs +++ b/xcm/xcm-executor/src/assets.rs @@ -403,31 +403,17 @@ mod tests { let all_min = assets.min(&all); assert!(all_min.assets_iter().eq(assets.assets_iter())); } -/* - #[test] - fn min_all_fungible_and_all_non_fungible_works() { - let assets = test_assets(); - let fungible = vec![MultiAsset::AllFungible]; - let non_fungible = vec![MultiAsset::AllNonFungible]; - - let fungible = assets.min(fungible.iter()); - let fungible = fungible.assets_iter().collect::<Vec<_>>(); - assert_eq!(fungible, vec![CF(300), AF(1, 100)]); - let non_fungible = assets.min(non_fungible.iter()); - let non_fungible = non_fungible.assets_iter().collect::<Vec<_>>(); - assert_eq!(non_fungible, vec![CNF(400), ANF(2, 200)]); - } #[test] fn min_all_abstract_works() { let assets = test_assets(); - let fungible = vec![MultiAsset::AllAbstractFungible { id: vec![1] }]; - let non_fungible = vec![MultiAsset::AllAbstractNonFungible { class: vec![2] }]; + let fungible = Wild((vec![1], WildFungible).into()); + let non_fungible = Wild((vec![2], WildNonFungible).into()); - let fungible = assets.min(fungible.iter()); + let fungible = assets.min(&fungible); let fungible = fungible.assets_iter().collect::<Vec<_>>(); assert_eq!(fungible, vec![AF(1, 100)]); - let non_fungible = assets.min(non_fungible.iter()); + let non_fungible = assets.min(&non_fungible); let non_fungible = non_fungible.assets_iter().collect::<Vec<_>>(); assert_eq!(non_fungible, vec![ANF(2, 200)]); } @@ -435,13 +421,13 @@ mod tests { #[test] fn min_all_concrete_works() { let assets = test_assets(); - let fungible = vec![MultiAsset::AllConcreteFungible { id: MultiLocation::Null }]; - let non_fungible = vec![MultiAsset::AllConcreteNonFungible { class: MultiLocation::Null }]; + let fungible = Wild((Null, WildFungible).into()); + let non_fungible = Wild((Null, WildNonFungible).into()); - let fungible = assets.min(fungible.iter()); + let fungible = assets.min(&fungible); let fungible = fungible.assets_iter().collect::<Vec<_>>(); assert_eq!(fungible, vec![CF(300)]); - let non_fungible = assets.min(non_fungible.iter()); + let non_fungible = assets.min(&non_fungible); let non_fungible = non_fungible.assets_iter().collect::<Vec<_>>(); assert_eq!(non_fungible, vec![CNF(400)]); } @@ -450,18 +436,18 @@ mod tests { fn min_basic_works() { let assets1 = test_assets(); - let mut assets2_vec: Vec<MultiAsset> = Vec::new(); + let mut assets2 = Assets::new(); // This is less than 100, so it will decrease to 50 - assets2_vec.push(AF(1, 50)); + assets2.subsume(AF(1, 50)); // This asset does not exist, so not included - assets2_vec.push(ANF(2, 400)); + assets2.subsume(ANF(2, 400)); // This is more then 300, so it should stay at 300 - assets2_vec.push(CF(600)); + assets2.subsume(CF(600)); // This asset should be included - assets2_vec.push(CNF(400)); - let assets2: Assets = assets2_vec.into(); + assets2.subsume(CNF(400)); + let assets2: MultiAssets = assets2.into(); - let assets_min = assets1.min(assets2.assets_iter()); + let assets_min = assets1.min(&assets2.into()); let assets_min = assets_min.into_assets_iter().collect::<Vec<_>>(); assert_eq!(assets_min, vec![CF(300), AF(1, 50), CNF(400)]); } @@ -469,39 +455,21 @@ mod tests { #[test] fn saturating_take_all_and_none_works() { let mut assets = test_assets(); - let none = vec![MultiAsset::None]; - let all = vec![MultiAsset::All]; - let taken_none = assets.saturating_take(none); + let taken_none = assets.saturating_take(vec![].into()); assert_eq!(None, taken_none.assets_iter().next()); - let taken_all = assets.saturating_take(all); + let taken_all = assets.saturating_take(All.into()); // Everything taken assert_eq!(None, assets.assets_iter().next()); let all_iter = taken_all.assets_iter(); assert!(all_iter.eq(test_assets().assets_iter())); } - #[test] - fn saturating_take_all_fungible_and_all_non_fungible_works() { - let mut assets = test_assets(); - let fungible = vec![MultiAsset::AllFungible]; - let non_fungible = vec![MultiAsset::AllNonFungible]; - - let fungible = assets.saturating_take(fungible); - let fungible = fungible.assets_iter().collect::<Vec<_>>(); - assert_eq!(fungible, vec![CF(300), AF(1, 100)]); - let non_fungible = assets.saturating_take(non_fungible); - let non_fungible = non_fungible.assets_iter().collect::<Vec<_>>(); - assert_eq!(non_fungible, [CNF(400), ANF(2, 200)]); - // Assets completely drained - assert_eq!(None, assets.assets_iter().next()); - } - #[test] fn saturating_take_all_abstract_works() { let mut assets = test_assets(); - let fungible = vec![MultiAsset::AllAbstractFungible { id: vec![1] }]; - let non_fungible = vec![MultiAsset::AllAbstractNonFungible { class: vec![2] }]; + let fungible = Wild((vec![1], WildFungible).into()); + let non_fungible = Wild((vec![2], WildNonFungible).into()); let fungible = assets.saturating_take(fungible); let fungible = fungible.assets_iter().collect::<Vec<_>>(); @@ -517,8 +485,8 @@ mod tests { #[test] fn saturating_take_all_concrete_works() { let mut assets = test_assets(); - let fungible = vec![MultiAsset::AllConcreteFungible { id: MultiLocation::Null }]; - let non_fungible = vec![MultiAsset::AllConcreteNonFungible { class: MultiLocation::Null }]; + let fungible = Wild((Null, WildFungible).into()); + let non_fungible = Wild((Null, WildNonFungible).into()); let fungible = assets.saturating_take(fungible); let fungible = fungible.assets_iter().collect::<Vec<_>>(); @@ -535,21 +503,22 @@ mod tests { fn saturating_take_basic_works() { let mut assets1 = test_assets(); - let mut assets2_vec: Vec<MultiAsset> = Vec::new(); + let mut assets2 = Assets::new(); // We should take 50 - assets2_vec.push(AF(1, 50)); + assets2.subsume(AF(1, 50)); // This asset should not be taken - assets2_vec.push(ANF(2, 400)); + assets2.subsume(ANF(2, 400)); // This is more then 300, so it takes everything - assets2_vec.push(CF(600)); + assets2.subsume(CF(600)); // This asset should be taken - assets2_vec.push(CNF(400)); + assets2.subsume(CNF(400)); + let assets2: MultiAssets = assets2.into(); - let taken = assets1.saturating_take(assets2_vec); + let taken = assets1.saturating_take(assets2.into()); let taken = taken.into_assets_iter().collect::<Vec<_>>(); assert_eq!(taken, vec![CF(300), AF(1, 50), CNF(400)]); let assets = assets1.into_assets_iter().collect::<Vec<_>>(); assert_eq!(assets, vec![AF(1, 50), ANF(2, 200)]); - }*/ + } } diff --git a/xcm/xcm-executor/src/traits/transact_asset.rs b/xcm/xcm-executor/src/traits/transact_asset.rs index d4ff17ce8496..09cd94b19918 100644 --- a/xcm/xcm-executor/src/traits/transact_asset.rs +++ b/xcm/xcm-executor/src/traits/transact_asset.rs @@ -181,7 +181,6 @@ impl TransactAsset for Tuple { #[cfg(test)] mod tests { use super::*; - use xcm::v0::prelude::*; use MultiLocation::Null; pub struct UnimplementedTransactor; From 3e62aa35b5945c786c5256baec10b3d701f5d4eb Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Mon, 2 Aug 2021 00:32:23 +0200 Subject: [PATCH 037/166] Typo --- xcm/src/v0/multiasset.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xcm/src/v0/multiasset.rs b/xcm/src/v0/multiasset.rs index 88cfa8c75364..c6fb07518578 100644 --- a/xcm/src/v0/multiasset.rs +++ b/xcm/src/v0/multiasset.rs @@ -94,7 +94,7 @@ impl AssetId { } } -/// Classification of whether an asset is fungible or not, along with an mandatory amount or instance. +/// Classification of whether an asset is fungible or not, along with a mandatory amount or instance. #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, Decode)] pub enum Fungibility { Fungible(u128), From ca477f093f6e287cf3d7a3456327be8d8c7118f0 Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Mon, 2 Aug 2021 01:11:56 +0200 Subject: [PATCH 038/166] Optimize subsume_assets and add test --- xcm/xcm-executor/src/assets.rs | 44 ++++++++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/xcm/xcm-executor/src/assets.rs b/xcm/xcm-executor/src/assets.rs index 3064a4a7312a..5cb8aac02a37 100644 --- a/xcm/xcm-executor/src/assets.rs +++ b/xcm/xcm-executor/src/assets.rs @@ -104,12 +104,32 @@ impl Assets { } /// Mutate `self` to contain all given `assets`, saturating if necessary. - pub fn subsume_assets(&mut self, assets: Assets) { - // TODO: Could be done with a much faster btree entry merge and only sum the entries with the - // same key. - for asset in assets.into_assets_iter() { - self.subsume(asset) + pub fn subsume_assets(&mut self, mut assets: Assets) { + let mut f_iter = assets.fungible.iter_mut(); + let mut g_iter = self.fungible.iter_mut(); + if let (Some(mut f), Some(mut g)) = (f_iter.next(), g_iter.next()) { + loop { + if f.0 == g.0 { + // keys are equal. in this case, we add `swlf`'s balance for the asset onto `assets`, balance, knowing + // that the `append` operation which follows will clobber `self`'s value and only use `assets`'s. + *f.1 += *g.1; + } + if f.0 <= g.0 { + f = match f_iter.next() { + Some(x) => x, + None => break, + }; + } + if f.0 >= g.0 { + g = match g_iter.next() { + Some(x) => x, + None => break, + }; + } + } } + self.fungible.append(&mut assets.fungible); + self.non_fungible.append(&mut assets.non_fungible); } /// Mutate `self` to contain the given `asset`, saturating if necessary. @@ -356,6 +376,20 @@ mod tests { assets } + #[test] + fn subsume_assets_works() { + let t1 = test_assets(); + let mut t2 = Assets::new(); + t2.subsume(AF(1, 50)); + t2.subsume(ANF(2, 100)); + t2.subsume(CF(300)); + t2.subsume(CNF(500)); + let r1 = t1.clone().subsume_assets(t2.clone()); + let mut r2 = t1.clone(); + for a in t2.assets_iter() { r2.subsume(a) } + assert_eq!(r1, r2); + } + #[test] fn into_assets_iter_works() { let assets = test_assets(); From 3cc428fce5d734f41deb17c99bae76c51722f1c2 Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Mon, 2 Aug 2021 01:30:43 +0200 Subject: [PATCH 039/166] Optimize checked_sub --- xcm/xcm-executor/src/assets.rs | 52 +++++++++++++++++++++++++++++----- 1 file changed, 45 insertions(+), 7 deletions(-) diff --git a/xcm/xcm-executor/src/assets.rs b/xcm/xcm-executor/src/assets.rs index 5cb8aac02a37..bd499bd8ec62 100644 --- a/xcm/xcm-executor/src/assets.rs +++ b/xcm/xcm-executor/src/assets.rs @@ -274,12 +274,29 @@ impl Assets { } /// Consumes `self` and returns its original value excluding `asset` iff it contains at least `asset`. - pub fn checked_sub(mut self, asset: MultiAsset) -> Result<Assets, Self> { - // TODO: Optimize by doing this operation directly rather than converting into a MultiAssetFilter and - // constructing the unused `_taken` return value. - match self.try_take(asset.into()) { - Ok(_taken) => Ok(self), - Err(_) => Err(self), + pub fn checked_sub(mut self, asset: MultiAsset) -> Result<Assets, Assets> { + match asset.fun { + Fungible(amount) => { + let remove = if let Some(balance) = self.fungible.get_mut(&asset.id) { + if *balance >= amount { + *balance -= amount; + *balance == 0 + } else { + return Err(self) + } + } else { + return Err(self) + }; + if remove { + self.fungible.remove(&asset.id); + } + Ok(self) + } + NonFungible(instance) => if self.non_fungible.remove(&(asset.id, instance)) { + Ok(self) + } else { + Err(self) + }, } } @@ -384,12 +401,33 @@ mod tests { t2.subsume(ANF(2, 100)); t2.subsume(CF(300)); t2.subsume(CNF(500)); - let r1 = t1.clone().subsume_assets(t2.clone()); + let mut r1 = t1.clone(); + r1.subsume_assets(t2.clone()); let mut r2 = t1.clone(); for a in t2.assets_iter() { r2.subsume(a) } assert_eq!(r1, r2); } + #[test] + fn checked_sub_works() { + let t = test_assets(); + let t = t.checked_sub(AF(1, 50)).unwrap(); + let t = t.checked_sub(AF(1, 51)).unwrap_err(); + let t = t.checked_sub(AF(1, 50)).unwrap(); + let t = t.checked_sub(AF(1, 1)).unwrap_err(); + let t = t.checked_sub(CF(150)).unwrap(); + let t = t.checked_sub(CF(151)).unwrap_err(); + let t = t.checked_sub(CF(150)).unwrap(); + let t = t.checked_sub(CF(1)).unwrap_err(); + let t = t.checked_sub(ANF(2, 201)).unwrap_err(); + let t = t.checked_sub(ANF(2, 200)).unwrap(); + let t = t.checked_sub(ANF(2, 200)).unwrap_err(); + let t = t.checked_sub(CNF(401)).unwrap_err(); + let t = t.checked_sub(CNF(400)).unwrap(); + let t = t.checked_sub(CNF(400)).unwrap_err(); + assert_eq!(t, Assets::new()); + } + #[test] fn into_assets_iter_works() { let assets = test_assets(); From 099aea73570a56bb07a26a07ffd34f99dc6e534c Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Mon, 2 Aug 2021 01:43:54 +0200 Subject: [PATCH 040/166] XCM Builder first test fixed --- xcm/src/v0/mod.rs | 3 ++- xcm/src/v0/multiasset.rs | 12 ++++++------ xcm/src/v0/order.rs | 4 ++-- xcm/xcm-builder/src/mock.rs | 17 +++++++---------- xcm/xcm-builder/src/tests.rs | 10 +++++----- 5 files changed, 22 insertions(+), 24 deletions(-) diff --git a/xcm/src/v0/mod.rs b/xcm/src/v0/mod.rs index 38d940a16a19..473cc9f06b7b 100644 --- a/xcm/src/v0/mod.rs +++ b/xcm/src/v0/mod.rs @@ -38,7 +38,7 @@ pub use traits::{Error, Result, SendXcm, ExecuteXcm, Outcome}; /// A prelude for importing all types typically used when interacting with XCM messages. pub mod prelude { - pub use super::junction::{Junction::*, NetworkId, BodyId, BodyPart}; + pub use super::junction::{Junction::*, NetworkId::{self, *}, BodyId, BodyPart}; pub use super::multiasset::{ MultiAssets, MultiAsset, AssetId::{self, *}, @@ -52,6 +52,7 @@ pub mod prelude { pub use super::order::Order::{self, *}; pub use super::traits::{Error as XcmError, Result as XcmResult, SendXcm, ExecuteXcm, Outcome}; pub use super::{Xcm::{self, *}, OriginKind}; + pub use super::opaque; } // TODO: #2841 #XCMENCODE Efficient encodings for MultiAssets, Vec<Order>, using initial byte values 128+ to encode diff --git a/xcm/src/v0/multiasset.rs b/xcm/src/v0/multiasset.rs index c6fb07518578..207b117b9ed6 100644 --- a/xcm/src/v0/multiasset.rs +++ b/xcm/src/v0/multiasset.rs @@ -317,15 +317,15 @@ pub enum MultiAssetFilter { Wild(WildMultiAsset), } -impl From<WildMultiAsset> for MultiAssetFilter { - fn from(x: WildMultiAsset) -> Self { - Self::Wild(x) +impl<T: Into<WildMultiAsset>> From<T> for MultiAssetFilter { + fn from(x: T) -> Self { + Self::Wild(x.into()) } } -impl<T: Into<MultiAsset>> From<T> for MultiAssetFilter { - fn from(x: T) -> Self { - Self::Definite(vec![x.into()].into()) +impl From<MultiAsset> for MultiAssetFilter { + fn from(x: MultiAsset) -> Self { + Self::Definite(vec![x].into()) } } diff --git a/xcm/src/v0/order.rs b/xcm/src/v0/order.rs index 6162581f7e28..3917e6a01116 100644 --- a/xcm/src/v0/order.rs +++ b/xcm/src/v0/order.rs @@ -29,7 +29,7 @@ use super::{MultiAsset, MultiAssetFilter, MultiLocation, Xcm}; pub enum Order<Call> { /// Do nothing. Not generally used. #[codec(index = 0)] - Null, + Noop, /// Remove the asset(s) (`assets`) from holding and place equivalent assets under the ownership of `dest` within /// this consensus system. @@ -121,7 +121,7 @@ impl<Call> Order<Call> { pub fn from<C>(order: Order<C>) -> Self { use Order::*; match order { - Null => Null, + Noop => Noop, DepositAsset { assets, dest } => DepositAsset { assets, dest }, DepositReserveAsset { assets, dest, effects } diff --git a/xcm/xcm-builder/src/mock.rs b/xcm/xcm-builder/src/mock.rs index 6e9b7ff5a322..81f926626829 100644 --- a/xcm/xcm-builder/src/mock.rs +++ b/xcm/xcm-builder/src/mock.rs @@ -17,10 +17,7 @@ pub use sp_std::{fmt::Debug, marker::PhantomData, cell::RefCell}; pub use sp_std::collections::{btree_map::BTreeMap, btree_set::BTreeSet}; pub use parity_scale_codec::{Encode, Decode}; -pub use xcm::v0::{ - SendXcm, MultiLocation::*, Junction::*, MultiAsset, Xcm, Order, Result as XcmResult, Error as XcmError, - OriginKind, MultiLocation, Junction, opaque, -}; +pub use xcm::v0::prelude::*; pub use frame_support::{ ensure, parameter_types, dispatch::{Dispatchable, Parameter, Weight, DispatchError, DispatchResultWithPostInfo, DispatchInfo}, @@ -139,8 +136,8 @@ impl TransactAsset for TestAssetTransactor { ASSETS.with(|a| a.borrow_mut() .get_mut(&who) .ok_or(XcmError::NotWithdrawable)? - .try_take(what.clone()) - .map_err(|()| XcmError::NotWithdrawable) + .try_take(what.clone().into()) + .map_err(|_| XcmError::NotWithdrawable) ) } } @@ -178,14 +175,14 @@ impl ConvertOrigin<TestOrigin> for TestOriginConverter { } thread_local! { - pub static IS_RESERVE: RefCell<BTreeMap<MultiLocation, Vec<MultiAsset>>> = RefCell::new(BTreeMap::new()); - pub static IS_TELEPORTER: RefCell<BTreeMap<MultiLocation, Vec<MultiAsset>>> = RefCell::new(BTreeMap::new()); + pub static IS_RESERVE: RefCell<BTreeMap<MultiLocation, Vec<MultiAssetFilter>>> = RefCell::new(BTreeMap::new()); + pub static IS_TELEPORTER: RefCell<BTreeMap<MultiLocation, Vec<MultiAssetFilter>>> = RefCell::new(BTreeMap::new()); } -pub fn add_reserve(from: MultiLocation, asset: MultiAsset) { +pub fn add_reserve(from: MultiLocation, asset: MultiAssetFilter) { IS_RESERVE.with(|r| r.borrow_mut().entry(from).or_default().push(asset)); } #[allow(dead_code)] -pub fn add_teleporter(from: MultiLocation, asset: MultiAsset) { +pub fn add_teleporter(from: MultiLocation, asset: MultiAssetFilter) { IS_TELEPORTER.with(|r| r.borrow_mut().entry(from).or_default().push(asset)); } pub struct TestIsReserve; diff --git a/xcm/xcm-builder/src/tests.rs b/xcm/xcm-builder/src/tests.rs index 79235427be62..a0af0893d6d2 100644 --- a/xcm/xcm-builder/src/tests.rs +++ b/xcm/xcm-builder/src/tests.rs @@ -16,15 +16,14 @@ use super::*; use super::mock::*; -use {MultiAsset::*, Option::None}; -use xcm::v0::{Order, NetworkId::Any, Outcome, Response, ExecuteXcm}; +use xcm::v0::prelude::*; use xcm_executor::{XcmExecutor, Config, traits::*}; #[test] fn basic_setup_works() { - add_reserve(X1(Parent), AllConcreteFungible { id: X1(Parent) }); + add_reserve(X1(Parent), Wild((X1(Parent), WildFungible).into())); assert!(<TestConfig as Config>::IsReserve::filter_asset_location( - &ConcreteFungible { id: X1(Parent), amount: 100 }, + &(X1(Parent), 100).into(), &X1(Parent), )); @@ -36,7 +35,7 @@ fn basic_setup_works() { assert_eq!(to_account(X1(AccountIndex64{index:42, network:Any})), Ok(42)); assert_eq!(to_account(Null), Ok(3000)); } - +/* #[test] fn weigher_should_work() { let mut message = opaque::Xcm::ReserveAssetDeposited { @@ -336,3 +335,4 @@ fn prepaid_result_of_query_should_get_free_execution() { let r = XcmExecutor::<TestConfig>::execute_xcm(origin.clone(), message.clone(), weight_limit); assert_eq!(r, Outcome::Incomplete(10, XcmError::Barrier)); } +*/ From 51584424df5ead86d25364b0e837cfb3db13deaf Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Mon, 2 Aug 2021 08:55:57 +0200 Subject: [PATCH 041/166] Fix builder tests --- xcm/src/v0/mod.rs | 2 +- xcm/src/v0/multiasset.rs | 6 +++ xcm/xcm-builder/src/lib.rs | 4 +- xcm/xcm-builder/src/mock.rs | 6 +-- xcm/xcm-builder/src/tests.rs | 77 ++++++++++++++++++---------------- xcm/xcm-builder/src/weight.rs | 65 +++++++++++++++++++++++++--- xcm/xcm-executor/src/assets.rs | 16 +++---- 7 files changed, 121 insertions(+), 55 deletions(-) diff --git a/xcm/src/v0/mod.rs b/xcm/src/v0/mod.rs index 473cc9f06b7b..95bccfacf0b5 100644 --- a/xcm/src/v0/mod.rs +++ b/xcm/src/v0/mod.rs @@ -51,7 +51,7 @@ pub mod prelude { pub use super::multi_location::MultiLocation::{self, *}; pub use super::order::Order::{self, *}; pub use super::traits::{Error as XcmError, Result as XcmResult, SendXcm, ExecuteXcm, Outcome}; - pub use super::{Xcm::{self, *}, OriginKind}; + pub use super::{Xcm::{self, *}, OriginKind, Response}; pub use super::opaque; } diff --git a/xcm/src/v0/multiasset.rs b/xcm/src/v0/multiasset.rs index 207b117b9ed6..f00c73d8efee 100644 --- a/xcm/src/v0/multiasset.rs +++ b/xcm/src/v0/multiasset.rs @@ -209,6 +209,12 @@ impl From<Vec<MultiAsset>> for MultiAssets { } } +impl<T: Into<MultiAsset>> From<T> for MultiAssets { + fn from(x: T) -> Self { + Self(vec![x.into()]) + } +} + impl MultiAssets { /// A new (empty) value. pub fn new() -> Self { diff --git a/xcm/xcm-builder/src/lib.rs b/xcm/xcm-builder/src/lib.rs index 534261a9998d..339a9321e1ad 100644 --- a/xcm/xcm-builder/src/lib.rs +++ b/xcm/xcm-builder/src/lib.rs @@ -54,7 +54,9 @@ pub use fungibles_adapter::{ }; mod weight; -pub use weight::{FixedRateOfConcreteFungible, FixedWeightBounds, UsingComponents, TakeRevenue}; +pub use weight::{FixedRateOfFungible, FixedWeightBounds, UsingComponents, TakeRevenue}; +#[allow(deprecated)] +pub use weight::FixedRateOfConcreteFungible; mod matches_fungible; pub use matches_fungible::{IsAbstract, IsConcrete}; diff --git a/xcm/xcm-builder/src/mock.rs b/xcm/xcm-builder/src/mock.rs index 81f926626829..d036d2997df1 100644 --- a/xcm/xcm-builder/src/mock.rs +++ b/xcm/xcm-builder/src/mock.rs @@ -30,7 +30,7 @@ pub use xcm_executor::{ }; pub use crate::{ TakeWeightCredit, AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, FixedWeightBounds, - FixedRateOfConcreteFungible, AllowKnownQueryResponses, LocationInverter, + FixedRateOfFungible, AllowKnownQueryResponses, LocationInverter, }; pub enum TestOrigin { @@ -253,7 +253,7 @@ parameter_types! { pub static AllowUnpaidFrom: Vec<MultiLocation> = vec![]; pub static AllowPaidFrom: Vec<MultiLocation> = vec![]; // 1_000_000_000_000 => 1 unit of asset for 1 unit of Weight. - pub static WeightPrice: (MultiLocation, u128) = (Null, 1_000_000_000_000); + pub static WeightPrice: (AssetId, u128) = (Null.into(), 1_000_000_000_000); } pub type TestBarrier = ( @@ -274,6 +274,6 @@ impl Config for TestConfig { type LocationInverter = LocationInverter<TestAncestry>; type Barrier = TestBarrier; type Weigher = FixedWeightBounds<UnitWeightCost, TestCall>; - type Trader = FixedRateOfConcreteFungible<WeightPrice, ()>; + type Trader = FixedRateOfFungible<WeightPrice, ()>; type ResponseHandler = TestResponseHandler; } diff --git a/xcm/xcm-builder/src/tests.rs b/xcm/xcm-builder/src/tests.rs index a0af0893d6d2..e23c262ea660 100644 --- a/xcm/xcm-builder/src/tests.rs +++ b/xcm/xcm-builder/src/tests.rs @@ -35,14 +35,14 @@ fn basic_setup_works() { assert_eq!(to_account(X1(AccountIndex64{index:42, network:Any})), Ok(42)); assert_eq!(to_account(Null), Ok(3000)); } -/* + #[test] fn weigher_should_work() { let mut message = opaque::Xcm::ReserveAssetDeposited { - assets: vec![ConcreteFungible { id: X1(Parent), amount: 100 }], + assets: (X1(Parent), 100).into(), effects: vec![ - Order::BuyExecution { fees: All, weight: 0, debt: 30, halt_on_error: true, xcm: vec![] }, - Order::DepositAsset { assets: vec![All], dest: Null }, + Order::BuyExecution { fees: (X1(Parent), 1).into(), weight: 0, debt: 30, halt_on_error: true, xcm: vec![] }, + Order::DepositAsset { assets: All.into(), dest: Null }, ], }.into(); assert_eq!(<TestConfig as Config>::Weigher::shallow(&mut message), Ok(30)); @@ -51,7 +51,7 @@ fn weigher_should_work() { #[test] fn take_weight_credit_barrier_should_work() { let mut message = opaque::Xcm::TransferAsset { - assets: vec![ConcreteFungible { id: X1(Parent), amount: 100 }], + assets: (X1(Parent), 100).into(), dest: Null, }; @@ -80,7 +80,7 @@ fn take_weight_credit_barrier_should_work() { #[test] fn allow_unpaid_should_work() { let mut message = opaque::Xcm::TransferAsset { - assets: vec![ConcreteFungible { id: X1(Parent), amount: 100 }], + assets: (X1(Parent), 100).into(), dest: Null, }; @@ -110,7 +110,7 @@ fn allow_paid_should_work() { AllowPaidFrom::set(vec![ X1(Parent) ]); let mut message = opaque::Xcm::TransferAsset { - assets: vec![ConcreteFungible { id: X1(Parent), amount: 100 }], + assets: (X1(Parent), 100).into(), dest: Null, }; @@ -123,11 +123,12 @@ fn allow_paid_should_work() { ); assert_eq!(r, Err(())); + let fees = (X1(Parent), 1).into(); let mut underpaying_message = opaque::Xcm::ReserveAssetDeposited { - assets: vec![ConcreteFungible { id: X1(Parent), amount: 100 }], + assets: (X1(Parent), 100).into(), effects: vec![ - Order::BuyExecution { fees: All, weight: 0, debt: 20, halt_on_error: true, xcm: vec![] }, - Order::DepositAsset { assets: vec![All], dest: Null }, + Order::BuyExecution { fees, weight: 0, debt: 20, halt_on_error: true, xcm: vec![] }, + Order::DepositAsset { assets: All.into(), dest: Null }, ], }; @@ -140,11 +141,12 @@ fn allow_paid_should_work() { ); assert_eq!(r, Err(())); + let fees = (X1(Parent), 1).into(); let mut paying_message = opaque::Xcm::ReserveAssetDeposited { - assets: vec![ConcreteFungible { id: X1(Parent), amount: 100 }], + assets: (X1(Parent), 100).into(), effects: vec![ - Order::BuyExecution { fees: All, weight: 0, debt: 30, halt_on_error: true, xcm: vec![] }, - Order::DepositAsset { assets: vec![All], dest: Null }, + Order::BuyExecution { fees, weight: 0, debt: 30, halt_on_error: true, xcm: vec![] }, + Order::DepositAsset { assets: All.into(), dest: Null }, ], }; @@ -170,21 +172,22 @@ fn allow_paid_should_work() { #[test] fn paying_reserve_deposit_should_work() { AllowPaidFrom::set(vec![ X1(Parent) ]); - add_reserve(X1(Parent), AllConcreteFungible { id: X1(Parent) }); - WeightPrice::set((X1(Parent), 1_000_000_000_000)); + add_reserve(X1(Parent), (X1(Parent), WildFungible).into()); + WeightPrice::set((X1(Parent).into(), 1_000_000_000_000)); let origin = X1(Parent); + let fees = (X1(Parent), 30).into(); let message = Xcm::<TestCall>::ReserveAssetDeposited { - assets: vec![ ConcreteFungible { id: X1(Parent), amount: 100 } ], + assets: (X1(Parent), 100).into(), effects: vec![ - Order::<TestCall>::BuyExecution { fees: All, weight: 0, debt: 30, halt_on_error: true, xcm: vec![] }, - Order::<TestCall>::DepositAsset { assets: vec![ All ], dest: Null }, + Order::<TestCall>::BuyExecution { fees, weight: 0, debt: 30, halt_on_error: true, xcm: vec![] }, + Order::<TestCall>::DepositAsset { assets: All.into(), dest: Null }, ], }; let weight_limit = 50; let r = XcmExecutor::<TestConfig>::execute_xcm(origin, message, weight_limit); assert_eq!(r, Outcome::Complete(30)); - assert_eq!(assets(3000), vec![ ConcreteFungible { id: X1(Parent), amount: 70 } ]); + assert_eq!(assets(3000), vec![(X1(Parent), 70).into()]); } #[test] @@ -192,19 +195,19 @@ fn transfer_should_work() { // we'll let them have message execution for free. AllowUnpaidFrom::set(vec![ X1(Parachain(1)) ]); // Child parachain #1 owns 1000 tokens held by us in reserve. - add_asset(1001, ConcreteFungible { id: Null, amount: 1000 }); + add_asset(1001, (Null, 1000).into()); // They want to transfer 100 of them to their sibling parachain #2 let r = XcmExecutor::<TestConfig>::execute_xcm( X1(Parachain(1)), Xcm::TransferAsset { - assets: vec![ ConcreteFungible { id: Null, amount: 100 } ], + assets: (Null, 100).into(), dest: X1(AccountIndex64{index:3, network:Any}), }, 50, ); assert_eq!(r, Outcome::Complete(10)); - assert_eq!(assets(3), vec![ ConcreteFungible { id: Null, amount: 100 } ]); - assert_eq!(assets(1001), vec![ ConcreteFungible { id: Null, amount: 900 } ]); + assert_eq!(assets(3), vec![(Null, 100).into()]); + assert_eq!(assets(1001), vec![(Null, 900).into()]); assert_eq!(sent_xcm(), vec![]); } @@ -212,7 +215,7 @@ fn transfer_should_work() { fn reserve_transfer_should_work() { AllowUnpaidFrom::set(vec![ X1(Parachain(1)) ]); // Child parachain #1 owns 1000 tokens held by us in reserve. - add_asset(1001, ConcreteFungible { id: Null, amount: 1000 }); + add_asset(1001, (Null, 1000).into()); // The remote account owned by gav. let three = X1(AccountIndex64{index:3, network:Any}); @@ -221,20 +224,20 @@ fn reserve_transfer_should_work() { let r = XcmExecutor::<TestConfig>::execute_xcm( X1(Parachain(1)), Xcm::TransferReserveAsset { - assets: vec![ ConcreteFungible { id: Null, amount: 100 } ], + assets: (Null, 100).into(), dest: X1(Parachain(2)), - effects: vec![ Order::DepositAsset { assets: vec![ All ], dest: three.clone() } ], + effects: vec![ Order::DepositAsset { assets: All.into(), dest: three.clone() } ], }, 50, ); assert_eq!(r, Outcome::Complete(10)); - assert_eq!(assets(1002), vec![ ConcreteFungible { id: Null, amount: 100 } ]); + assert_eq!(assets(1002), vec![(Null, 100).into()]); assert_eq!(sent_xcm(), vec![( X1(Parachain(2)), Xcm::ReserveAssetDeposited { - assets: vec![ ConcreteFungible { id: X1(Parent), amount: 100 } ], - effects: vec![ Order::DepositAsset { assets: vec![ All ], dest: three } ], + assets: (X1(Parent), 100).into(), + effects: vec![ Order::DepositAsset { assets: All.into(), dest: three } ], }) ]); } @@ -288,14 +291,15 @@ fn transacting_should_refund_weight() { fn paid_transacting_should_refund_payment_for_unused_weight() { let one = X1(AccountIndex64{index:1, network:Any}); AllowPaidFrom::set(vec![ one.clone() ]); - add_asset(1, ConcreteFungible { id: X1(Parent), amount: 100 }); - WeightPrice::set((X1(Parent), 1_000_000_000_000)); + add_asset(1, (X1(Parent), 100).into()); + WeightPrice::set((X1(Parent).into(), 1_000_000_000_000)); let origin = one.clone(); + let fees = (X1(Parent), 100).into(); let message = Xcm::<TestCall>::WithdrawAsset { - assets: vec![ ConcreteFungible { id: X1(Parent), amount: 100 } ], // enough for 100 units of weight. + assets: (X1(Parent), 100).into(), // enough for 100 units of weight. effects: vec![ - Order::<TestCall>::BuyExecution { fees: All, weight: 70, debt: 30, halt_on_error: true, xcm: vec![ + Order::<TestCall>::BuyExecution { fees, weight: 70, debt: 30, halt_on_error: true, xcm: vec![ Xcm::<TestCall>::Transact { origin_type: OriginKind::Native, require_weight_at_most: 60, @@ -303,13 +307,13 @@ fn paid_transacting_should_refund_payment_for_unused_weight() { call: TestCall::Any(60, Some(10)).encode().into(), } ] }, - Order::<TestCall>::DepositAsset { assets: vec![ All ], dest: one.clone() }, + Order::<TestCall>::DepositAsset { assets: All.into(), dest: one.clone() }, ], }; let weight_limit = 100; let r = XcmExecutor::<TestConfig>::execute_xcm(origin, message, weight_limit); assert_eq!(r, Outcome::Complete(50)); - assert_eq!(assets(1), vec![ ConcreteFungible { id: X1(Parent), amount: 50 } ]); + assert_eq!(assets(1), vec![(X1(Parent), 50).into()]); } #[test] @@ -319,7 +323,7 @@ fn prepaid_result_of_query_should_get_free_execution() { // 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(vec![ ConcreteFungible { id: X1(Parent), amount: 100 } ]); + let the_response = Response::Assets((X1(Parent), 100).into()); let message = Xcm::<TestCall>::QueryResponse { query_id, response: the_response.clone(), @@ -335,4 +339,3 @@ fn prepaid_result_of_query_should_get_free_execution() { let r = XcmExecutor::<TestConfig>::execute_xcm(origin.clone(), message.clone(), weight_limit); assert_eq!(r, Outcome::Incomplete(10, XcmError::Barrier)); } -*/ diff --git a/xcm/xcm-builder/src/weight.rs b/xcm/xcm-builder/src/weight.rs index ef18fcf99783..500db2a393c1 100644 --- a/xcm/xcm-builder/src/weight.rs +++ b/xcm/xcm-builder/src/weight.rs @@ -16,7 +16,7 @@ use sp_std::{result::Result, marker::PhantomData, convert::TryInto}; use parity_scale_codec::Decode; -use xcm::v0::{Xcm, Order, MultiAsset, MultiLocation, Error, AssetId::Concrete}; +use xcm::v0::{Xcm, Order, MultiAsset, AssetId, MultiLocation, Error, AssetId::Concrete}; use sp_runtime::traits::{Zero, Saturating, SaturatedConversion}; use frame_support::traits::{Get, OnUnbalanced as OnUnbalancedT, tokens::currency::Currency as CurrencyT}; use frame_support::weights::{Weight, GetDispatchInfo, WeightToFeePolynomial}; @@ -92,10 +92,12 @@ impl TakeRevenue for () { /// /// The constant `Get` type parameter should be the concrete fungible ID and the amount of it required for /// one second of weight. +#[deprecated = "Use `FixedRateOfFungible` instead"] pub struct FixedRateOfConcreteFungible< T: Get<(MultiLocation, u128)>, R: TakeRevenue, >(Weight, u128, PhantomData<(T, R)>); +#[allow(deprecated)] impl<T: Get<(MultiLocation, u128)>, R: TakeRevenue> WeightTrader for FixedRateOfConcreteFungible<T, R> { fn new() -> Self { Self(0, 0, PhantomData) } @@ -115,13 +117,62 @@ impl<T: Get<(MultiLocation, u128)>, R: TakeRevenue> WeightTrader for FixedRateOf let amount = units_per_second * (weight as u128) / 1_000_000_000_000u128; self.0 -= weight; self.1 = self.1.saturating_sub(amount); - Some((Concrete(id), amount).into()) + if amount > 0 { + Some((Concrete(id), amount).into()) + } else { + None + } } } - +#[allow(deprecated)] impl<T: Get<(MultiLocation, u128)>, R: TakeRevenue> Drop for FixedRateOfConcreteFungible<T, R> { fn drop(&mut self) { - R::take_revenue((Concrete(T::get().0), self.1).into()); + if self.1 > 0 { + R::take_revenue((Concrete(T::get().0), self.1).into()); + } + } +} + +/// Simple fee calculator that requires payment in a single fungible at a fixed rate. +/// +/// The constant `Get` type parameter should be the fungible ID and the amount of it required for +/// one second of weight. +pub struct FixedRateOfFungible< + T: Get<(AssetId, u128)>, + R: TakeRevenue, +>(Weight, u128, PhantomData<(T, R)>); +impl<T: Get<(AssetId, u128)>, R: TakeRevenue> WeightTrader for FixedRateOfFungible<T, R> { + fn new() -> Self { Self(0, 0, PhantomData) } + + fn buy_weight(&mut self, weight: Weight, payment: Assets) -> Result<Assets, Error> { + let (id, units_per_second) = T::get(); + use frame_support::weights::constants::WEIGHT_PER_SECOND; + let amount = units_per_second * (weight as u128) / (WEIGHT_PER_SECOND as u128); + let unused = payment.checked_sub((id, amount).into()).map_err(|_| Error::TooExpensive)?; + self.0 = self.0.saturating_add(weight); + self.1 = self.1.saturating_add(amount); + Ok(unused) + } + + fn refund_weight(&mut self, weight: Weight) -> Option<MultiAsset> { + let (id, units_per_second) = T::get(); + let weight = weight.min(self.0); + let amount = units_per_second * (weight as u128) / 1_000_000_000_000u128; + self.0 -= weight; + self.1 = self.1.saturating_sub(amount); + if amount > 0 { + Some((id, amount).into()) + } else { + None + } + } +} + +impl<T: Get<(AssetId, u128)>, R: TakeRevenue> Drop for FixedRateOfFungible<T, R> { + fn drop(&mut self) { + if self.1 > 0 { + R::take_revenue((T::get().0, self.1).into()); + } } } @@ -159,7 +210,11 @@ impl< self.0 -= weight; self.1 = self.1.saturating_sub(amount); let amount: u128 = amount.saturated_into(); - Some((AssetId::get(), amount).into()) + if amount > 0 { + Some((AssetId::get(), amount).into()) + } else { + None + } } } diff --git a/xcm/xcm-executor/src/assets.rs b/xcm/xcm-executor/src/assets.rs index bd499bd8ec62..23e576a35a9b 100644 --- a/xcm/xcm-executor/src/assets.rs +++ b/xcm/xcm-executor/src/assets.rs @@ -35,6 +35,14 @@ pub struct Assets { pub non_fungible: BTreeSet<(AssetId, AssetInstance)>, } +impl From<MultiAsset> for Assets { + fn from(asset: MultiAsset) -> Assets { + let mut result = Self::default(); + result.subsume(asset); + result + } +} + impl From<Vec<MultiAsset>> for Assets { fn from(assets: Vec<MultiAsset>) -> Assets { let mut result = Self::default(); @@ -63,14 +71,6 @@ impl From<Assets> for MultiAssets { } } -impl From<MultiAsset> for Assets { - fn from(asset: MultiAsset) -> Assets { - let mut result = Self::default(); - result.subsume(asset); - result - } -} - /// An error emitted by `take` operations. #[derive(Debug)] pub enum TakeError { From 6814aa8db13f4a64ce133fadc44811f36c7faa3b Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Mon, 2 Aug 2021 11:15:53 +0200 Subject: [PATCH 042/166] Fix doc test --- xcm/xcm-executor/src/assets.rs | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/xcm/xcm-executor/src/assets.rs b/xcm/xcm-executor/src/assets.rs index 23e576a35a9b..41fafbf67c40 100644 --- a/xcm/xcm-executor/src/assets.rs +++ b/xcm/xcm-executor/src/assets.rs @@ -308,20 +308,13 @@ impl Assets { /// /// ``` /// use xcm_executor::Assets; - /// use xcm::v0::{MultiAsset, MultiLocation}; - /// let assets_i_have: Assets = vec![ - /// MultiAsset::ConcreteFungible { id: MultiLocation::Null, amount: 100 }, - /// MultiAsset::AbstractFungible { id: vec![0], amount: 100 }, - /// ].into(); - /// let assets_they_want: Assets = vec![ - /// MultiAsset::ConcreteFungible { id: MultiLocation::Null, amount: 200 }, - /// MultiAsset::AbstractFungible { id: vec![0], amount: 50 }, - /// ].into(); + /// use xcm::v0::prelude::*; + /// let assets_i_have: Assets = vec![ (Null, 100).into(), (vec![0], 100).into() ].into(); + /// let assets_they_want: MultiAssetFilter = vec![ (Null, 200).into(), (vec![0], 50).into() [.into(); /// - /// let assets_we_can_trade: Assets = assets_i_have.min(assets_they_want.assets_iter()); + /// let assets_we_can_trade: Assets = assets_i_have.min(&assets_they_want); /// assert_eq!(assets_we_can_trade.into_assets_iter().collect::<Vec<_>>(), vec![ - /// MultiAsset::ConcreteFungible { id: MultiLocation::Null, amount: 100 }, - /// MultiAsset::AbstractFungible { id: vec![0], amount: 50 }, + /// (Null, 100).into(), (vec![0], 50).into(), /// ]); /// ``` pub fn min(&self, mask: &MultiAssetFilter) -> Assets { From 8d8aa5cfead7d1d772728e86fcdfd466fe35db71 Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Mon, 2 Aug 2021 04:41:34 -0700 Subject: [PATCH 043/166] Make xcm-simulator compile --- xcm/xcm-simulator/example/src/parachain.rs | 2 +- xcm/xcm-simulator/example/src/relay_chain.rs | 4 ++-- xcm/xcm-simulator/src/lib.rs | 10 +++++----- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/xcm/xcm-simulator/example/src/parachain.rs b/xcm/xcm-simulator/example/src/parachain.rs index f4ad471ff697..e8cb7021bd3f 100644 --- a/xcm/xcm-simulator/example/src/parachain.rs +++ b/xcm/xcm-simulator/example/src/parachain.rs @@ -110,7 +110,7 @@ parameter_types! { } parameter_types! { - pub const KsmLocation: MultiLocation = MultiLocation::X1(Parent); + pub const KsmLocation: MultiLocation = MultiLocation::with_parents(1).expect("well-formed XCM; qed"); pub const RelayNetwork: NetworkId = NetworkId::Kusama; pub Ancestry: MultiLocation = Parachain(MsgQueue::parachain_id().into()).into(); } diff --git a/xcm/xcm-simulator/example/src/relay_chain.rs b/xcm/xcm-simulator/example/src/relay_chain.rs index c69f20d05eaf..26a9af806c54 100644 --- a/xcm/xcm-simulator/example/src/relay_chain.rs +++ b/xcm/xcm-simulator/example/src/relay_chain.rs @@ -92,10 +92,10 @@ impl shared::Config for Runtime {} impl configuration::Config for Runtime {} parameter_types! { - pub const KsmLocation: MultiLocation = MultiLocation::Null; + pub const KsmLocation: MultiLocation = MultiLocation::empty(); pub const KusamaNetwork: NetworkId = NetworkId::Kusama; pub const AnyNetwork: NetworkId = NetworkId::Any; - pub Ancestry: MultiLocation = MultiLocation::Null; + pub Ancestry: MultiLocation = MultiLocation::empty(); pub UnitWeightCost: Weight = 1_000; } diff --git a/xcm/xcm-simulator/src/lib.rs b/xcm/xcm-simulator/src/lib.rs index 096d62b61695..c875141c401c 100644 --- a/xcm/xcm-simulator/src/lib.rs +++ b/xcm/xcm-simulator/src/lib.rs @@ -194,8 +194,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() { + Null if destination.parent_count() == 1 => { let encoded = $crate::encode_xcm(message, $crate::MessageKind::Ump); let _ = <$relay_chain>::process_upward_message( T::get(), &encoded[..], @@ -204,7 +204,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( @@ -225,9 +225,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( From 825a2aa0712eb582a0df3a1787b305d07f5f5b34 Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Mon, 2 Aug 2021 06:13:49 -0700 Subject: [PATCH 044/166] Make xcm-simulator-example compile --- xcm/src/v0/multi_location.rs | 9 ++++++++ xcm/xcm-simulator/example/src/lib.rs | 24 +++++++++++----------- xcm/xcm-simulator/example/src/parachain.rs | 19 ++++++++++------- 3 files changed, 33 insertions(+), 19 deletions(-) diff --git a/xcm/src/v0/multi_location.rs b/xcm/src/v0/multi_location.rs index 7c1efaa5e893..3ce4aeabe190 100644 --- a/xcm/src/v0/multi_location.rs +++ b/xcm/src/v0/multi_location.rs @@ -125,6 +125,15 @@ impl MultiLocation { MultiLocation { parents: 0, interior: Junctions::Null } } + /// Creates a new `MultiLocation` with the specified number of parents in the `P` const generic + /// parameter and a `Null` interior. + pub const fn with_parents_const<const P: u8>() -> MultiLocation { + MultiLocation { + parents: P, + interior: Junctions::Null, + } + } + /// Creates a new `MultiLocation` with the specified number of parents and a `Null` interior. /// Returns an error if `parents` is greater than `MAX_MULTILOCATION_LENGTH`. pub const fn with_parents(parents: u8) -> result::Result<MultiLocation, ()> { diff --git a/xcm/xcm-simulator/example/src/lib.rs b/xcm/xcm-simulator/example/src/lib.rs index f318409bf187..032cbd8c8674 100644 --- a/xcm/xcm-simulator/example/src/lib.rs +++ b/xcm/xcm-simulator/example/src/lib.rs @@ -101,10 +101,10 @@ mod tests { use codec::Encode; use frame_support::assert_ok; use xcm::v0::{ - Junction::{self, Parachain, Parent}, + Junction::{self, Parachain}, + Junctions::*, MultiAsset::*, - MultiLocation::*, - NetworkId, OriginKind, + MultiLocation, NetworkId, OriginKind, Xcm::*, }; use xcm_simulator::TestExt; @@ -118,8 +118,8 @@ mod tests { ); Relay::execute_with(|| { assert_ok!(RelayChainPalletXcm::send_xcm( - Null, - X1(Parachain(1)), + MultiLocation::empty(), + X1(Parachain(1)).into(), Transact { origin_type: OriginKind::SovereignAccount, require_weight_at_most: INITIAL_BALANCE as u64, @@ -145,8 +145,8 @@ mod tests { ); ParaA::execute_with(|| { assert_ok!(ParachainPalletXcm::send_xcm( - Null, - X1(Parent), + MultiLocation::empty(), + MultiLocation::with_parents(1).unwrap(), Transact { origin_type: OriginKind::SovereignAccount, require_weight_at_most: INITIAL_BALANCE as u64, @@ -172,8 +172,8 @@ mod tests { ); ParaA::execute_with(|| { assert_ok!(ParachainPalletXcm::send_xcm( - Null, - X2(Parent, Parachain(2)), + MultiLocation::empty(), + MultiLocation::new(1, X1(Parachain(2))).unwrap(), Transact { origin_type: OriginKind::SovereignAccount, require_weight_at_most: INITIAL_BALANCE as u64, @@ -197,9 +197,9 @@ mod tests { Relay::execute_with(|| { assert_ok!(RelayChainPalletXcm::reserve_transfer_assets( relay_chain::Origin::signed(ALICE), - X1(Parachain(1)), - X1(Junction::AccountId32 { network: NetworkId::Any, id: ALICE.into() }), - vec![ConcreteFungible { id: Null, amount: 123 }], + X1(Parachain(1)).into(), + X1(Junction::AccountId32 { network: NetworkId::Any, id: ALICE.into() }).into(), + vec![ConcreteFungible { id: MultiLocation::empty(), amount: 123 }], 123, )); }); diff --git a/xcm/xcm-simulator/example/src/parachain.rs b/xcm/xcm-simulator/example/src/parachain.rs index e8cb7021bd3f..cd92bdd80d44 100644 --- a/xcm/xcm-simulator/example/src/parachain.rs +++ b/xcm/xcm-simulator/example/src/parachain.rs @@ -38,9 +38,10 @@ use polkadot_parachain::primitives::{ use xcm::{ v0::{ Error as XcmError, ExecuteXcm, - Junction::{Parachain, Parent}, + Junction::Parachain, + Junctions::X1, MultiAsset, - MultiLocation::{self, X1}, + MultiLocation, NetworkId, Outcome, Xcm, }, VersionedXcm, @@ -110,7 +111,7 @@ parameter_types! { } parameter_types! { - pub const KsmLocation: MultiLocation = MultiLocation::with_parents(1).expect("well-formed XCM; qed"); + pub const KsmLocation: MultiLocation = MultiLocation::with_parents_const::<1>(); pub const RelayNetwork: NetworkId = NetworkId::Kusama; pub Ancestry: MultiLocation = Parachain(MsgQueue::parachain_id().into()).into(); } @@ -129,7 +130,7 @@ pub type XcmOriginToCallOrigin = ( parameter_types! { pub const UnitWeightCost: Weight = 1; - pub KsmPerSecond: (MultiLocation, u128) = (X1(Parent), 1); + pub KsmPerSecond: (MultiLocation, u128) = (MultiLocation::with_parents(1).unwrap(), 1); } pub type LocalAssetTransactor = @@ -219,8 +220,8 @@ pub mod mock_msg_queue { let hash = Encode::using_encoded(&xcm, T::Hashing::hash); let (result, event) = match Xcm::<T::Call>::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()))).unwrap(); + 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 @@ -275,7 +276,11 @@ pub mod mock_msg_queue { Self::deposit_event(Event::UnsupportedVersion(id)); }, Ok(Ok(x)) => { - let outcome = T::XcmExecutor::execute_xcm(Parent.into(), x, limit); + let outcome = T::XcmExecutor::execute_xcm( + MultiLocation::with_parents(1).unwrap(), + x, + limit, + ); Self::deposit_event(Event::ExecutedDownward(id, outcome)); }, } From 4f4693a249f85fe992b1c9ba762e11084c62d912 Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Mon, 2 Aug 2021 06:14:53 -0700 Subject: [PATCH 045/166] Make spellcheck happy --- xcm/xcm-simulator/example/src/parachain.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xcm/xcm-simulator/example/src/parachain.rs b/xcm/xcm-simulator/example/src/parachain.rs index cd92bdd80d44..363b82eea558 100644 --- a/xcm/xcm-simulator/example/src/parachain.rs +++ b/xcm/xcm-simulator/example/src/parachain.rs @@ -188,7 +188,7 @@ pub mod mock_msg_queue { #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event<T: Config> { // XCMP - /// Some XCM was executed ok. + /// Some XCM was executed successfully. Success(Option<T::Hash>), /// Some XCM failed. Fail(Option<T::Hash>, XcmError), From 8178647599162373d6b9d997b967640ac69f64b5 Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Mon, 2 Aug 2021 06:38:23 -0700 Subject: [PATCH 046/166] cargo fmt --- runtime/westend/src/lib.rs | 2 +- xcm/src/v0/multi_location.rs | 5 +---- xcm/xcm-simulator/example/src/parachain.rs | 8 ++------ 3 files changed, 4 insertions(+), 11 deletions(-) diff --git a/runtime/westend/src/lib.rs b/runtime/westend/src/lib.rs index 5d436af6b8af..b1b9d58721f1 100644 --- a/runtime/westend/src/lib.rs +++ b/runtime/westend/src/lib.rs @@ -46,7 +46,7 @@ use runtime_parachains::{ use xcm::v0::{ Junction::Parachain, - Junctions::{Null, X1}, + Junctions::{Null, X1}, MultiAsset::{self, AllConcreteFungible}, MultiLocation, NetworkId, Xcm, }; diff --git a/xcm/src/v0/multi_location.rs b/xcm/src/v0/multi_location.rs index 3ce4aeabe190..68e1761e7c00 100644 --- a/xcm/src/v0/multi_location.rs +++ b/xcm/src/v0/multi_location.rs @@ -128,10 +128,7 @@ impl MultiLocation { /// Creates a new `MultiLocation` with the specified number of parents in the `P` const generic /// parameter and a `Null` interior. pub const fn with_parents_const<const P: u8>() -> MultiLocation { - MultiLocation { - parents: P, - interior: Junctions::Null, - } + MultiLocation { parents: P, interior: Junctions::Null } } /// Creates a new `MultiLocation` with the specified number of parents and a `Null` interior. diff --git a/xcm/xcm-simulator/example/src/parachain.rs b/xcm/xcm-simulator/example/src/parachain.rs index 363b82eea558..569abf5dc6b0 100644 --- a/xcm/xcm-simulator/example/src/parachain.rs +++ b/xcm/xcm-simulator/example/src/parachain.rs @@ -37,12 +37,8 @@ use polkadot_parachain::primitives::{ }; use xcm::{ v0::{ - Error as XcmError, ExecuteXcm, - Junction::Parachain, - Junctions::X1, - MultiAsset, - MultiLocation, - NetworkId, Outcome, Xcm, + Error as XcmError, ExecuteXcm, Junction::Parachain, Junctions::X1, MultiAsset, + MultiLocation, NetworkId, Outcome, Xcm, }, VersionedXcm, }; From 529a931a1f3058855b3ccc51274552cc4852f1cb Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Mon, 2 Aug 2021 16:12:19 +0200 Subject: [PATCH 047/166] fix some doc tests --- xcm/xcm-builder/src/matches_fungible.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/xcm/xcm-builder/src/matches_fungible.rs b/xcm/xcm-builder/src/matches_fungible.rs index 8ec1893ee9df..6b80994d1989 100644 --- a/xcm/xcm-builder/src/matches_fungible.rs +++ b/xcm/xcm-builder/src/matches_fungible.rs @@ -28,17 +28,16 @@ use xcm_executor::traits::MatchesFungible; /// # Example /// /// ``` -/// use xcm::v0::{MultiAsset, MultiLocation, Junction}; +/// use xcm::v0::prelude::*; /// use xcm_builder::IsConcrete; /// use xcm_executor::traits::MatchesFungible; /// /// frame_support::parameter_types! { -/// pub TargetLocation: MultiLocation = MultiLocation::X1(Junction::Parent); +/// pub TargetLocation: MultiLocation = X1(Parent); /// } /// /// # fn main() { -/// let id = MultiLocation::X1(Junction::Parent); -/// let asset = MultiAsset::ConcreteFungible { id, amount: 999u128 }; +/// let asset = (X1(Parent), 999).into(); /// // match `asset` if it is a concrete asset in `TargetLocation`. /// assert_eq!(<IsConcrete<TargetLocation> as MatchesFungible<u128>>::matches_fungible(&asset), Some(999)); /// # } @@ -59,7 +58,7 @@ impl<T: Get<MultiLocation>, B: TryFrom<u128>> MatchesFungible<B> for IsConcrete< /// # Example /// /// ``` -/// use xcm::v0::{MultiAsset}; +/// use xcm::v0::prelude::*; /// use xcm_builder::IsAbstract; /// use xcm_executor::traits::MatchesFungible; /// @@ -68,7 +67,7 @@ impl<T: Get<MultiLocation>, B: TryFrom<u128>> MatchesFungible<B> for IsConcrete< /// } /// /// # fn main() { -/// let asset = MultiAsset::AbstractFungible { id: vec![7u8], amount: 999u128 }; +/// let asset = (vec![7u8], 999).into(); /// // match `asset` if it is a concrete asset in `TargetLocation`. /// assert_eq!(<IsAbstract<TargetLocation> as MatchesFungible<u128>>::matches_fungible(&asset), Some(999)); /// # } From 3e93d54d0217b271f553d299e3314852f5c6701e Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Mon, 2 Aug 2021 16:17:15 +0200 Subject: [PATCH 048/166] spelling --- scripts/gitlab/lingua.dic | 1 + xcm/src/v0/multiasset.rs | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/scripts/gitlab/lingua.dic b/scripts/gitlab/lingua.dic index a532700e3a5d..c0fc608a45b5 100644 --- a/scripts/gitlab/lingua.dic +++ b/scripts/gitlab/lingua.dic @@ -68,6 +68,7 @@ extrinsics fedora/M FRAME/MS FSMs +fungibility gameable getter/MS GiB/S diff --git a/xcm/src/v0/multiasset.rs b/xcm/src/v0/multiasset.rs index f00c73d8efee..9356e258d1fc 100644 --- a/xcm/src/v0/multiasset.rs +++ b/xcm/src/v0/multiasset.rs @@ -16,7 +16,7 @@ //! Cross-Consensus Message format asset data structures. //! -//! This encompasses four types for repesenting assets: +//! This encompasses four types for representing assets: //! - `MultiAsset`: A description of a single asset, either an instance of a non-fungible or some amount of a fungible. //! - `MultiAssets`: A collection of `MultiAsset`s. These are stored in a `Vec` and sorted with fungibles first. //! - `Wild`: A single asset wildcard, this can either be "all" assets, or all assets of a specific kind. @@ -184,7 +184,7 @@ impl MultiAsset { -/// A vec of MultiAssets. There may be no duplicate fungible items in here and when decoding, they must be sorted. +/// A `Vec` of `MultiAsset`s. There may be no duplicate fungible items in here and when decoding, they must be sorted. #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode)] pub struct MultiAssets(Vec<MultiAsset>); @@ -221,7 +221,7 @@ impl MultiAssets { Self(Vec::new()) } - /// Add some asset onto the multiasset list. This is quite a laborious operation since it maintains the ordering. + /// Add some asset onto the list. This is quite a laborious operation since it maintains the ordering. pub fn push(&mut self, a: MultiAsset) { if let Fungibility::Fungible(ref amount) = a.fun { for asset in self.0.iter_mut().filter(|x| x.id == a.id) { @@ -274,7 +274,7 @@ pub enum WildFungibility { #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, Decode)] pub enum WildMultiAsset { - /// All assets in the holding register, up to usize individual assets (different instances of non-fungibles could + /// All assets in the holding register, up to `usize` individual assets (different instances of non-fungibles could /// as separate assets). All, // TODO: AllOf { fun: WildFungibility, id: AssetId } From f42b3abca40d6ada00321c21ece7793bb6d846b8 Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Mon, 2 Aug 2021 16:22:32 +0200 Subject: [PATCH 049/166] named fields for AllOf --- runtime/kusama/src/lib.rs | 2 +- runtime/rococo/src/lib.rs | 2 +- runtime/westend/src/lib.rs | 2 +- xcm/src/v0/multiasset.rs | 11 +++++------ xcm/xcm-executor/src/assets.rs | 8 ++++---- 5 files changed, 12 insertions(+), 13 deletions(-) diff --git a/runtime/kusama/src/lib.rs b/runtime/kusama/src/lib.rs index a69e46f8ef8a..e72b7ed1b5e1 100644 --- a/runtime/kusama/src/lib.rs +++ b/runtime/kusama/src/lib.rs @@ -1259,7 +1259,7 @@ pub type XcmRouter = ( ); parameter_types! { - pub const Kusama: MultiAssetFilter = Wild(AllOf(WildFungible, Concrete(KsmLocation::get()))); + pub const Kusama: MultiAssetFilter = Wild(AllOf { fun: WildFungible, id: Concrete(KsmLocation::get()) }); pub const KusamaForStatemint: (MultiAssetFilter, MultiLocation) = (Kusama::get(), X1(Parachain(1000))); } pub type TrustedTeleporters = ( diff --git a/runtime/rococo/src/lib.rs b/runtime/rococo/src/lib.rs index f25ce35baa84..292de1b633cf 100644 --- a/runtime/rococo/src/lib.rs +++ b/runtime/rococo/src/lib.rs @@ -629,7 +629,7 @@ pub type XcmRouter = ( use xcm::v0::prelude::*; parameter_types! { - pub const Rococo: MultiAssetFilter = Wild(AllOf(WildFungible, Concrete(RocLocation::get()))); + 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))); diff --git a/runtime/westend/src/lib.rs b/runtime/westend/src/lib.rs index 1e0f16918a72..860b3f1bc851 100644 --- a/runtime/westend/src/lib.rs +++ b/runtime/westend/src/lib.rs @@ -907,7 +907,7 @@ pub type XcmRouter = ( parameter_types! { pub const WestendForWestmint: (MultiAssetFilter, MultiLocation) = - (Wild(AllOf(WildFungible, Concrete(WndLocation::get()))), X1(Parachain(1000))); + (Wild(AllOf { fun: WildFungible, id: Concrete(WndLocation::get()) }), X1(Parachain(1000))); } pub type TrustedTeleporters = ( xcm_builder::Case<WestendForWestmint>, diff --git a/xcm/src/v0/multiasset.rs b/xcm/src/v0/multiasset.rs index 9356e258d1fc..351665baaa0c 100644 --- a/xcm/src/v0/multiasset.rs +++ b/xcm/src/v0/multiasset.rs @@ -90,7 +90,7 @@ impl AssetId { /// Use the value of `self` along with a `fun` fungibility specifier to create the corresponding `WildMultiAsset` /// wildcard (`AllOf`) value. pub fn into_wild(self, fun: WildFungibility) -> WildMultiAsset { - WildMultiAsset::AllOf(fun, self) + WildMultiAsset::AllOf { fun, id: self } } } @@ -277,10 +277,9 @@ pub enum WildMultiAsset { /// All assets in the holding register, up to `usize` individual assets (different instances of non-fungibles could /// as separate assets). All, - // TODO: AllOf { fun: WildFungibility, id: AssetId } /// All assets in the holding register of a given fungibility and ID. If operating on non-fungibles, then a limit /// is provided for the maximum amount of matching instances. - AllOf(WildFungibility, AssetId), + AllOf { fun: WildFungibility, id: AssetId }, } impl WildMultiAsset { @@ -291,7 +290,7 @@ impl WildMultiAsset { pub fn contains(&self, inner: &MultiAsset) -> bool { use WildMultiAsset::*; match self { - AllOf(fun, id) => inner.fun.is_kind(*fun) && &inner.id == id, + AllOf { fun, id } => inner.fun.is_kind(*fun) && &inner.id == id, All => true, } } @@ -300,7 +299,7 @@ impl WildMultiAsset { pub fn reanchor(&mut self, prepend: &MultiLocation) -> Result<(), ()> { use WildMultiAsset::*; match self { - AllOf(_, ref mut id) => id.reanchor(prepend).map_err(|_| ()), + AllOf { ref mut id, .. } => id.reanchor(prepend).map_err(|_| ()), _ => Ok(()), } } @@ -308,7 +307,7 @@ impl WildMultiAsset { impl<A: Into<AssetId>, B: Into<WildFungibility>> From<(A, B)> for WildMultiAsset { fn from((id, fun): (A, B)) -> WildMultiAsset { - WildMultiAsset::AllOf(fun.into(), id.into()) + WildMultiAsset::AllOf { fun: fun.into(), id: id.into() } } } diff --git a/xcm/xcm-executor/src/assets.rs b/xcm/xcm-executor/src/assets.rs index 41fafbf67c40..85ab40a8eb9b 100644 --- a/xcm/xcm-executor/src/assets.rs +++ b/xcm/xcm-executor/src/assets.rs @@ -206,12 +206,12 @@ impl Assets { let mut taken = Assets::new(); match mask { MultiAssetFilter::Wild(All) => return Ok(self.swapped(Assets::new())), - MultiAssetFilter::Wild(AllOf(WildFungible, id)) => { + MultiAssetFilter::Wild(AllOf { fun: WildFungible, id }) => { if let Some((id, amount)) = self.fungible.remove_entry(&id) { taken.fungible.insert(id, amount); } } - MultiAssetFilter::Wild(AllOf(WildNonFungible, id)) => { + MultiAssetFilter::Wild(AllOf { fun: WildNonFungible, id }) => { let non_fungible = mem::replace(&mut self.non_fungible, Default::default()); non_fungible.into_iter().for_each(|(c, instance)| { if c == id { @@ -321,12 +321,12 @@ impl Assets { let mut masked = Assets::new(); match mask { MultiAssetFilter::Wild(All) => return self.clone(), - MultiAssetFilter::Wild(AllOf(WildFungible, id)) => { + MultiAssetFilter::Wild(AllOf { fun: WildFungible, id }) => { if let Some(&amount) = self.fungible.get(&id) { masked.fungible.insert(id.clone(), amount); } } - MultiAssetFilter::Wild(AllOf(WildNonFungible, id)) => { + MultiAssetFilter::Wild(AllOf { fun: WildNonFungible, id }) => { self.non_fungible.iter().for_each(|(ref c, ref instance)| { if c == id { masked.non_fungible.insert((c.clone(), instance.clone())); From 260f8a42421a51b034836c759942b1246a8b1941 Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Tue, 3 Aug 2021 02:23:27 -0700 Subject: [PATCH 050/166] Fix subtle bug where Null is treated as an identifier --- xcm/xcm-simulator/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xcm/xcm-simulator/src/lib.rs b/xcm/xcm-simulator/src/lib.rs index 64edb2000160..22fb3e57a1f4 100644 --- a/xcm/xcm-simulator/src/lib.rs +++ b/xcm/xcm-simulator/src/lib.rs @@ -196,7 +196,7 @@ macro_rules! decl_test_network { use $crate::{UmpSink, XcmpMessageHandlerT}; match destination.interior() { - Null if destination.parent_count() == 1 => { + $crate::Junctions::Null if destination.parent_count() == 1 => { let encoded = $crate::encode_xcm(message, $crate::MessageKind::Ump); let _ = <$relay_chain>::process_upward_message( T::get(), &encoded[..], From 2a2af5becce51ecd251ff24461ef76e3b0befa8e Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Tue, 3 Aug 2021 02:55:57 -0700 Subject: [PATCH 051/166] Add FIXME comment awaiting for const generics eval stabilization --- xcm/src/v0/multi_location.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/xcm/src/v0/multi_location.rs b/xcm/src/v0/multi_location.rs index 68e1761e7c00..77d30bc7fb5a 100644 --- a/xcm/src/v0/multi_location.rs +++ b/xcm/src/v0/multi_location.rs @@ -127,6 +127,8 @@ impl MultiLocation { /// Creates a new `MultiLocation` with the specified number of parents in the `P` const generic /// parameter and a `Null` interior. + // #FIXME: Use a where clause to evaluate P for well-formedness once const eval of const + // generics is possible. pub const fn with_parents_const<const P: u8>() -> MultiLocation { MultiLocation { parents: P, interior: Junctions::Null } } From 97051b283461f486d00fd59842c79b7161d33684 Mon Sep 17 00:00:00 2001 From: Gavin Wood <gavin@parity.io> Date: Tue, 3 Aug 2021 17:47:03 +0200 Subject: [PATCH 052/166] Update xcm/src/v0/multiasset.rs Co-authored-by: Alexander Popiak <alexander.popiak@parity.io> --- xcm/src/v0/multiasset.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/xcm/src/v0/multiasset.rs b/xcm/src/v0/multiasset.rs index 351665baaa0c..944e449b60f9 100644 --- a/xcm/src/v0/multiasset.rs +++ b/xcm/src/v0/multiasset.rs @@ -272,6 +272,7 @@ pub enum WildFungibility { NonFungible, } +/// A wildcard representing a set of assets. #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, Decode)] pub enum WildMultiAsset { /// All assets in the holding register, up to `usize` individual assets (different instances of non-fungibles could From 84b79cf71ad03191e5f9c62cc863c265f9d70e70 Mon Sep 17 00:00:00 2001 From: Gavin Wood <gavin@parity.io> Date: Tue, 3 Aug 2021 17:49:07 +0200 Subject: [PATCH 053/166] Update xcm/src/v0/multiasset.rs Co-authored-by: Alexander Popiak <alexander.popiak@parity.io> --- xcm/src/v0/multiasset.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/xcm/src/v0/multiasset.rs b/xcm/src/v0/multiasset.rs index 944e449b60f9..dcd1d9f905c6 100644 --- a/xcm/src/v0/multiasset.rs +++ b/xcm/src/v0/multiasset.rs @@ -315,8 +315,10 @@ impl<A: Into<AssetId>, B: Into<WildFungibility>> From<(A, B)> for WildMultiAsset -/// `MultiAsset` collection, either `MultiAssets` or a single wildcard. Note: vectors of wildcards -/// whose encoding is supported in XCM v0 are unsupported in this implementation and will result in a decode error. +/// `MultiAsset` collection, either `MultiAssets` or a single wildcard. +/// +/// Note: Vectors of wildcards whose encoding is supported in XCM v0 are unsupported +/// in this implementation and will result in a decode error. #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, Decode)] pub enum MultiAssetFilter { Definite(MultiAssets), From 1f988728108b30ecf893b716bd0406546f578b76 Mon Sep 17 00:00:00 2001 From: Gavin Wood <gavin@parity.io> Date: Tue, 3 Aug 2021 17:49:27 +0200 Subject: [PATCH 054/166] Update xcm/src/v0/multiasset.rs Co-authored-by: Alexander Popiak <alexander.popiak@parity.io> --- xcm/src/v0/multiasset.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/xcm/src/v0/multiasset.rs b/xcm/src/v0/multiasset.rs index dcd1d9f905c6..0f3ea7f1ec8e 100644 --- a/xcm/src/v0/multiasset.rs +++ b/xcm/src/v0/multiasset.rs @@ -260,11 +260,6 @@ impl MultiAssets { self.0.iter_mut().try_for_each(|i| i.reanchor(prepend)) } } - - - - - /// Classification of whether an asset is fungible or not, along with an optional amount or instance. #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, Decode)] pub enum WildFungibility { From 0cc61debb05c30e394c1179b8a514f433c8ca325 Mon Sep 17 00:00:00 2001 From: Gavin Wood <gavin@parity.io> Date: Tue, 3 Aug 2021 17:49:32 +0200 Subject: [PATCH 055/166] Update xcm/src/v0/multiasset.rs Co-authored-by: Alexander Popiak <alexander.popiak@parity.io> --- xcm/src/v0/multiasset.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/xcm/src/v0/multiasset.rs b/xcm/src/v0/multiasset.rs index 0f3ea7f1ec8e..02c43fc1d205 100644 --- a/xcm/src/v0/multiasset.rs +++ b/xcm/src/v0/multiasset.rs @@ -306,10 +306,6 @@ impl<A: Into<AssetId>, B: Into<WildFungibility>> From<(A, B)> for WildMultiAsset WildMultiAsset::AllOf { fun: fun.into(), id: id.into() } } } - - - - /// `MultiAsset` collection, either `MultiAssets` or a single wildcard. /// /// Note: Vectors of wildcards whose encoding is supported in XCM v0 are unsupported From 723990cb50154b8b09a9a21a05c9b0c164bb945d Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Tue, 3 Aug 2021 20:06:27 +0200 Subject: [PATCH 056/166] Reformat --- runtime/westend/src/lib.rs | 1 - xcm/pallet-xcm/src/lib.rs | 109 ++++++---- xcm/src/v0/mod.rs | 136 +++++++----- xcm/src/v0/multiasset.rs | 60 +++--- xcm/src/v0/order.rs | 52 +++-- xcm/xcm-builder/src/barriers.rs | 31 ++- xcm/xcm-builder/src/filter_asset_location.rs | 4 +- xcm/xcm-builder/src/fungibles_adapter.rs | 201 ++++++++++++------ xcm/xcm-builder/src/lib.rs | 19 +- xcm/xcm-builder/src/matches_fungible.rs | 10 +- xcm/xcm-builder/src/mock.rs | 116 +++++----- xcm/xcm-builder/src/tests.rs | 123 ++++++----- xcm/xcm-builder/src/weight.rs | 127 ++++++----- xcm/xcm-executor/src/assets.rs | 115 ++++++---- xcm/xcm-executor/src/lib.rs | 109 ++++++---- xcm/xcm-executor/src/traits/transact_asset.rs | 57 +++-- xcm/xcm-executor/src/traits/weight.rs | 14 +- 17 files changed, 753 insertions(+), 531 deletions(-) diff --git a/runtime/westend/src/lib.rs b/runtime/westend/src/lib.rs index 2255f4194c87..12efa280771d 100644 --- a/runtime/westend/src/lib.rs +++ b/runtime/westend/src/lib.rs @@ -944,7 +944,6 @@ pub type LocalOriginToLocation = ( SignedToAccountId32<Origin, AccountId, WestendNetwork>, ); - impl pallet_xcm::Config for Runtime { type Event = Event; type SendXcmOrigin = xcm_builder::EnsureXcmOrigin<Origin, LocalOriginToLocation>; diff --git a/xcm/pallet-xcm/src/lib.rs b/xcm/pallet-xcm/src/lib.rs index 99341c2a0e85..95d5c867e781 100644 --- a/xcm/pallet-xcm/src/lib.rs +++ b/xcm/pallet-xcm/src/lib.rs @@ -18,23 +18,28 @@ #![cfg_attr(not(feature = "std"), no_std)] -use sp_std::{prelude::*, marker::PhantomData, convert::TryInto, boxed::Box, vec}; -use codec::{Encode, Decode}; +#[cfg(test)] +mod mock; +#[cfg(test)] +mod tests; + +use codec::{Decode, Encode}; +use frame_support::traits::{Contains, EnsureOrigin, Filter, Get, OriginTrait}; +use sp_runtime::{traits::BadOrigin, RuntimeDebug}; +use sp_std::{boxed::Box, convert::TryInto, marker::PhantomData, prelude::*, vec}; use xcm::v0::prelude::*; use xcm_executor::traits::ConvertOrigin; -use sp_runtime::{RuntimeDebug, traits::BadOrigin}; -use frame_support::traits::{EnsureOrigin, OriginTrait, Filter, Get, Contains}; -pub use pallet::*; use frame_support::PalletId; +pub use pallet::*; #[frame_support::pallet] pub mod pallet { use super::*; use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; - use xcm_executor::traits::WeightBounds; use sp_runtime::traits::AccountIdConversion; + use xcm_executor::traits::WeightBounds; #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] @@ -48,7 +53,7 @@ pub mod pallet { /// Required origin for sending XCM messages. If successful, the it resolves to `MultiLocation` /// which exists as an interior location within this chain's XCM context. - type SendXcmOrigin: EnsureOrigin<Self::Origin, Success=MultiLocation>; + type SendXcmOrigin: EnsureOrigin<Self::Origin, Success = MultiLocation>; /// The type used to actually dispatch an XCM to its destination. type XcmRouter: SendXcm; @@ -56,7 +61,7 @@ pub mod pallet { /// Required origin for executing XCM messages, including the teleport functionality. If successful, /// then it resolves to `MultiLocation` which exists as an interior location within this chain's XCM /// context. - type ExecuteXcmOrigin: EnsureOrigin<Self::Origin, Success=MultiLocation>; + type ExecuteXcmOrigin: EnsureOrigin<Self::Origin, Success = MultiLocation>; /// Our XCM filter which messages to be executed using `XcmExecutor` must pass. type XcmExecuteFilter: Contains<(MultiLocation, Xcm<Self::Call>)>; @@ -101,11 +106,12 @@ pub mod pallet { #[pallet::weight(100_000_000)] pub fn send(origin: OriginFor<T>, dest: MultiLocation, message: Xcm<()>) -> DispatchResult { let origin_location = T::SendXcmOrigin::ensure_origin(origin)?; - Self::send_xcm(origin_location.clone(), dest.clone(), message.clone()) - .map_err(|e| match e { + Self::send_xcm(origin_location.clone(), dest.clone(), message.clone()).map_err( + |e| match e { XcmError::CannotReachDestination(..) => Error::<T>::Unreachable, _ => Error::<T>::SendFailure, - })?; + }, + )?; Self::deposit_event(Event::Sent(origin_location, dest, message)); Ok(()) } @@ -147,27 +153,26 @@ pub mod pallet { let assets = assets.into(); let mut message = Xcm::WithdrawAsset { assets, - effects: vec![ - InitiateTeleport { - assets: Wild(All), - dest, - effects: vec![ - BuyExecution { - fees, - // Zero weight for additional XCM (since there are none to execute) - weight: 0, - debt: dest_weight, - halt_on_error: false, - xcm: vec![], - }, - DepositAsset { assets: Wild(All), dest: beneficiary }, - ], - }, - ], + effects: vec![InitiateTeleport { + assets: Wild(All), + dest, + effects: vec![ + BuyExecution { + fees, + // Zero weight for additional XCM (since there are none to execute) + weight: 0, + debt: dest_weight, + halt_on_error: false, + xcm: vec![], + }, + DepositAsset { assets: Wild(All), dest: beneficiary }, + ], + }], }; - let weight = T::Weigher::weight(&mut message) - .map_err(|()| Error::<T>::UnweighableMessage)?; - let outcome = T::XcmExecutor::execute_xcm_in_credit(origin_location, message, weight, weight); + let weight = + T::Weigher::weight(&mut message).map_err(|()| Error::<T>::UnweighableMessage)?; + let outcome = + T::XcmExecutor::execute_xcm_in_credit(origin_location, message, weight, weight); Self::deposit_event(Event::Attempted(outcome)); Ok(()) } @@ -220,9 +225,10 @@ pub mod pallet { DepositAsset { assets: Wild(All), dest: beneficiary }, ], }; - let weight = T::Weigher::weight(&mut message) - .map_err(|()| Error::<T>::UnweighableMessage)?; - let outcome = T::XcmExecutor::execute_xcm_in_credit(origin_location, message, weight, weight); + let weight = + T::Weigher::weight(&mut message).map_err(|()| Error::<T>::UnweighableMessage)?; + let outcome = + T::XcmExecutor::execute_xcm_in_credit(origin_location, message, weight, weight); Self::deposit_event(Event::Attempted(outcome)); Ok(()) } @@ -239,9 +245,11 @@ pub mod pallet { /// NOTE: A successful return to this does *not* imply that the `msg` was executed successfully /// to completion; only that *some* of it was executed. #[pallet::weight(max_weight.saturating_add(100_000_000u64))] - pub fn execute(origin: OriginFor<T>, message: Box<Xcm<T::Call>>, max_weight: Weight) - -> DispatchResult - { + pub fn execute( + origin: OriginFor<T>, + message: Box<Xcm<T::Call>>, + max_weight: Weight, + ) -> DispatchResult { let origin_location = T::ExecuteXcmOrigin::ensure_origin(origin)?; let value = (origin_location, *message); ensure!(T::XcmExecuteFilter::contains(&value), Error::<T>::Filtered); @@ -255,7 +263,11 @@ pub mod pallet { impl<T: Config> Pallet<T> { /// Relay an XCM `message` from a given `interior` location in this context to a given `dest` /// location. A null `dest` is not handled. - pub fn send_xcm(interior: MultiLocation, dest: MultiLocation, message: Xcm<()>) -> Result<(), XcmError> { + pub fn send_xcm( + interior: MultiLocation, + dest: MultiLocation, + message: Xcm<()>, + ) -> Result<(), XcmError> { let message = match interior { MultiLocation::Null => message, who => Xcm::<()>::RelayedFrom { who, message: Box::new(message) }, @@ -288,7 +300,8 @@ pub mod pallet { /// Ensure that the origin `o` represents a sibling parachain. /// Returns `Ok` with the parachain ID of the sibling or an `Err` otherwise. pub fn ensure_xcm<OuterOrigin>(o: OuterOrigin) -> Result<MultiLocation, BadOrigin> - where OuterOrigin: Into<Result<Origin, OuterOrigin>> +where + OuterOrigin: Into<Result<Origin, OuterOrigin>>, { match o.into() { Ok(Origin::Xcm(location)) => Ok(location), @@ -301,7 +314,9 @@ pub fn ensure_xcm<OuterOrigin>(o: OuterOrigin) -> Result<MultiLocation, BadOrigi /// /// May reasonably be used with `EnsureXcm`. pub struct IsMajorityOfBody<Prefix, Body>(PhantomData<(Prefix, Body)>); -impl<Prefix: Get<MultiLocation>, Body: Get<BodyId>> Filter<MultiLocation> for IsMajorityOfBody<Prefix, Body> { +impl<Prefix: Get<MultiLocation>, Body: Get<BodyId>> Filter<MultiLocation> + for IsMajorityOfBody<Prefix, Body> +{ fn filter(l: &MultiLocation) -> bool { let maybe_suffix = l.match_and_split(&Prefix::get()); matches!(maybe_suffix, Some(Plurality { id, part }) if id == &Body::get() && part.is_majority()) @@ -312,19 +327,21 @@ impl<Prefix: Get<MultiLocation>, Body: Get<BodyId>> Filter<MultiLocation> for Is /// `Origin::Xcm` item. pub struct EnsureXcm<F>(PhantomData<F>); impl<O: OriginTrait + From<Origin>, F: Filter<MultiLocation>> EnsureOrigin<O> for EnsureXcm<F> - where O::PalletsOrigin: From<Origin> + TryInto<Origin, Error=O::PalletsOrigin> +where + O::PalletsOrigin: From<Origin> + TryInto<Origin, Error = O::PalletsOrigin>, { type Success = MultiLocation; fn try_origin(outer: O) -> Result<Self::Success, O> { - outer.try_with_caller(|caller| caller.try_into() - .and_then(|Origin::Xcm(location)| + outer.try_with_caller(|caller| { + caller.try_into().and_then(|Origin::Xcm(location)| { if F::filter(&location) { Ok(location) } else { Err(Origin::Xcm(location).into()) } - )) + }) + }) } #[cfg(feature = "runtime-benchmarks")] @@ -336,9 +353,7 @@ impl<O: OriginTrait + From<Origin>, F: Filter<MultiLocation>> EnsureOrigin<O> fo /// A simple passthrough where we reuse the `MultiLocation`-typed XCM origin as the inner value of /// this crate's `Origin::Xcm` value. pub struct XcmPassthrough<Origin>(PhantomData<Origin>); -impl< - Origin: From<crate::Origin>, -> ConvertOrigin<Origin> for XcmPassthrough<Origin> { +impl<Origin: From<crate::Origin>> ConvertOrigin<Origin> for XcmPassthrough<Origin> { fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result<Origin, MultiLocation> { match (kind, origin) { (OriginKind::Xcm, l) => Ok(crate::Origin::Xcm(l).into()), diff --git a/xcm/src/v0/mod.rs b/xcm/src/v0/mod.rs index 95bccfacf0b5..2bd568e60194 100644 --- a/xcm/src/v0/mod.rs +++ b/xcm/src/v0/mod.rs @@ -16,43 +16,52 @@ //! Version 0 of the Cross-Consensus Message format data structures. -use core::{result, convert::TryFrom, fmt::Debug}; -use derivative::Derivative; -use alloc::vec::Vec; -use parity_scale_codec::{self, Encode, Decode}; use crate::{DoubleEncoded, VersionedXcm}; +use alloc::vec::Vec; +use core::{convert::TryFrom, fmt::Debug, result}; +use derivative::Derivative; +use parity_scale_codec::{self, Decode, Encode}; mod junction; mod multi_location; +pub mod multiasset; mod order; -mod traits; -pub mod multiasset; // the new multiasset. +mod traits; // the new multiasset. -pub use junction::{Junction, NetworkId, BodyId, BodyPart}; +pub use junction::{BodyId, BodyPart, Junction, NetworkId}; +pub use multi_location::MultiLocation; pub use multiasset::{ - AssetId, AssetInstance, MultiAsset, MultiAssets, MultiAssetFilter, Fungibility, WildMultiAsset, WildFungibility + AssetId, AssetInstance, Fungibility, MultiAsset, MultiAssetFilter, MultiAssets, + WildFungibility, WildMultiAsset, }; -pub use multi_location::MultiLocation; pub use order::Order; -pub use traits::{Error, Result, SendXcm, ExecuteXcm, Outcome}; +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::{Junction::*, NetworkId::{self, *}, BodyId, BodyPart}; - pub use super::multiasset::{ - MultiAssets, MultiAsset, - AssetId::{self, *}, - AssetInstance::{self, *}, - MultiAssetFilter::{self, *}, - Fungibility::{self, *}, - WildMultiAsset::{self, *}, - WildFungibility::{self, Fungible as WildFungible, NonFungible as WildNonFungible}, + pub use super::{ + junction::{ + BodyId, BodyPart, + Junction::*, + NetworkId::{self, *}, + }, + multi_location::MultiLocation::{self, *}, + multiasset::{ + AssetId::{self, *}, + AssetInstance::{self, *}, + Fungibility::{self, *}, + MultiAsset, + MultiAssetFilter::{self, *}, + MultiAssets, + WildFungibility::{self, Fungible as WildFungible, NonFungible as WildNonFungible}, + WildMultiAsset::{self, *}, + }, + opaque, + order::Order::{self, *}, + traits::{Error as XcmError, ExecuteXcm, Outcome, Result as XcmResult, SendXcm}, + OriginKind, Response, + Xcm::{self, *}, }; - pub use super::multi_location::MultiLocation::{self, *}; - pub use super::order::Order::{self, *}; - pub use super::traits::{Error as XcmError, Result as XcmResult, SendXcm, ExecuteXcm, Outcome}; - pub use super::{Xcm::{self, *}, OriginKind, Response}; - pub use super::opaque; } // TODO: #2841 #XCMENCODE Efficient encodings for MultiAssets, Vec<Order>, using initial byte values 128+ to encode @@ -159,7 +168,11 @@ pub enum Xcm<Call> { /// /// Errors: #[codec(index = 3)] - QueryResponse { #[codec(compact)] query_id: u64, response: Response }, + QueryResponse { + #[codec(compact)] + query_id: u64, + response: Response, + }, /// Withdraw asset(s) (`assets`) from the ownership of `origin` and place equivalent assets under the /// ownership of `dest` within this consensus system. @@ -221,9 +234,12 @@ pub enum Xcm<Call> { /// Kind: *System Notification* #[codec(index = 7)] HrmpNewChannelOpenRequest { - #[codec(compact)] sender: u32, - #[codec(compact)] max_message_size: u32, - #[codec(compact)] max_capacity: u32, + #[codec(compact)] + sender: u32, + #[codec(compact)] + max_message_size: u32, + #[codec(compact)] + max_capacity: u32, }, /// A message to notify about that a previously sent open channel request has been accepted by @@ -237,7 +253,8 @@ pub enum Xcm<Call> { /// Errors: #[codec(index = 8)] HrmpChannelAccepted { - #[codec(compact)] recipient: u32, + #[codec(compact)] + recipient: u32, }, /// A message to notify that the other party in an open channel decided to close it. In particular, @@ -252,9 +269,12 @@ pub enum Xcm<Call> { /// Errors: #[codec(index = 9)] HrmpChannelClosing { - #[codec(compact)] initiator: u32, - #[codec(compact)] sender: u32, - #[codec(compact)] recipient: u32, + #[codec(compact)] + initiator: u32, + #[codec(compact)] + sender: u32, + #[codec(compact)] + recipient: u32, }, /// A message to indicate that the embedded XCM is actually arriving on behalf of some consensus @@ -267,10 +287,7 @@ pub enum Xcm<Call> { /// /// Errors: #[codec(index = 10)] - RelayedFrom { - who: MultiLocation, - message: alloc::boxed::Box<Xcm<Call>>, - }, + RelayedFrom { who: MultiLocation, message: alloc::boxed::Box<Xcm<Call>> }, } impl<Call> From<Xcm<Call>> for VersionedXcm<Call> { @@ -289,32 +306,33 @@ impl<Call> TryFrom<VersionedXcm<Call>> for Xcm<Call> { } impl<Call> Xcm<Call> { - pub fn into<C>(self) -> Xcm<C> { Xcm::from(self) } + pub fn into<C>(self) -> Xcm<C> { + Xcm::from(self) + } pub fn from<C>(xcm: Xcm<C>) -> Self { use Xcm::*; match xcm { - WithdrawAsset { assets, effects } - => WithdrawAsset { assets, effects: effects.into_iter().map(Order::into).collect() }, - ReserveAssetDeposited { assets, effects } - => ReserveAssetDeposited { assets, effects: effects.into_iter().map(Order::into).collect() }, - TeleportAsset { assets, effects } - => TeleportAsset { assets, effects: effects.into_iter().map(Order::into).collect() }, - QueryResponse { query_id: u64, response } - => QueryResponse { query_id: u64, response }, - TransferAsset { assets, dest } - => TransferAsset { assets, dest }, - TransferReserveAsset { assets, dest, effects } - => TransferReserveAsset { assets, dest, effects }, - HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity} - => HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity}, - HrmpChannelAccepted { recipient} - => HrmpChannelAccepted { recipient}, - HrmpChannelClosing { initiator, sender, recipient} - => HrmpChannelClosing { initiator, sender, recipient}, - Transact { origin_type, require_weight_at_most, call} - => Transact { origin_type, require_weight_at_most, call: call.into() }, - RelayedFrom { who, message } - => RelayedFrom { who, message: alloc::boxed::Box::new((*message).into()) }, + WithdrawAsset { assets, effects } => + WithdrawAsset { assets, effects: effects.into_iter().map(Order::into).collect() }, + ReserveAssetDeposited { assets, effects } => ReserveAssetDeposited { + assets, + effects: effects.into_iter().map(Order::into).collect(), + }, + TeleportAsset { assets, effects } => + TeleportAsset { assets, effects: effects.into_iter().map(Order::into).collect() }, + QueryResponse { query_id: u64, response } => QueryResponse { query_id: u64, response }, + TransferAsset { assets, dest } => TransferAsset { assets, dest }, + TransferReserveAsset { assets, dest, effects } => + TransferReserveAsset { assets, dest, effects }, + HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } => + HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity }, + HrmpChannelAccepted { recipient } => HrmpChannelAccepted { recipient }, + HrmpChannelClosing { initiator, sender, recipient } => + HrmpChannelClosing { initiator, sender, recipient }, + Transact { origin_type, require_weight_at_most, call } => + Transact { origin_type, require_weight_at_most, call: call.into() }, + RelayedFrom { who, message } => + RelayedFrom { who, message: alloc::boxed::Box::new((*message).into()) }, } } } diff --git a/xcm/src/v0/multiasset.rs b/xcm/src/v0/multiasset.rs index 02c43fc1d205..c11110ed571c 100644 --- a/xcm/src/v0/multiasset.rs +++ b/xcm/src/v0/multiasset.rs @@ -1,5 +1,5 @@ // Copyright 2020 Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// This file is part of Polkadot. // Substrate is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -23,10 +23,10 @@ //! - `MultiAssetFilter`: A combination of `Wild` and `MultiAssets` designed for efficiently filtering an XCM holding //! account. -use core::cmp::Ordering; -use alloc::{vec, vec::Vec}; -use parity_scale_codec::{self as codec, Encode, Decode}; use super::MultiLocation; +use alloc::{vec, vec::Vec}; +use core::cmp::Ordering; +use parity_scale_codec::{self as codec, Decode, Encode}; /// A general identifier for an instance of a non-fungible asset class. #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug)] @@ -36,7 +36,10 @@ pub enum AssetInstance { /// A compact index. Technically this could be greater than `u128`, but this implementation supports only /// values up to `2**128 - 1`. - Index { #[codec(compact)] id: u128 }, + Index { + #[codec(compact)] + id: u128, + }, /// A 4-byte fixed-length datum. Array4([u8; 4]), @@ -103,7 +106,8 @@ pub enum Fungibility { impl Fungibility { pub fn is_kind(&self, w: WildFungibility) -> bool { - use {Fungibility::*, WildFungibility::{Fungible as WildFungible, NonFungible as WildNonFungible}}; + use Fungibility::*; + use WildFungibility::{Fungible as WildFungible, NonFungible as WildNonFungible}; matches!((self, w), (Fungible(_), WildFungible) | (NonFungible(_), WildNonFungible)) } } @@ -121,9 +125,6 @@ impl From<AssetInstance> for Fungibility { } } - - - #[derive(Clone, Eq, PartialEq, Debug, Encode, Decode)] pub struct MultiAsset { pub id: AssetId, @@ -182,8 +183,6 @@ impl MultiAsset { } } - - /// A `Vec` of `MultiAsset`s. There may be no duplicate fungible items in here and when decoding, they must be sorted. #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode)] pub struct MultiAssets(Vec<MultiAsset>); @@ -191,14 +190,19 @@ pub struct MultiAssets(Vec<MultiAsset>); impl Decode for MultiAssets { fn decode<I: codec::Input>(input: &mut I) -> Result<Self, parity_scale_codec::Error> { let r = Vec::<MultiAsset>::decode(input)?; - if r.is_empty() { return Ok(Self(Vec::new())) } - r.iter().skip(1).try_fold(&r[0], |a, b| -> Result<&MultiAsset, parity_scale_codec::Error> { - if a.id < b.id || a < b && (a.is_non_fungible(None) || b.is_non_fungible(None)) { - Ok(b) - } else { - Err("Out of order".into()) - } - })?; + if r.is_empty() { + return Ok(Self(Vec::new())) + } + r.iter().skip(1).try_fold( + &r[0], + |a, b| -> Result<&MultiAsset, parity_scale_codec::Error> { + if a.id < b.id || a < b && (a.is_non_fungible(None) || b.is_non_fungible(None)) { + Ok(b) + } else { + Err("Out of order".into()) + } + }, + )?; Ok(Self(r)) } } @@ -306,8 +310,9 @@ impl<A: Into<AssetId>, B: Into<WildFungibility>> From<(A, B)> for WildMultiAsset WildMultiAsset::AllOf { fun: fun.into(), id: id.into() } } } + /// `MultiAsset` collection, either `MultiAssets` or a single wildcard. -/// +/// /// Note: Vectors of wildcards whose encoding is supported in XCM v0 are unsupported /// in this implementation and will result in a decode error. #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, Decode)] @@ -341,21 +346,6 @@ impl From<MultiAssets> for MultiAssetFilter { } impl MultiAssetFilter { - /// Returns `true` if the `MultiAsset` is a wildcard and refers to sets of assets, instead of just one. - pub fn is_wildcard(&self) -> bool { - matches!(self, MultiAssetFilter::Wild(..)) - } - - /// Returns `true` if the `MultiAsset` is not a wildcard. - pub fn is_definite(&self) -> bool { - !self.is_wildcard() - } - - /// Returns `true` if this definitely represents no asset. - pub fn is_none(&self) -> bool { - matches!(self, MultiAssetFilter::Definite(a) if a.is_none()) - } - /// Returns true if `self` is a super-set of the given `inner`. /// /// Typically, any wildcard is never contained in anything else, and a wildcard can contain any other non-wildcard. diff --git a/xcm/src/v0/order.rs b/xcm/src/v0/order.rs index 3917e6a01116..aed5a6ff3634 100644 --- a/xcm/src/v0/order.rs +++ b/xcm/src/v0/order.rs @@ -16,14 +16,14 @@ //! Version 0 of the Cross-Consensus Message format data structures. +use super::{MultiAsset, MultiAssetFilter, MultiLocation, Xcm}; use alloc::vec::Vec; use derivative::Derivative; -use parity_scale_codec::{self, Encode, Decode}; -use super::{MultiAsset, MultiAssetFilter, MultiLocation, Xcm}; +use parity_scale_codec::{self, Decode, Encode}; /// An instruction to be executed on some or all of the assets in holding, used by asset-related XCM messages. #[derive(Derivative, Encode, Decode)] -#[derivative(Clone(bound=""), Eq(bound=""), PartialEq(bound=""), Debug(bound=""))] +#[derivative(Clone(bound = ""), Eq(bound = ""), PartialEq(bound = ""), Debug(bound = ""))] #[codec(encode_bound())] #[codec(decode_bound())] pub enum Order<Call> { @@ -78,7 +78,11 @@ pub enum Order<Call> { /// /// Errors: #[codec(index = 4)] - InitiateReserveWithdraw { assets: MultiAssetFilter, reserve: MultiLocation, effects: Vec<Order<()>> }, + InitiateReserveWithdraw { + assets: MultiAssetFilter, + reserve: MultiLocation, + effects: Vec<Order<()>>, + }, /// Remove the asset(s) (`assets`) from holding and send a `TeleportAsset` XCM message to a destination location. /// @@ -100,7 +104,12 @@ pub enum Order<Call> { /// /// Errors: #[codec(index = 6)] - QueryHolding { #[codec(compact)] query_id: u64, dest: MultiLocation, assets: MultiAssetFilter }, + QueryHolding { + #[codec(compact)] + query_id: u64, + dest: MultiLocation, + assets: MultiAssetFilter, + }, /// Pay for the execution of some XCM with up to `weight` picoseconds of execution time, paying for this with /// up to `fees` from the holding register. @@ -109,7 +118,13 @@ pub enum Order<Call> { /// /// Errors: #[codec(index = 7)] - BuyExecution { fees: MultiAsset, weight: u64, debt: u64, halt_on_error: bool, xcm: Vec<Xcm<Call>> }, + BuyExecution { + fees: MultiAsset, + weight: u64, + debt: u64, + halt_on_error: bool, + xcm: Vec<Xcm<Call>>, + }, } pub mod opaque { @@ -117,23 +132,22 @@ pub mod opaque { } impl<Call> Order<Call> { - pub fn into<C>(self) -> Order<C> { Order::from(self) } + pub fn into<C>(self) -> Order<C> { + Order::from(self) + } pub fn from<C>(order: Order<C>) -> Self { use Order::*; match order { Noop => Noop, - DepositAsset { assets, dest } - => DepositAsset { assets, dest }, - DepositReserveAsset { assets, dest, effects } - => DepositReserveAsset { assets, dest, effects }, - ExchangeAsset { give, receive } - => ExchangeAsset { give, receive }, - InitiateReserveWithdraw { assets, reserve, effects } - => InitiateReserveWithdraw { assets, reserve, effects }, - InitiateTeleport { assets, dest, effects } - => InitiateTeleport { assets, dest, effects }, - QueryHolding { query_id, dest, assets } - => QueryHolding { query_id, dest, assets }, + DepositAsset { assets, dest } => DepositAsset { assets, dest }, + DepositReserveAsset { assets, dest, effects } => + DepositReserveAsset { assets, dest, effects }, + ExchangeAsset { give, receive } => ExchangeAsset { give, receive }, + InitiateReserveWithdraw { assets, reserve, effects } => + InitiateReserveWithdraw { assets, reserve, effects }, + InitiateTeleport { assets, dest, effects } => + InitiateTeleport { assets, dest, effects }, + QueryHolding { query_id, dest, assets } => QueryHolding { query_id, dest, assets }, BuyExecution { fees, weight, debt, halt_on_error, xcm } => { let xcm = xcm.into_iter().map(Xcm::from).collect(); BuyExecution { fees, weight, debt, halt_on_error, xcm } diff --git a/xcm/xcm-builder/src/barriers.rs b/xcm/xcm-builder/src/barriers.rs index 0a48ad6c42e2..2d870d7525c2 100644 --- a/xcm/xcm-builder/src/barriers.rs +++ b/xcm/xcm-builder/src/barriers.rs @@ -16,11 +16,11 @@ //! Various implementations for `ShouldExecute`. -use sp_std::{result::Result, marker::PhantomData}; -use xcm::v0::{Xcm, Order, MultiLocation, Junction}; use frame_support::{ensure, traits::Contains, weights::Weight}; -use xcm_executor::traits::{OnResponse, ShouldExecute}; use polkadot_parachain::primitives::IsSystem; +use sp_std::{marker::PhantomData, result::Result}; +use xcm::v0::{Junction, MultiLocation, Order, Xcm}; +use xcm_executor::traits::{OnResponse, ShouldExecute}; /// Execution barrier that just takes `shallow_weight` from `weight_credit`. pub struct TakeWeightCredit; @@ -51,14 +51,14 @@ impl<T: Contains<MultiLocation>> ShouldExecute for AllowTopLevelPaidExecutionFro ensure!(T::contains(origin), ()); ensure!(top_level, ()); match message { - Xcm::TeleportAsset { effects, .. } - | Xcm::WithdrawAsset { effects, ..} - | Xcm::ReserveAssetDeposited { effects, ..} - if matches!( - effects.first(), - Some(Order::BuyExecution { debt, ..}) if *debt >= shallow_weight - ) - => Ok(()), + Xcm::TeleportAsset { effects, .. } | + Xcm::WithdrawAsset { effects, .. } | + Xcm::ReserveAssetDeposited { effects, .. } + if matches!( + effects.first(), + Some(Order::BuyExecution { debt, ..}) if *debt >= shallow_weight + ) => + Ok(()), _ => Err(()), } } @@ -82,9 +82,7 @@ impl<T: Contains<MultiLocation>> ShouldExecute for AllowUnpaidExecutionFrom<T> { /// Allows a message only if it is from a system-level child parachain. pub struct IsChildSystemParachain<ParaId>(PhantomData<ParaId>); -impl< - ParaId: IsSystem + From<u32>, -> Contains<MultiLocation> for IsChildSystemParachain<ParaId> { +impl<ParaId: IsSystem + From<u32>> Contains<MultiLocation> for IsChildSystemParachain<ParaId> { fn contains(l: &MultiLocation) -> bool { matches!(l, MultiLocation::X1(Junction::Parachain(id)) if ParaId::from(*id).is_system()) } @@ -101,8 +99,9 @@ impl<ResponseHandler: OnResponse> ShouldExecute for AllowKnownQueryResponses<Res _weight_credit: &mut Weight, ) -> Result<(), ()> { match message { - Xcm::QueryResponse { query_id, .. } if ResponseHandler::expecting_response(origin, *query_id) - => Ok(()), + Xcm::QueryResponse { query_id, .. } + if ResponseHandler::expecting_response(origin, *query_id) => + Ok(()), _ => Err(()), } } diff --git a/xcm/xcm-builder/src/filter_asset_location.rs b/xcm/xcm-builder/src/filter_asset_location.rs index 462b9421e35a..cb2fa80be734 100644 --- a/xcm/xcm-builder/src/filter_asset_location.rs +++ b/xcm/xcm-builder/src/filter_asset_location.rs @@ -16,9 +16,9 @@ //! Various implementations of `FilterAssetLocation`. -use sp_std::marker::PhantomData; -use xcm::v0::{MultiAsset, MultiAssetFilter, MultiLocation, AssetId::Concrete}; use frame_support::traits::Get; +use sp_std::marker::PhantomData; +use xcm::v0::{AssetId::Concrete, MultiAsset, MultiAssetFilter, MultiLocation}; use xcm_executor::traits::FilterAssetLocation; /// Accepts an asset iff it is a native asset. diff --git a/xcm/xcm-builder/src/fungibles_adapter.rs b/xcm/xcm-builder/src/fungibles_adapter.rs index 121d0828f165..d81ddd5a575d 100644 --- a/xcm/xcm-builder/src/fungibles_adapter.rs +++ b/xcm/xcm-builder/src/fungibles_adapter.rs @@ -16,23 +16,25 @@ //! Adapters to work with `frame_support::traits::tokens::fungibles` through XCM. -use sp_std::{prelude::*, result, marker::PhantomData, borrow::Borrow}; +use frame_support::traits::{tokens::fungibles, Contains, Get}; +use sp_std::{borrow::Borrow, marker::PhantomData, prelude::*, result}; use xcm::v0::{ - Error as XcmError, Result, MultiAsset, MultiLocation, Junction, Fungibility::Fungible, - AssetId::{Concrete, Abstract}, + AssetId::{Abstract, Concrete}, + Error as XcmError, + Fungibility::Fungible, + Junction, MultiAsset, MultiLocation, Result, }; -use frame_support::traits::{Get, tokens::fungibles, Contains}; -use xcm_executor::traits::{TransactAsset, Convert, MatchesFungibles, Error as MatchError}; +use xcm_executor::traits::{Convert, Error as MatchError, MatchesFungibles, TransactAsset}; /// Converter struct implementing `AssetIdConversion` converting a numeric asset ID (must be `TryFrom/TryInto<u128>`) into /// a `GeneralIndex` junction, prefixed by some `MultiLocation` value. The `MultiLocation` value will typically be a /// `PalletInstance` junction. -pub struct AsPrefixedGeneralIndex<Prefix, AssetId, ConvertAssetId>(PhantomData<(Prefix, AssetId, ConvertAssetId)>); -impl< - Prefix: Get<MultiLocation>, - AssetId: Clone, - ConvertAssetId: Convert<u128, AssetId>, -> Convert<MultiLocation, AssetId> for AsPrefixedGeneralIndex<Prefix, AssetId, ConvertAssetId> { +pub struct AsPrefixedGeneralIndex<Prefix, AssetId, ConvertAssetId>( + PhantomData<(Prefix, AssetId, ConvertAssetId)>, +); +impl<Prefix: Get<MultiLocation>, AssetId: Clone, ConvertAssetId: Convert<u128, AssetId>> + Convert<MultiLocation, AssetId> for AsPrefixedGeneralIndex<Prefix, AssetId, ConvertAssetId> +{ fn convert_ref(id: impl Borrow<MultiLocation>) -> result::Result<AssetId, ()> { let prefix = Prefix::get(); let id = id.borrow(); @@ -53,58 +55,63 @@ impl< } pub struct ConvertedConcreteAssetId<AssetId, Balance, ConvertAssetId, ConvertBalance>( - PhantomData<(AssetId, Balance, ConvertAssetId, ConvertBalance)> + PhantomData<(AssetId, Balance, ConvertAssetId, ConvertBalance)>, ); impl< - AssetId: Clone, - Balance: Clone, - ConvertAssetId: Convert<MultiLocation, AssetId>, - ConvertBalance: Convert<u128, Balance>, -> MatchesFungibles<AssetId, Balance> for - ConvertedConcreteAssetId<AssetId, Balance, ConvertAssetId, ConvertBalance> + AssetId: Clone, + Balance: Clone, + ConvertAssetId: Convert<MultiLocation, AssetId>, + ConvertBalance: Convert<u128, Balance>, + > MatchesFungibles<AssetId, Balance> + for ConvertedConcreteAssetId<AssetId, Balance, ConvertAssetId, ConvertBalance> { fn matches_fungibles(a: &MultiAsset) -> result::Result<(AssetId, Balance), MatchError> { let (amount, id) = match (&a.fun, &a.id) { (Fungible(ref amount), Concrete(ref id)) => (amount, id), _ => return Err(MatchError::AssetNotFound), }; - let what = ConvertAssetId::convert_ref(id).map_err(|_| MatchError::AssetIdConversionFailed)?; - let amount = ConvertBalance::convert_ref(amount).map_err(|_| MatchError::AmountToBalanceConversionFailed)?; + let what = + ConvertAssetId::convert_ref(id).map_err(|_| MatchError::AssetIdConversionFailed)?; + let amount = ConvertBalance::convert_ref(amount) + .map_err(|_| MatchError::AmountToBalanceConversionFailed)?; Ok((what, amount)) } } pub struct ConvertedAbstractAssetId<AssetId, Balance, ConvertAssetId, ConvertBalance>( - PhantomData<(AssetId, Balance, ConvertAssetId, ConvertBalance)> + PhantomData<(AssetId, Balance, ConvertAssetId, ConvertBalance)>, ); impl< - AssetId: Clone, - Balance: Clone, - ConvertAssetId: Convert<Vec<u8>, AssetId>, - ConvertBalance: Convert<u128, Balance>, -> MatchesFungibles<AssetId, Balance> for - ConvertedAbstractAssetId<AssetId, Balance, ConvertAssetId, ConvertBalance> + AssetId: Clone, + Balance: Clone, + ConvertAssetId: Convert<Vec<u8>, AssetId>, + ConvertBalance: Convert<u128, Balance>, + > MatchesFungibles<AssetId, Balance> + for ConvertedAbstractAssetId<AssetId, Balance, ConvertAssetId, ConvertBalance> { fn matches_fungibles(a: &MultiAsset) -> result::Result<(AssetId, Balance), MatchError> { let (amount, id) = match (&a.fun, &a.id) { (Fungible(ref amount), Abstract(ref id)) => (amount, id), _ => return Err(MatchError::AssetNotFound), }; - let what = ConvertAssetId::convert_ref(id).map_err(|_| MatchError::AssetIdConversionFailed)?; - let amount = ConvertBalance::convert_ref(amount).map_err(|_| MatchError::AmountToBalanceConversionFailed)?; + let what = + ConvertAssetId::convert_ref(id).map_err(|_| MatchError::AssetIdConversionFailed)?; + let amount = ConvertBalance::convert_ref(amount) + .map_err(|_| MatchError::AmountToBalanceConversionFailed)?; Ok((what, amount)) } } pub struct FungiblesTransferAdapter<Assets, Matcher, AccountIdConverter, AccountId>( - PhantomData<(Assets, Matcher, AccountIdConverter, AccountId)> + PhantomData<(Assets, Matcher, AccountIdConverter, AccountId)>, ); impl< - Assets: fungibles::Transfer<AccountId>, - Matcher: MatchesFungibles<Assets::AssetId, Assets::Balance>, - AccountIdConverter: Convert<MultiLocation, AccountId>, - AccountId: Clone, // can't get away without it since Currency is generic over it. -> TransactAsset for FungiblesTransferAdapter<Assets, Matcher, AccountIdConverter, AccountId> { + Assets: fungibles::Transfer<AccountId>, + Matcher: MatchesFungibles<Assets::AssetId, Assets::Balance>, + AccountIdConverter: Convert<MultiLocation, AccountId>, + AccountId: Clone, // can't get away without it since Currency is generic over it. + > TransactAsset for FungiblesTransferAdapter<Assets, Matcher, AccountIdConverter, AccountId> +{ fn transfer_asset( what: &MultiAsset, from: &MultiLocation, @@ -122,17 +129,31 @@ impl< } } -pub struct FungiblesMutateAdapter<Assets, Matcher, AccountIdConverter, AccountId, CheckAsset, CheckingAccount>( - PhantomData<(Assets, Matcher, AccountIdConverter, AccountId, CheckAsset, CheckingAccount)> -); +pub struct FungiblesMutateAdapter< + Assets, + Matcher, + AccountIdConverter, + AccountId, + CheckAsset, + CheckingAccount, +>(PhantomData<(Assets, Matcher, AccountIdConverter, AccountId, CheckAsset, CheckingAccount)>); impl< - Assets: fungibles::Mutate<AccountId>, - Matcher: MatchesFungibles<Assets::AssetId, Assets::Balance>, - AccountIdConverter: Convert<MultiLocation, AccountId>, - AccountId: Clone, // can't get away without it since Currency is generic over it. - CheckAsset: Contains<Assets::AssetId>, - CheckingAccount: Get<AccountId>, -> TransactAsset for FungiblesMutateAdapter<Assets, Matcher, AccountIdConverter, AccountId, CheckAsset, CheckingAccount> { + Assets: fungibles::Mutate<AccountId>, + Matcher: MatchesFungibles<Assets::AssetId, Assets::Balance>, + AccountIdConverter: Convert<MultiLocation, AccountId>, + AccountId: Clone, // can't get away without it since Currency is generic over it. + CheckAsset: Contains<Assets::AssetId>, + CheckingAccount: Get<AccountId>, + > TransactAsset + for FungiblesMutateAdapter< + Assets, + Matcher, + AccountIdConverter, + AccountId, + CheckAsset, + CheckingAccount, + > +{ fn can_check_in(_origin: &MultiLocation, what: &MultiAsset) -> Result { // Check we handle this asset. let (asset_id, amount) = Matcher::matches_fungibles(what)?; @@ -151,7 +172,10 @@ impl< if CheckAsset::contains(&asset_id) { let checking_account = CheckingAccount::get(); let ok = Assets::burn_from(asset_id, &checking_account, amount).is_ok(); - debug_assert!(ok, "`can_check_in` must have returned `true` immediately prior; qed"); + debug_assert!( + ok, + "`can_check_in` must have returned `true` immediately prior; qed" + ); } } } @@ -177,7 +201,7 @@ impl< fn withdraw_asset( what: &MultiAsset, - who: &MultiLocation + who: &MultiLocation, ) -> result::Result<xcm_executor::Assets, XcmError> { // Check we handle this asset. let (asset_id, amount) = Matcher::matches_fungibles(what)?; @@ -189,43 +213,80 @@ impl< } } -pub struct FungiblesAdapter<Assets, Matcher, AccountIdConverter, AccountId, CheckAsset, CheckingAccount>( - PhantomData<(Assets, Matcher, AccountIdConverter, AccountId, CheckAsset, CheckingAccount)> -); +pub struct FungiblesAdapter< + Assets, + Matcher, + AccountIdConverter, + AccountId, + CheckAsset, + CheckingAccount, +>(PhantomData<(Assets, Matcher, AccountIdConverter, AccountId, CheckAsset, CheckingAccount)>); impl< - Assets: fungibles::Mutate<AccountId> + fungibles::Transfer<AccountId>, - Matcher: MatchesFungibles<Assets::AssetId, Assets::Balance>, - AccountIdConverter: Convert<MultiLocation, AccountId>, - AccountId: Clone, // can't get away without it since Currency is generic over it. - CheckAsset: Contains<Assets::AssetId>, - CheckingAccount: Get<AccountId>, -> TransactAsset for FungiblesAdapter<Assets, Matcher, AccountIdConverter, AccountId, CheckAsset, CheckingAccount> { + Assets: fungibles::Mutate<AccountId> + fungibles::Transfer<AccountId>, + Matcher: MatchesFungibles<Assets::AssetId, Assets::Balance>, + AccountIdConverter: Convert<MultiLocation, AccountId>, + AccountId: Clone, // can't get away without it since Currency is generic over it. + CheckAsset: Contains<Assets::AssetId>, + CheckingAccount: Get<AccountId>, + > TransactAsset + for FungiblesAdapter<Assets, Matcher, AccountIdConverter, AccountId, CheckAsset, CheckingAccount> +{ fn can_check_in(origin: &MultiLocation, what: &MultiAsset) -> Result { - FungiblesMutateAdapter::<Assets, Matcher, AccountIdConverter, AccountId, CheckAsset, CheckingAccount> - ::can_check_in(origin, what) + FungiblesMutateAdapter::< + Assets, + Matcher, + AccountIdConverter, + AccountId, + CheckAsset, + CheckingAccount, + >::can_check_in(origin, what) } fn check_in(origin: &MultiLocation, what: &MultiAsset) { - FungiblesMutateAdapter::<Assets, Matcher, AccountIdConverter, AccountId, CheckAsset, CheckingAccount> - ::check_in(origin, what) + FungiblesMutateAdapter::< + Assets, + Matcher, + AccountIdConverter, + AccountId, + CheckAsset, + CheckingAccount, + >::check_in(origin, what) } fn check_out(dest: &MultiLocation, what: &MultiAsset) { - FungiblesMutateAdapter::<Assets, Matcher, AccountIdConverter, AccountId, CheckAsset, CheckingAccount> - ::check_out(dest, what) + FungiblesMutateAdapter::< + Assets, + Matcher, + AccountIdConverter, + AccountId, + CheckAsset, + CheckingAccount, + >::check_out(dest, what) } fn deposit_asset(what: &MultiAsset, who: &MultiLocation) -> Result { - FungiblesMutateAdapter::<Assets, Matcher, AccountIdConverter, AccountId, CheckAsset, CheckingAccount> - ::deposit_asset(what, who) + FungiblesMutateAdapter::< + Assets, + Matcher, + AccountIdConverter, + AccountId, + CheckAsset, + CheckingAccount, + >::deposit_asset(what, who) } fn withdraw_asset( what: &MultiAsset, - who: &MultiLocation + who: &MultiLocation, ) -> result::Result<xcm_executor::Assets, XcmError> { - FungiblesMutateAdapter::<Assets, Matcher, AccountIdConverter, AccountId, CheckAsset, CheckingAccount> - ::withdraw_asset(what, who) + FungiblesMutateAdapter::< + Assets, + Matcher, + AccountIdConverter, + AccountId, + CheckAsset, + CheckingAccount, + >::withdraw_asset(what, who) } fn transfer_asset( @@ -233,6 +294,8 @@ impl< from: &MultiLocation, to: &MultiLocation, ) -> result::Result<xcm_executor::Assets, XcmError> { - FungiblesTransferAdapter::<Assets, Matcher, AccountIdConverter, AccountId>::transfer_asset(what, from, to) + FungiblesTransferAdapter::<Assets, Matcher, AccountIdConverter, AccountId>::transfer_asset( + what, from, to, + ) } } diff --git a/xcm/xcm-builder/src/lib.rs b/xcm/xcm-builder/src/lib.rs index 339a9321e1ad..d2e2d2e23f38 100644 --- a/xcm/xcm-builder/src/lib.rs +++ b/xcm/xcm-builder/src/lib.rs @@ -27,21 +27,22 @@ mod tests; mod location_conversion; pub use location_conversion::{ - Account32Hash, ParentIsDefault, ChildParachainConvertsVia, SiblingParachainConvertsVia, AccountId32Aliases, - AccountKey20Aliases, LocationInverter, + Account32Hash, AccountId32Aliases, AccountKey20Aliases, ChildParachainConvertsVia, + LocationInverter, ParentIsDefault, SiblingParachainConvertsVia, }; mod origin_conversion; pub use origin_conversion::{ - SovereignSignedViaLocation, ParentAsSuperuser, ChildSystemParachainAsSuperuser, SiblingSystemParachainAsSuperuser, - ChildParachainAsNative, SiblingParachainAsNative, RelayChainAsNative, SignedAccountId32AsNative, - SignedAccountKey20AsNative, EnsureXcmOrigin, SignedToAccountId32, BackingToPlurality, + BackingToPlurality, ChildParachainAsNative, ChildSystemParachainAsSuperuser, EnsureXcmOrigin, + ParentAsSuperuser, RelayChainAsNative, SiblingParachainAsNative, + SiblingSystemParachainAsSuperuser, SignedAccountId32AsNative, SignedAccountKey20AsNative, + SignedToAccountId32, SovereignSignedViaLocation, }; mod barriers; pub use barriers::{ - TakeWeightCredit, AllowUnpaidExecutionFrom, AllowTopLevelPaidExecutionFrom, AllowKnownQueryResponses, - IsChildSystemParachain, + AllowKnownQueryResponses, AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, + IsChildSystemParachain, TakeWeightCredit, }; mod currency_adapter; @@ -50,13 +51,13 @@ pub use currency_adapter::CurrencyAdapter; mod fungibles_adapter; pub use fungibles_adapter::{ AsPrefixedGeneralIndex, ConvertedAbstractAssetId, ConvertedConcreteAssetId, FungiblesAdapter, - FungiblesMutateAdapter, FungiblesTransferAdapter + FungiblesMutateAdapter, FungiblesTransferAdapter, }; mod weight; -pub use weight::{FixedRateOfFungible, FixedWeightBounds, UsingComponents, TakeRevenue}; #[allow(deprecated)] pub use weight::FixedRateOfConcreteFungible; +pub use weight::{FixedRateOfFungible, FixedWeightBounds, TakeRevenue, UsingComponents}; mod matches_fungible; pub use matches_fungible::{IsAbstract, IsConcrete}; diff --git a/xcm/xcm-builder/src/matches_fungible.rs b/xcm/xcm-builder/src/matches_fungible.rs index 6b80994d1989..0b635f3c1cb8 100644 --- a/xcm/xcm-builder/src/matches_fungible.rs +++ b/xcm/xcm-builder/src/matches_fungible.rs @@ -16,10 +16,14 @@ //! Various implementations for the `MatchesFungible` trait. -use sp_std::{marker::PhantomData, convert::TryFrom}; -use sp_runtime::traits::CheckedConversion; -use xcm::v0::{MultiAsset, MultiLocation, AssetId::{Abstract, Concrete}, Fungibility::Fungible}; use frame_support::traits::Get; +use sp_runtime::traits::CheckedConversion; +use sp_std::{convert::TryFrom, marker::PhantomData}; +use xcm::v0::{ + AssetId::{Abstract, Concrete}, + Fungibility::Fungible, + MultiAsset, MultiLocation, +}; use xcm_executor::traits::MatchesFungible; /// Converts a `MultiAsset` into balance `B` if it is a concrete fungible with an id equal to that diff --git a/xcm/xcm-builder/src/mock.rs b/xcm/xcm-builder/src/mock.rs index d036d2997df1..6adc5b478343 100644 --- a/xcm/xcm-builder/src/mock.rs +++ b/xcm/xcm-builder/src/mock.rs @@ -14,23 +14,30 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see <http://www.gnu.org/licenses/>. -pub use sp_std::{fmt::Debug, marker::PhantomData, cell::RefCell}; -pub use sp_std::collections::{btree_map::BTreeMap, btree_set::BTreeSet}; -pub use parity_scale_codec::{Encode, Decode}; -pub use xcm::v0::prelude::*; +pub use crate::{ + AllowKnownQueryResponses, AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, + FixedRateOfFungible, FixedWeightBounds, LocationInverter, TakeWeightCredit, +}; pub use frame_support::{ + dispatch::{ + DispatchError, DispatchInfo, DispatchResultWithPostInfo, Dispatchable, Parameter, Weight, + }, ensure, parameter_types, - dispatch::{Dispatchable, Parameter, Weight, DispatchError, DispatchResultWithPostInfo, DispatchInfo}, - weights::{PostDispatchInfo, GetDispatchInfo}, sp_runtime::DispatchErrorWithPostInfo, - traits::{Get, Contains, IsInVec}, + traits::{Contains, Get, IsInVec}, + weights::{GetDispatchInfo, PostDispatchInfo}, }; -pub use xcm_executor::{ - Assets, Config, traits::{TransactAsset, ConvertOrigin, FilterAssetLocation, InvertLocation, OnResponse} +pub use parity_scale_codec::{Decode, Encode}; +pub use sp_std::{ + cell::RefCell, + collections::{btree_map::BTreeMap, btree_set::BTreeSet}, + fmt::Debug, + marker::PhantomData, }; -pub use crate::{ - TakeWeightCredit, AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, FixedWeightBounds, - FixedRateOfFungible, AllowKnownQueryResponses, LocationInverter, +pub use xcm::v0::prelude::*; +pub use xcm_executor::{ + traits::{ConvertOrigin, FilterAssetLocation, InvertLocation, OnResponse, TransactAsset}, + Assets, Config, }; pub enum TestOrigin { @@ -59,20 +66,18 @@ impl Dispatchable for TestCall { fn dispatch(self, origin: Self::Origin) -> DispatchResultWithPostInfo { let mut post_info = PostDispatchInfo::default(); post_info.actual_weight = match self { - TestCall::OnlyRoot(_, maybe_actual) - | TestCall::OnlySigned(_, maybe_actual, _) - | TestCall::OnlyParachain(_, maybe_actual, _) - | TestCall::Any(_, maybe_actual) - => maybe_actual, + TestCall::OnlyRoot(_, maybe_actual) | + TestCall::OnlySigned(_, maybe_actual, _) | + TestCall::OnlyParachain(_, maybe_actual, _) | + TestCall::Any(_, maybe_actual) => maybe_actual, }; if match (&origin, &self) { (TestOrigin::Parachain(i), TestCall::OnlyParachain(_, _, Some(j))) => i == j, (TestOrigin::Signed(i), TestCall::OnlySigned(_, _, Some(j))) => i == j, - (TestOrigin::Root, TestCall::OnlyRoot(..)) - | (TestOrigin::Parachain(_), TestCall::OnlyParachain(_, _, None)) - | (TestOrigin::Signed(_), TestCall::OnlySigned(_, _, None)) - | (_, TestCall::Any(..)) - => true, + (TestOrigin::Root, TestCall::OnlyRoot(..)) | + (TestOrigin::Parachain(_), TestCall::OnlyParachain(_, _, None)) | + (TestOrigin::Signed(_), TestCall::OnlySigned(_, _, None)) | + (_, TestCall::Any(..)) => true, _ => false, } { Ok(post_info) @@ -85,13 +90,12 @@ impl Dispatchable for TestCall { impl GetDispatchInfo for TestCall { fn get_dispatch_info(&self) -> DispatchInfo { let weight = *match self { - TestCall::OnlyRoot(estimate, ..) - | TestCall::OnlyParachain(estimate, ..) - | TestCall::OnlySigned(estimate, ..) - | TestCall::Any(estimate, ..) - => estimate, + TestCall::OnlyRoot(estimate, ..) | + TestCall::OnlyParachain(estimate, ..) | + TestCall::OnlySigned(estimate, ..) | + TestCall::Any(estimate, ..) => estimate, }; - DispatchInfo { weight, .. Default::default() } + DispatchInfo { weight, ..Default::default() } } } @@ -116,11 +120,7 @@ pub fn assets(who: u64) -> Vec<MultiAsset> { ASSETS.with(|a| a.borrow().get(&who).map_or(vec![], |a| a.clone().into())) } pub fn add_asset(who: u64, what: MultiAsset) { - ASSETS.with(|a| a.borrow_mut() - .entry(who) - .or_insert(Assets::new()) - .subsume(what) - ); + ASSETS.with(|a| a.borrow_mut().entry(who).or_insert(Assets::new()).subsume(what)); } pub struct TestAssetTransactor; @@ -133,16 +133,16 @@ impl TransactAsset for TestAssetTransactor { fn withdraw_asset(what: &MultiAsset, who: &MultiLocation) -> Result<Assets, XcmError> { let who = to_account(who.clone()).map_err(|_| XcmError::LocationCannotHold)?; - ASSETS.with(|a| a.borrow_mut() - .get_mut(&who) - .ok_or(XcmError::NotWithdrawable)? - .try_take(what.clone().into()) - .map_err(|_| XcmError::NotWithdrawable) - ) + ASSETS.with(|a| { + a.borrow_mut() + .get_mut(&who) + .ok_or(XcmError::NotWithdrawable)? + .try_take(what.clone().into()) + .map_err(|_| XcmError::NotWithdrawable) + }) } } - pub fn to_account(l: MultiLocation) -> Result<u64, MultiLocation> { Ok(match l { // Siblings at 2000+id @@ -161,14 +161,17 @@ pub fn to_account(l: MultiLocation) -> Result<u64, MultiLocation> { pub struct TestOriginConverter; impl ConvertOrigin<TestOrigin> for TestOriginConverter { - fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result<TestOrigin, MultiLocation> { + fn convert_origin( + origin: MultiLocation, + kind: OriginKind, + ) -> Result<TestOrigin, MultiLocation> { use OriginKind::*; 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, X1(AccountIndex64 { index, .. })) => Ok(TestOrigin::Signed(index)), (_, origin) => Err(origin), } } @@ -188,17 +191,15 @@ pub fn add_teleporter(from: MultiLocation, asset: MultiAssetFilter) { pub struct TestIsReserve; impl FilterAssetLocation for TestIsReserve { fn filter_asset_location(asset: &MultiAsset, origin: &MultiLocation) -> bool { - IS_RESERVE.with(|r| r.borrow().get(origin) - .map_or(false, |v| v.iter().any(|a| a.contains(asset))) - ) + IS_RESERVE + .with(|r| r.borrow().get(origin).map_or(false, |v| v.iter().any(|a| a.contains(asset)))) } } pub struct TestIsTeleporter; impl FilterAssetLocation for TestIsTeleporter { fn filter_asset_location(asset: &MultiAsset, origin: &MultiLocation) -> bool { - IS_TELEPORTER.with(|r| r.borrow().get(origin) - .map_or(false, |v| v.iter().any(|a| a.contains(asset))) - ) + IS_TELEPORTER + .with(|r| r.borrow().get(origin).map_or(false, |v| v.iter().any(|a| a.contains(asset)))) } } @@ -220,28 +221,25 @@ impl OnResponse for TestResponseHandler { } fn on_response(_origin: MultiLocation, query_id: u64, response: xcm::v0::Response) -> Weight { QUERIES.with(|q| { - q.borrow_mut() - .entry(query_id) - .and_modify(|v| if matches!(*v, ResponseSlot::Expecting(..)) { + q.borrow_mut().entry(query_id).and_modify(|v| { + if matches!(*v, ResponseSlot::Expecting(..)) { *v = ResponseSlot::Received(response); - }); + } + }); }); 10 } } pub fn expect_response(query_id: u64, from: MultiLocation) { - QUERIES.with(|q| q.borrow_mut() - .insert(query_id, ResponseSlot::Expecting(from)) - ); + QUERIES.with(|q| q.borrow_mut().insert(query_id, ResponseSlot::Expecting(from))); } pub fn response(query_id: u64) -> Option<Response> { - QUERIES.with(|q| q.borrow() - .get(&query_id) - .and_then(|v| match v { + QUERIES.with(|q| { + q.borrow().get(&query_id).and_then(|v| match v { ResponseSlot::Received(r) => Some(r.clone()), _ => None, }) - ) + }) } parameter_types! { diff --git a/xcm/xcm-builder/src/tests.rs b/xcm/xcm-builder/src/tests.rs index e23c262ea660..5c7465440b29 100644 --- a/xcm/xcm-builder/src/tests.rs +++ b/xcm/xcm-builder/src/tests.rs @@ -14,10 +14,9 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see <http://www.gnu.org/licenses/>. -use super::*; -use super::mock::*; +use super::{mock::*, *}; use xcm::v0::prelude::*; -use xcm_executor::{XcmExecutor, Config, traits::*}; +use xcm_executor::{traits::*, Config, XcmExecutor}; #[test] fn basic_setup_works() { @@ -31,8 +30,8 @@ fn basic_setup_works() { 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(X1(AccountIndex64 { index: 1, network: Any })), Ok(1)); + assert_eq!(to_account(X1(AccountIndex64 { index: 42, network: Any })), Ok(42)); assert_eq!(to_account(Null), Ok(3000)); } @@ -41,50 +40,41 @@ fn weigher_should_work() { let mut message = opaque::Xcm::ReserveAssetDeposited { assets: (X1(Parent), 100).into(), effects: vec![ - Order::BuyExecution { fees: (X1(Parent), 1).into(), weight: 0, debt: 30, halt_on_error: true, xcm: vec![] }, + Order::BuyExecution { + fees: (X1(Parent), 1).into(), + weight: 0, + debt: 30, + halt_on_error: true, + xcm: vec![], + }, Order::DepositAsset { assets: All.into(), dest: Null }, ], - }.into(); + } + .into(); assert_eq!(<TestConfig as Config>::Weigher::shallow(&mut message), Ok(30)); } #[test] fn take_weight_credit_barrier_should_work() { - let mut message = opaque::Xcm::TransferAsset { - assets: (X1(Parent), 100).into(), - dest: Null, - }; + let mut message = opaque::Xcm::TransferAsset { assets: (X1(Parent), 100).into(), dest: Null }; let mut weight_credit = 10; - let r = TakeWeightCredit::should_execute( - &X1(Parent), - true, - &mut message, - 10, - &mut weight_credit, - ); + let r = + TakeWeightCredit::should_execute(&X1(Parent), 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(&X1(Parent), true, &mut message, 10, &mut weight_credit); assert_eq!(r, Err(())); assert_eq!(weight_credit, 0); } #[test] fn allow_unpaid_should_work() { - let mut message = opaque::Xcm::TransferAsset { - assets: (X1(Parent), 100).into(), - dest: Null, - }; + let mut message = opaque::Xcm::TransferAsset { assets: (X1(Parent), 100).into(), dest: Null }; - AllowUnpaidFrom::set(vec![ X1(Parent) ]); + AllowUnpaidFrom::set(vec![X1(Parent)]); let r = AllowUnpaidExecutionFrom::<IsInVec<AllowUnpaidFrom>>::should_execute( &X1(Parachain(1)), @@ -107,12 +97,9 @@ fn allow_unpaid_should_work() { #[test] fn allow_paid_should_work() { - AllowPaidFrom::set(vec![ X1(Parent) ]); + AllowPaidFrom::set(vec![X1(Parent)]); - let mut message = opaque::Xcm::TransferAsset { - assets: (X1(Parent), 100).into(), - dest: Null, - }; + let mut message = opaque::Xcm::TransferAsset { assets: (X1(Parent), 100).into(), dest: Null }; let r = AllowTopLevelPaidExecutionFrom::<IsInVec<AllowPaidFrom>>::should_execute( &X1(Parachain(1)), @@ -171,7 +158,7 @@ fn allow_paid_should_work() { #[test] fn paying_reserve_deposit_should_work() { - AllowPaidFrom::set(vec![ X1(Parent) ]); + AllowPaidFrom::set(vec![X1(Parent)]); add_reserve(X1(Parent), (X1(Parent), WildFungible).into()); WeightPrice::set((X1(Parent).into(), 1_000_000_000_000)); @@ -180,7 +167,13 @@ fn paying_reserve_deposit_should_work() { let message = Xcm::<TestCall>::ReserveAssetDeposited { assets: (X1(Parent), 100).into(), effects: vec![ - Order::<TestCall>::BuyExecution { fees, weight: 0, debt: 30, halt_on_error: true, xcm: vec![] }, + Order::<TestCall>::BuyExecution { + fees, + weight: 0, + debt: 30, + halt_on_error: true, + xcm: vec![], + }, Order::<TestCall>::DepositAsset { assets: All.into(), dest: Null }, ], }; @@ -193,7 +186,7 @@ fn paying_reserve_deposit_should_work() { #[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))]); // Child parachain #1 owns 1000 tokens held by us in reserve. add_asset(1001, (Null, 1000).into()); // They want to transfer 100 of them to their sibling parachain #2 @@ -201,7 +194,7 @@ fn transfer_should_work() { X1(Parachain(1)), Xcm::TransferAsset { assets: (Null, 100).into(), - dest: X1(AccountIndex64{index:3, network:Any}), + dest: X1(AccountIndex64 { index: 3, network: Any }), }, 50, ); @@ -213,11 +206,11 @@ fn transfer_should_work() { #[test] fn reserve_transfer_should_work() { - AllowUnpaidFrom::set(vec![ X1(Parachain(1)) ]); + AllowUnpaidFrom::set(vec![X1(Parachain(1))]); // Child parachain #1 owns 1000 tokens held by us in reserve. add_asset(1001, (Null, 1000).into()); // The remote account owned by gav. - let three = X1(AccountIndex64{index:3, network:Any}); + let three = X1(AccountIndex64 { index: 3, network: Any }); // 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. @@ -226,25 +219,28 @@ fn reserve_transfer_should_work() { Xcm::TransferReserveAsset { assets: (Null, 100).into(), dest: X1(Parachain(2)), - effects: vec![ Order::DepositAsset { assets: All.into(), dest: three.clone() } ], + effects: vec![Order::DepositAsset { assets: All.into(), dest: three.clone() }], }, 50, ); assert_eq!(r, Outcome::Complete(10)); assert_eq!(assets(1002), vec![(Null, 100).into()]); - assert_eq!(sent_xcm(), vec![( - X1(Parachain(2)), - Xcm::ReserveAssetDeposited { - assets: (X1(Parent), 100).into(), - effects: vec![ Order::DepositAsset { assets: All.into(), dest: three } ], - }) - ]); + assert_eq!( + sent_xcm(), + vec![( + X1(Parachain(2)), + Xcm::ReserveAssetDeposited { + assets: (X1(Parent), 100).into(), + effects: vec![Order::DepositAsset { assets: All.into(), dest: three }], + } + )] + ); } #[test] fn transacting_should_work() { - AllowUnpaidFrom::set(vec![ X1(Parent) ]); + AllowUnpaidFrom::set(vec![X1(Parent)]); let origin = X1(Parent); let message = Xcm::<TestCall>::Transact { @@ -259,7 +255,7 @@ fn transacting_should_work() { #[test] fn transacting_should_respect_max_weight_requirement() { - AllowUnpaidFrom::set(vec![ X1(Parent) ]); + AllowUnpaidFrom::set(vec![X1(Parent)]); let origin = X1(Parent); let message = Xcm::<TestCall>::Transact { @@ -274,7 +270,7 @@ fn transacting_should_respect_max_weight_requirement() { #[test] fn transacting_should_refund_weight() { - AllowUnpaidFrom::set(vec![ X1(Parent) ]); + AllowUnpaidFrom::set(vec![X1(Parent)]); let origin = X1(Parent); let message = Xcm::<TestCall>::Transact { @@ -289,24 +285,28 @@ fn transacting_should_refund_weight() { #[test] fn paid_transacting_should_refund_payment_for_unused_weight() { - let one = X1(AccountIndex64{index:1, network:Any}); - AllowPaidFrom::set(vec![ one.clone() ]); + let one = X1(AccountIndex64 { index: 1, network: Any }); + AllowPaidFrom::set(vec![one.clone()]); add_asset(1, (X1(Parent), 100).into()); WeightPrice::set((X1(Parent).into(), 1_000_000_000_000)); let origin = one.clone(); let fees = (X1(Parent), 100).into(); let message = Xcm::<TestCall>::WithdrawAsset { - assets: (X1(Parent), 100).into(), // enough for 100 units of weight. + assets: (X1(Parent), 100).into(), // enough for 100 units of weight. effects: vec![ - Order::<TestCall>::BuyExecution { fees, weight: 70, debt: 30, halt_on_error: true, xcm: vec![ - Xcm::<TestCall>::Transact { + Order::<TestCall>::BuyExecution { + fees, + weight: 70, + debt: 30, + halt_on_error: true, + xcm: vec![Xcm::<TestCall>::Transact { origin_type: OriginKind::Native, require_weight_at_most: 60, // call estimated at 70 but only takes 10. call: TestCall::Any(60, Some(10)).encode().into(), - } - ] }, + }], + }, Order::<TestCall>::DepositAsset { assets: All.into(), dest: one.clone() }, ], }; @@ -324,10 +324,7 @@ fn prepaid_result_of_query_should_get_free_execution() { expect_response(query_id, origin.clone()); let the_response = Response::Assets((X1(Parent), 100).into()); - let message = Xcm::<TestCall>::QueryResponse { - query_id, - response: the_response.clone(), - }; + let message = Xcm::<TestCall>::QueryResponse { query_id, response: the_response.clone() }; let weight_limit = 10; // First time the response gets through since we're expecting it... diff --git a/xcm/xcm-builder/src/weight.rs b/xcm/xcm-builder/src/weight.rs index 500db2a393c1..faee6a08f23c 100644 --- a/xcm/xcm-builder/src/weight.rs +++ b/xcm/xcm-builder/src/weight.rs @@ -14,27 +14,32 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see <http://www.gnu.org/licenses/>. -use sp_std::{result::Result, marker::PhantomData, convert::TryInto}; +use frame_support::{ + traits::{tokens::currency::Currency as CurrencyT, Get, OnUnbalanced as OnUnbalancedT}, + weights::{GetDispatchInfo, Weight, WeightToFeePolynomial}, +}; use parity_scale_codec::Decode; -use xcm::v0::{Xcm, Order, MultiAsset, AssetId, MultiLocation, Error, AssetId::Concrete}; -use sp_runtime::traits::{Zero, Saturating, SaturatedConversion}; -use frame_support::traits::{Get, OnUnbalanced as OnUnbalancedT, tokens::currency::Currency as CurrencyT}; -use frame_support::weights::{Weight, GetDispatchInfo, WeightToFeePolynomial}; -use xcm_executor::{Assets, traits::{WeightBounds, WeightTrader}}; +use sp_runtime::traits::{SaturatedConversion, Saturating, Zero}; +use sp_std::{convert::TryInto, marker::PhantomData, result::Result}; +use xcm::v0::{AssetId, AssetId::Concrete, Error, MultiAsset, MultiLocation, Order, Xcm}; +use xcm_executor::{ + traits::{WeightBounds, WeightTrader}, + Assets, +}; pub struct FixedWeightBounds<T, C>(PhantomData<(T, C)>); impl<T: Get<Weight>, C: Decode + GetDispatchInfo> WeightBounds<C> for FixedWeightBounds<T, C> { fn shallow(message: &mut Xcm<C>) -> Result<Weight, ()> { Ok(match message { - Xcm::Transact { call, .. } => { - call.ensure_decoded()?.get_dispatch_info().weight.saturating_add(T::get()) - } - Xcm::RelayedFrom { ref mut message, .. } => T::get().saturating_add(Self::shallow(message.as_mut())?), - Xcm::WithdrawAsset { effects, .. } - | Xcm::ReserveAssetDeposited { effects, .. } - | Xcm::TeleportAsset { effects, .. } - => { - let inner: Weight = effects.iter_mut() + Xcm::Transact { call, .. } => + call.ensure_decoded()?.get_dispatch_info().weight.saturating_add(T::get()), + Xcm::RelayedFrom { ref mut message, .. } => + T::get().saturating_add(Self::shallow(message.as_mut())?), + Xcm::WithdrawAsset { effects, .. } | + Xcm::ReserveAssetDeposited { effects, .. } | + Xcm::TeleportAsset { effects, .. } => { + let inner: Weight = effects + .iter_mut() .map(|effect| match effect { Order::BuyExecution { .. } => { // On success, execution of this will result in more weight being consumed but @@ -45,28 +50,29 @@ impl<T: Get<Weight>, C: Decode + GetDispatchInfo> WeightBounds<C> for FixedWeigh T::get() }, _ => T::get(), - }).sum(); + }) + .sum(); T::get().saturating_add(inner) - } + }, _ => T::get(), }) } fn deep(message: &mut Xcm<C>) -> Result<Weight, ()> { Ok(match message { Xcm::RelayedFrom { ref mut message, .. } => Self::deep(message.as_mut())?, - Xcm::WithdrawAsset { effects, .. } - | Xcm::ReserveAssetDeposited { effects, .. } - | Xcm::TeleportAsset { effects, .. } - => { + Xcm::WithdrawAsset { effects, .. } | + Xcm::ReserveAssetDeposited { effects, .. } | + Xcm::TeleportAsset { effects, .. } => { let mut extra = 0; for effect in effects.iter_mut() { match effect { - Order::BuyExecution { xcm, .. } => { + Order::BuyExecution { xcm, .. } => for message in xcm.iter_mut() { - extra.saturating_accrue(Self::shallow(message)?.saturating_add(Self::deep(message)?)); - } - }, - _ => {} + extra.saturating_accrue( + Self::shallow(message)?.saturating_add(Self::deep(message)?), + ); + }, + _ => {}, } } extra @@ -93,13 +99,18 @@ impl TakeRevenue for () { /// The constant `Get` type parameter should be the concrete fungible ID and the amount of it required for /// one second of weight. #[deprecated = "Use `FixedRateOfFungible` instead"] -pub struct FixedRateOfConcreteFungible< - T: Get<(MultiLocation, u128)>, - R: TakeRevenue, ->(Weight, u128, PhantomData<(T, R)>); +pub struct FixedRateOfConcreteFungible<T: Get<(MultiLocation, u128)>, R: TakeRevenue>( + Weight, + u128, + PhantomData<(T, R)>, +); #[allow(deprecated)] -impl<T: Get<(MultiLocation, u128)>, R: TakeRevenue> WeightTrader for FixedRateOfConcreteFungible<T, R> { - fn new() -> Self { Self(0, 0, PhantomData) } +impl<T: Get<(MultiLocation, u128)>, R: TakeRevenue> WeightTrader + for FixedRateOfConcreteFungible<T, R> +{ + fn new() -> Self { + Self(0, 0, PhantomData) + } fn buy_weight(&mut self, weight: Weight, payment: Assets) -> Result<Assets, Error> { let (id, units_per_second) = T::get(); @@ -137,12 +148,15 @@ impl<T: Get<(MultiLocation, u128)>, R: TakeRevenue> Drop for FixedRateOfConcrete /// /// The constant `Get` type parameter should be the fungible ID and the amount of it required for /// one second of weight. -pub struct FixedRateOfFungible< - T: Get<(AssetId, u128)>, - R: TakeRevenue, ->(Weight, u128, PhantomData<(T, R)>); +pub struct FixedRateOfFungible<T: Get<(AssetId, u128)>, R: TakeRevenue>( + Weight, + u128, + PhantomData<(T, R)>, +); impl<T: Get<(AssetId, u128)>, R: TakeRevenue> WeightTrader for FixedRateOfFungible<T, R> { - fn new() -> Self { Self(0, 0, PhantomData) } + fn new() -> Self { + Self(0, 0, PhantomData) + } fn buy_weight(&mut self, weight: Weight, payment: Assets) -> Result<Assets, Error> { let (id, units_per_second) = T::get(); @@ -179,20 +193,27 @@ impl<T: Get<(AssetId, u128)>, R: TakeRevenue> Drop for FixedRateOfFungible<T, R> /// Weight trader which uses the `TransactionPayment` pallet to set the right price for weight and then /// places any weight bought into the right account. pub struct UsingComponents< - WeightToFee: WeightToFeePolynomial<Balance=Currency::Balance>, + WeightToFee: WeightToFeePolynomial<Balance = Currency::Balance>, AssetId: Get<MultiLocation>, AccountId, Currency: CurrencyT<AccountId>, OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>, ->(Weight, Currency::Balance, PhantomData<(WeightToFee, AssetId, AccountId, Currency, OnUnbalanced)>); +>( + Weight, + Currency::Balance, + PhantomData<(WeightToFee, AssetId, AccountId, Currency, OnUnbalanced)>, +); impl< - WeightToFee: WeightToFeePolynomial<Balance=Currency::Balance>, - AssetId: Get<MultiLocation>, - AccountId, - Currency: CurrencyT<AccountId>, - OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>, -> WeightTrader for UsingComponents<WeightToFee, AssetId, AccountId, Currency, OnUnbalanced> { - fn new() -> Self { Self(0, Zero::zero(), PhantomData) } + WeightToFee: WeightToFeePolynomial<Balance = Currency::Balance>, + AssetId: Get<MultiLocation>, + AccountId, + Currency: CurrencyT<AccountId>, + OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>, + > WeightTrader for UsingComponents<WeightToFee, AssetId, AccountId, Currency, OnUnbalanced> +{ + fn new() -> Self { + Self(0, Zero::zero(), PhantomData) + } fn buy_weight(&mut self, weight: Weight, payment: Assets) -> Result<Assets, Error> { let amount = WeightToFee::calc(&weight); @@ -216,15 +237,15 @@ impl< None } } - } impl< - WeightToFee: WeightToFeePolynomial<Balance=Currency::Balance>, - AssetId: Get<MultiLocation>, - AccountId, - Currency: CurrencyT<AccountId>, - OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>, -> Drop for UsingComponents<WeightToFee, AssetId, AccountId, Currency, OnUnbalanced> { + WeightToFee: WeightToFeePolynomial<Balance = Currency::Balance>, + AssetId: Get<MultiLocation>, + AccountId, + Currency: CurrencyT<AccountId>, + OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>, + > Drop for UsingComponents<WeightToFee, AssetId, AccountId, Currency, OnUnbalanced> +{ fn drop(&mut self) { OnUnbalanced::on_unbalanced(Currency::issue(self.1)); } diff --git a/xcm/xcm-executor/src/assets.rs b/xcm/xcm-executor/src/assets.rs index 85ab40a8eb9b..a7e48662e719 100644 --- a/xcm/xcm-executor/src/assets.rs +++ b/xcm/xcm-executor/src/assets.rs @@ -14,14 +14,19 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see <http://www.gnu.org/licenses/>. -use sp_std::{prelude::*, mem, collections::{btree_map::BTreeMap, btree_set::BTreeSet}}; +use sp_runtime::RuntimeDebug; +use sp_std::{ + collections::{btree_map::BTreeMap, btree_set::BTreeSet}, + mem, + prelude::*, +}; use xcm::v0::{ - MultiAsset, MultiAssets, MultiLocation, AssetInstance, MultiAssetFilter, AssetId, - WildMultiAsset::{All, AllOf}, + AssetId, AssetInstance, Fungibility::{Fungible, NonFungible}, + MultiAsset, MultiAssetFilter, MultiAssets, MultiLocation, WildFungibility::{Fungible as WildFungible, NonFungible as WildNonFungible}, + WildMultiAsset::{All, AllOf}, }; -use sp_runtime::RuntimeDebug; /// List of non-wildcard fungible and non-fungible assets. #[derive(Default, Clone, RuntimeDebug, Eq, PartialEq)] @@ -80,26 +85,38 @@ pub enum TakeError { impl Assets { /// New value, containing no assets. - pub fn new() -> Self { Self::default() } + pub fn new() -> Self { + Self::default() + } /// A borrowing iterator over the fungible assets. - pub fn fungible_assets_iter<'a>(&'a self) -> impl Iterator<Item=MultiAsset> + 'a { - self.fungible.iter().map(|(id, &amount)| MultiAsset { fun: Fungible(amount), id: id.clone() }) + pub fn fungible_assets_iter<'a>(&'a self) -> impl Iterator<Item = MultiAsset> + 'a { + self.fungible + .iter() + .map(|(id, &amount)| MultiAsset { fun: Fungible(amount), id: id.clone() }) } /// A borrowing iterator over the non-fungible assets. - pub fn non_fungible_assets_iter<'a>(&'a self) -> impl Iterator<Item=MultiAsset> + 'a { - self.non_fungible.iter().map(|(id, instance)| MultiAsset { fun: NonFungible(instance.clone()), id: id.clone() }) + pub fn non_fungible_assets_iter<'a>(&'a self) -> impl Iterator<Item = MultiAsset> + 'a { + self.non_fungible + .iter() + .map(|(id, instance)| MultiAsset { fun: NonFungible(instance.clone()), id: id.clone() }) } /// A consuming iterator over all assets. - pub fn into_assets_iter(self) -> impl Iterator<Item=MultiAsset> { - self.fungible.into_iter().map(|(id, amount)| MultiAsset { fun: Fungible(amount), id }) - .chain(self.non_fungible.into_iter().map(|(id, instance)| MultiAsset { fun: NonFungible(instance), id })) + pub fn into_assets_iter(self) -> impl Iterator<Item = MultiAsset> { + self.fungible + .into_iter() + .map(|(id, amount)| MultiAsset { fun: Fungible(amount), id }) + .chain( + self.non_fungible + .into_iter() + .map(|(id, instance)| MultiAsset { fun: NonFungible(instance), id }), + ) } /// A borrowing iterator over all assets. - pub fn assets_iter<'a>(&'a self) -> impl Iterator<Item=MultiAsset> + 'a { + pub fn assets_iter<'a>(&'a self) -> impl Iterator<Item = MultiAsset> + 'a { self.fungible_assets_iter().chain(self.non_fungible_assets_iter()) } @@ -110,7 +127,7 @@ impl Assets { if let (Some(mut f), Some(mut g)) = (f_iter.next(), g_iter.next()) { loop { if f.0 == g.0 { - // keys are equal. in this case, we add `swlf`'s balance for the asset onto `assets`, balance, knowing + // keys are equal. in this case, we add `self`'s balance for the asset onto `assets`, balance, knowing // that the `append` operation which follows will clobber `self`'s value and only use `assets`'s. *f.1 += *g.1; } @@ -142,10 +159,10 @@ impl Assets { .entry(asset.id) .and_modify(|e| *e = e.saturating_add(amount)) .or_insert(amount); - } + }, NonFungible(instance) => { self.non_fungible.insert((asset.id, instance)); - } + }, } } @@ -162,13 +179,21 @@ impl Assets { pub fn prepend_location(&mut self, prepend: &MultiLocation) { let mut fungible = Default::default(); mem::swap(&mut self.fungible, &mut fungible); - self.fungible = fungible.into_iter() - .map(|(mut id, amount)| { let _ = id.reanchor(prepend); (id, amount) }) + self.fungible = fungible + .into_iter() + .map(|(mut id, amount)| { + let _ = id.reanchor(prepend); + (id, amount) + }) .collect(); let mut non_fungible = Default::default(); mem::swap(&mut self.non_fungible, &mut non_fungible); - self.non_fungible = non_fungible.into_iter() - .map(|(mut class, inst)| { let _ = class.reanchor(prepend); (class, inst) }) + self.non_fungible = non_fungible + .into_iter() + .map(|(mut class, inst)| { + let _ = class.reanchor(prepend); + (class, inst) + }) .collect(); } @@ -181,13 +206,13 @@ impl Assets { if self.fungible.get(id).map_or(true, |a| a < amount) { return Err(TakeError::AssetUnderflow((id.clone(), *amount).into())) } - } + }, MultiAsset { fun: NonFungible(ref instance), ref id } => { let id_instance = (id.clone(), instance.clone()); if !self.non_fungible.contains(&id_instance) { return Err(TakeError::AssetUnderflow(id_instance.into())) } - } + }, } } return Ok(()) @@ -202,7 +227,11 @@ impl Assets { /// Returns `Ok` with the definite assets token from `self` and mutates `self` to its value minus /// `mask`. Returns `Err` in the non-saturating case where `self` did not contain (enough of) a definite asset to /// be removed. - fn general_take(&mut self, mask: MultiAssetFilter, saturate: bool) -> Result<Assets, TakeError> { + fn general_take( + &mut self, + mask: MultiAssetFilter, + saturate: bool, + ) -> Result<Assets, TakeError> { let mut taken = Assets::new(); match mask { MultiAssetFilter::Wild(All) => return Ok(self.swapped(Assets::new())), @@ -210,7 +239,7 @@ impl Assets { if let Some((id, amount)) = self.fungible.remove_entry(&id) { taken.fungible.insert(id, amount); } - } + }, MultiAssetFilter::Wild(AllOf { fun: WildNonFungible, id }) => { let non_fungible = mem::replace(&mut self.non_fungible, Default::default()); non_fungible.into_iter().for_each(|(c, instance)| { @@ -220,7 +249,7 @@ impl Assets { self.non_fungible.insert((c, instance)); } }); - } + }, MultiAssetFilter::Definite(assets) => { if !saturate { self.ensure_contains(&assets)?; @@ -233,7 +262,7 @@ impl Assets { let amount = amount.min(*self_amount); *self_amount -= amount; (*self_amount == 0, amount) - } + }, None => (false, 0), }; if remove { @@ -242,16 +271,16 @@ impl Assets { if amount > 0 { taken.subsume(MultiAsset::from((id, amount)).into()); } - } + }, MultiAsset { fun: NonFungible(instance), id } => { let id_instance = (id, instance); if self.non_fungible.remove(&id_instance) { taken.subsume(id_instance.into()) } - } + }, } } - } + }, } Ok(taken) } @@ -291,12 +320,13 @@ impl Assets { self.fungible.remove(&asset.id); } Ok(self) - } - NonFungible(instance) => if self.non_fungible.remove(&(asset.id, instance)) { - Ok(self) - } else { - Err(self) }, + NonFungible(instance) => + if self.non_fungible.remove(&(asset.id, instance)) { + Ok(self) + } else { + Err(self) + }, } } @@ -325,31 +355,30 @@ impl Assets { if let Some(&amount) = self.fungible.get(&id) { masked.fungible.insert(id.clone(), amount); } - } + }, MultiAssetFilter::Wild(AllOf { fun: WildNonFungible, id }) => { self.non_fungible.iter().for_each(|(ref c, ref instance)| { if c == id { masked.non_fungible.insert((c.clone(), instance.clone())); } }); - } - MultiAssetFilter::Definite(assets) => { + }, + MultiAssetFilter::Definite(assets) => for asset in assets.inner().iter() { match asset { MultiAsset { fun: Fungible(ref amount), ref id } => { if let Some(m) = self.fungible.get(id) { masked.subsume((id.clone(), Fungible(*amount.min(m))).into()); } - } + }, MultiAsset { fun: NonFungible(ref instance), ref id } => { let id_instance = (id.clone(), instance.clone()); if self.non_fungible.contains(&id_instance) { masked.subsume(id_instance.into()); } - } + }, } - } - } + }, } masked } @@ -397,7 +426,9 @@ mod tests { let mut r1 = t1.clone(); r1.subsume_assets(t2.clone()); let mut r2 = t1.clone(); - for a in t2.assets_iter() { r2.subsume(a) } + for a in t2.assets_iter() { + r2.subsume(a) + } assert_eq!(r1, r2); } diff --git a/xcm/xcm-executor/src/lib.rs b/xcm/xcm-executor/src/lib.rs index a12d714cac6c..d6dcbd1f93fd 100644 --- a/xcm/xcm-executor/src/lib.rs +++ b/xcm/xcm-executor/src/lib.rs @@ -16,17 +16,21 @@ #![cfg_attr(not(feature = "std"), no_std)] -use sp_std::{prelude::*, marker::PhantomData}; use frame_support::{ - ensure, weights::GetDispatchInfo, - dispatch::{Weight, Dispatchable} + dispatch::{Dispatchable, Weight}, + ensure, + weights::GetDispatchInfo, +}; +use sp_std::{marker::PhantomData, prelude::*}; +use xcm::v0::{ + Error as XcmError, ExecuteXcm, MultiAssets, MultiLocation, Order, Outcome, Response, SendXcm, + Xcm, }; -use xcm::v0::{ExecuteXcm, SendXcm, Error as XcmError, Outcome, MultiLocation, MultiAssets, Xcm, Order, Response}; pub mod traits; use traits::{ - TransactAsset, ConvertOrigin, FilterAssetLocation, InvertLocation, WeightBounds, WeightTrader, - ShouldExecute, OnResponse + ConvertOrigin, FilterAssetLocation, InvertLocation, OnResponse, ShouldExecute, TransactAsset, + WeightBounds, WeightTrader, }; mod assets; @@ -67,10 +71,17 @@ impl<Config: config::Config> ExecuteXcm<Config::Call> for XcmExecutor<Config> { None => return Outcome::Error(XcmError::Overflow), }; if maximum_weight > weight_limit { - return Outcome::Error(XcmError::WeightLimitReached(maximum_weight)); + return Outcome::Error(XcmError::WeightLimitReached(maximum_weight)) } let mut trader = Config::Trader::new(); - let result = Self::do_execute_xcm(origin, true, message, &mut weight_credit, Some(shallow_weight), &mut trader); + let result = Self::do_execute_xcm( + origin, + true, + message, + &mut weight_credit, + Some(shallow_weight), + &mut trader, + ); drop(trader); log::trace!(target: "xcm::execute_xcm", "result: {:?}", &result); match result { @@ -115,8 +126,14 @@ impl<Config: config::Config> XcmExecutor<Config> { .or_else(|| Config::Weigher::shallow(&mut message).ok()) .ok_or(XcmError::WeightNotComputable)?; - Config::Barrier::should_execute(&origin, top_level, &message, shallow_weight, weight_credit) - .map_err(|()| XcmError::Barrier)?; + Config::Barrier::should_execute( + &origin, + top_level, + &message, + shallow_weight, + weight_credit, + ) + .map_err(|()| XcmError::Barrier)?; // The surplus weight, defined as the amount by which `shallow_weight` plus all nested // `shallow_weight` values (ensuring no double-counting and also known as `deep_weight`) is an @@ -132,23 +149,26 @@ impl<Config: config::Config> XcmExecutor<Config> { holding.subsume_assets(withdrawn); } Some((holding, effects)) - } + }, (origin, Xcm::ReserveAssetDeposited { assets, effects }) => { // check whether we trust origin to be our reserve location for this asset. for asset in assets.inner() { // We only trust the origin to send us assets that they identify as their // sovereign assets. - ensure!(Config::IsReserve::filter_asset_location(asset, &origin), XcmError::UntrustedReserveLocation); + ensure!( + Config::IsReserve::filter_asset_location(asset, &origin), + XcmError::UntrustedReserveLocation + ); } Some((assets.into(), effects)) - } + }, (origin, Xcm::TransferAsset { assets, dest }) => { // Take `assets` from the origin account (on-chain) and place into dest account. for asset in assets.inner() { Config::AssetTransactor::beam_asset(&asset, &origin, &dest)?; } None - } + }, (origin, Xcm::TransferReserveAsset { mut assets, dest, effects }) => { // Take `assets` from the origin account (on-chain) and place into dest account. let inv_dest = Config::LocationInverter::invert_location(&dest); @@ -158,13 +178,16 @@ impl<Config: config::Config> XcmExecutor<Config> { assets.reanchor(&inv_dest)?; Config::XcmSender::send_xcm(dest, Xcm::ReserveAssetDeposited { assets, effects })?; None - } + }, (origin, Xcm::TeleportAsset { assets, effects }) => { // check whether we trust origin to teleport this asset to us via config trait. for asset in assets.inner() { // We only trust the origin to send us assets that they identify as their // sovereign assets. - ensure!(Config::IsTeleporter::filter_asset_location(asset, &origin), XcmError::UntrustedTeleportLocation); + ensure!( + Config::IsTeleporter::filter_asset_location(asset, &origin), + XcmError::UntrustedTeleportLocation + ); // We should check that the asset can actually be teleported in (for this to be in error, there // would need to be an accounting violation by one of the trusted chains, so it's unlikely, but we // don't want to punish a possibly innocent chain/user). @@ -174,7 +197,7 @@ impl<Config: config::Config> XcmExecutor<Config> { Config::AssetTransactor::check_in(&origin, asset); } Some((Assets::from(assets), effects)) - } + }, (origin, Xcm::Transact { origin_type, require_weight_at_most, mut call }) => { // We assume that the Relay-chain is allowed to use transact on this parachain. @@ -190,8 +213,9 @@ impl<Config: config::Config> XcmExecutor<Config> { // Not much to do with the result as it is. It's up to the parachain to ensure that the // message makes sense. error_and_info.post_info.actual_weight - } - }.unwrap_or(weight); + }, + } + .unwrap_or(weight); let surplus = weight.saturating_sub(actual_weight); // Credit any surplus weight that we bought. This should be safe since it's work we // didn't realise that we didn't have to do. @@ -204,20 +228,21 @@ impl<Config: config::Config> XcmExecutor<Config> { // Return the overestimated amount so we can adjust our expectations on how much this entire // execution has taken. None - } + }, (origin, Xcm::QueryResponse { query_id, response }) => { Config::ResponseHandler::on_response(origin, query_id, response); None - } + }, (origin, Xcm::RelayedFrom { who, message }) => { ensure!(who.is_interior(), XcmError::EscalationOfPrivilege); let mut origin = origin; origin.append_with(who).map_err(|_| XcmError::MultiLocationFull)?; - let surplus = Self::do_execute_xcm(origin, top_level, *message, weight_credit, None, trader)?; + let surplus = + Self::do_execute_xcm(origin, top_level, *message, weight_credit, None, trader)?; total_surplus = total_surplus.saturating_add(surplus); None - } - _ => Err(XcmError::UnhandledXcmMessage)?, // Unhandled XCM message. + }, + _ => Err(XcmError::UnhandledXcmMessage)?, // Unhandled XCM message. }; if let Some((mut holding, effects)) = maybe_holding_effects { @@ -258,11 +283,11 @@ impl<Config: config::Config> XcmExecutor<Config> { let assets = Self::reanchored(deposited, &dest); Config::XcmSender::send_xcm(dest, Xcm::ReserveAssetDeposited { assets, effects })?; }, - Order::InitiateReserveWithdraw { assets, reserve, effects} => { + Order::InitiateReserveWithdraw { assets, reserve, effects } => { let assets = Self::reanchored(holding.saturating_take(assets), &reserve); Config::XcmSender::send_xcm(reserve, Xcm::WithdrawAsset { assets, effects })?; - } - Order::InitiateTeleport { assets, dest, effects} => { + }, + Order::InitiateTeleport { assets, dest, effects } => { // We must do this first in order to resolve wildcards. let assets = holding.saturating_take(assets); for asset in assets.assets_iter() { @@ -270,30 +295,42 @@ impl<Config: config::Config> XcmExecutor<Config> { } let assets = Self::reanchored(assets, &dest); Config::XcmSender::send_xcm(dest, Xcm::TeleportAsset { assets, effects })?; - } + }, Order::QueryHolding { query_id, dest, assets } => { let assets = Self::reanchored(holding.min(&assets), &dest); - Config::XcmSender::send_xcm(dest, Xcm::QueryResponse { query_id, response: Response::Assets(assets) })?; - } + Config::XcmSender::send_xcm( + dest, + Xcm::QueryResponse { query_id, response: Response::Assets(assets) }, + )?; + }, Order::BuyExecution { fees, weight, debt, halt_on_error, xcm } => { // pay for `weight` using up to `fees` of the holding register. - let purchasing_weight = Weight::from(weight.checked_add(debt).ok_or(XcmError::Overflow)?); - let max_fee = holding.try_take(fees.into()).map_err(|_| XcmError::NotHoldingFees)?; + let purchasing_weight = + Weight::from(weight.checked_add(debt).ok_or(XcmError::Overflow)?); + let max_fee = + holding.try_take(fees.into()).map_err(|_| XcmError::NotHoldingFees)?; let unspent = trader.buy_weight(purchasing_weight, max_fee)?; holding.subsume_assets(unspent); let mut remaining_weight = weight; for message in xcm.into_iter() { - match Self::do_execute_xcm(origin.clone(), false, message, &mut remaining_weight, None, trader) { + match Self::do_execute_xcm( + origin.clone(), + false, + message, + &mut remaining_weight, + None, + trader, + ) { Err(e) if halt_on_error => return Err(e), - Err(_) => {} - Ok(surplus) => { total_surplus += surplus } + Err(_) => {}, + Ok(surplus) => total_surplus += surplus, } } if let Some(w) = trader.refund_weight(remaining_weight) { holding.subsume(w); } - } + }, _ => return Err(XcmError::UnhandledEffect)?, } Ok(total_surplus) diff --git a/xcm/xcm-executor/src/traits/transact_asset.rs b/xcm/xcm-executor/src/traits/transact_asset.rs index 09cd94b19918..d6114efbe09c 100644 --- a/xcm/xcm-executor/src/traits/transact_asset.rs +++ b/xcm/xcm-executor/src/traits/transact_asset.rs @@ -14,9 +14,9 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see <http://www.gnu.org/licenses/>. -use sp_std::result::Result; -use xcm::v0::{Error as XcmError, Result as XcmResult, MultiAsset, MultiLocation}; use crate::Assets; +use sp_std::result::Result; +use xcm::v0::{Error as XcmError, MultiAsset, MultiLocation, Result as XcmResult}; /// Facility for asset transacting. /// @@ -78,22 +78,30 @@ pub trait TransactAsset { /// Move an `asset` `from` one location in `to` another location. /// /// Returns `XcmError::FailedToTransactAsset` if transfer failed. - fn transfer_asset(_asset: &MultiAsset, _from: &MultiLocation, _to: &MultiLocation) -> Result<Assets, XcmError> { + fn transfer_asset( + _asset: &MultiAsset, + _from: &MultiLocation, + _to: &MultiLocation, + ) -> Result<Assets, XcmError> { Err(XcmError::Unimplemented) } /// Move an `asset` `from` one location in `to` another location. /// /// Attempts to use `transfer_asset` and if not available then falls back to using a two-part withdraw/deposit. - fn beam_asset(asset: &MultiAsset, from: &MultiLocation, to: &MultiLocation) -> Result<Assets, XcmError> { + fn beam_asset( + asset: &MultiAsset, + from: &MultiLocation, + to: &MultiLocation, + ) -> Result<Assets, XcmError> { match Self::transfer_asset(asset, from, to) { Err(XcmError::Unimplemented) => { let assets = Self::withdraw_asset(asset, from)?; // Not a very forgiving attitude; once we implement roll-backs then it'll be nicer. Self::deposit_asset(asset, to)?; Ok(assets) - } - result => result + }, + result => result, } } } @@ -160,7 +168,11 @@ impl TransactAsset for Tuple { Err(XcmError::AssetNotFound) } - fn transfer_asset(what: &MultiAsset, from: &MultiLocation, to: &MultiLocation) -> Result<Assets, XcmError> { + fn transfer_asset( + what: &MultiAsset, + from: &MultiLocation, + to: &MultiLocation, + ) -> Result<Assets, XcmError> { for_tuples!( #( match Tuple::transfer_asset(what, from, to) { Err(XcmError::AssetNotFound) | Err(XcmError::Unimplemented) => (), @@ -200,7 +212,11 @@ mod tests { Err(XcmError::AssetNotFound) } - fn transfer_asset(_what: &MultiAsset, _from: &MultiLocation, _to: &MultiLocation) -> Result<Assets, XcmError> { + fn transfer_asset( + _what: &MultiAsset, + _from: &MultiLocation, + _to: &MultiLocation, + ) -> Result<Assets, XcmError> { Err(XcmError::AssetNotFound) } } @@ -219,7 +235,11 @@ mod tests { Err(XcmError::Overflow) } - fn transfer_asset(_what: &MultiAsset, _from: &MultiLocation, _to: &MultiLocation) -> Result<Assets, XcmError> { + fn transfer_asset( + _what: &MultiAsset, + _from: &MultiLocation, + _to: &MultiLocation, + ) -> Result<Assets, XcmError> { Err(XcmError::Overflow) } } @@ -238,16 +258,24 @@ mod tests { Ok(Assets::default()) } - fn transfer_asset(_what: &MultiAsset, _from: &MultiLocation, _to: &MultiLocation) -> Result<Assets, XcmError> { + fn transfer_asset( + _what: &MultiAsset, + _from: &MultiLocation, + _to: &MultiLocation, + ) -> Result<Assets, XcmError> { Ok(Assets::default()) } } #[test] fn defaults_to_asset_not_found() { - type MultiTransactor = (UnimplementedTransactor, NotFoundTransactor, UnimplementedTransactor); + type MultiTransactor = + (UnimplementedTransactor, NotFoundTransactor, UnimplementedTransactor); - assert_eq!(MultiTransactor::deposit_asset(&(Null, 1).into(), &Null), Err(XcmError::AssetNotFound)); + assert_eq!( + MultiTransactor::deposit_asset(&(Null, 1).into(), &Null), + Err(XcmError::AssetNotFound) + ); } #[test] @@ -261,7 +289,10 @@ mod tests { fn unexpected_error_stops_iteration() { type MultiTransactor = (OverflowTransactor, SuccessfulTransactor); - assert_eq!(MultiTransactor::deposit_asset(&(Null, 1).into(), &Null), Err(XcmError::Overflow)); + assert_eq!( + MultiTransactor::deposit_asset(&(Null, 1).into(), &Null), + Err(XcmError::Overflow) + ); } #[test] diff --git a/xcm/xcm-executor/src/traits/weight.rs b/xcm/xcm-executor/src/traits/weight.rs index 1844f3b6c7f2..4e9c805edfbd 100644 --- a/xcm/xcm-executor/src/traits/weight.rs +++ b/xcm/xcm-executor/src/traits/weight.rs @@ -14,10 +14,10 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see <http://www.gnu.org/licenses/>. -use sp_std::result::Result; -use xcm::v0::{Xcm, MultiAsset, MultiLocation, Error}; -use frame_support::weights::Weight; use crate::Assets; +use frame_support::weights::Weight; +use sp_std::result::Result; +use xcm::v0::{Error, MultiAsset, MultiLocation, Xcm}; /// Determine the weight of an XCM message. pub trait WeightBounds<Call> { @@ -71,11 +71,15 @@ pub trait WeightTrader: Sized { /// purchased using `buy_weight`. /// /// Default implementation refunds nothing. - fn refund_weight(&mut self, _weight: Weight) -> Option<MultiAsset> { None } + fn refund_weight(&mut self, _weight: Weight) -> Option<MultiAsset> { + None + } } impl WeightTrader for () { - fn new() -> Self { () } + fn new() -> Self { + () + } fn buy_weight(&mut self, _: Weight, _: Assets) -> Result<Assets, Error> { Err(Error::Unimplemented) } From 9e2e009e4ba12f663b45f10563a2b80e7043d287 Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Tue, 3 Aug 2021 20:21:54 +0200 Subject: [PATCH 057/166] Move to XCM version 1 --- runtime/kusama/src/lib.rs | 2 +- runtime/parachains/src/dmp.rs | 2 +- runtime/parachains/src/ump.rs | 4 +- runtime/rococo/src/lib.rs | 2 +- runtime/westend/src/lib.rs | 2 +- xcm/pallet-xcm/src/lib.rs | 4 +- xcm/pallet-xcm/src/mock.rs | 2 +- xcm/src/lib.rs | 66 +++++++++++++++---- xcm/src/{v0 => v1}/junction.rs | 0 xcm/src/{v0 => v1}/mod.rs | 21 +----- xcm/src/{v0 => v1}/multiasset.rs | 0 .../multi_location.rs => v1/multilocation.rs} | 23 ++----- xcm/src/{v0 => v1}/order.rs | 0 xcm/src/{v0 => v1}/traits.rs | 2 +- xcm/xcm-builder/src/barriers.rs | 2 +- xcm/xcm-builder/src/currency_adapter.rs | 4 +- xcm/xcm-builder/src/filter_asset_location.rs | 2 +- xcm/xcm-builder/src/fungibles_adapter.rs | 2 +- xcm/xcm-builder/src/location_conversion.rs | 6 +- xcm/xcm-builder/src/matches_fungible.rs | 6 +- xcm/xcm-builder/src/mock.rs | 6 +- xcm/xcm-builder/src/origin_conversion.rs | 2 +- xcm/xcm-builder/src/tests.rs | 2 +- xcm/xcm-builder/src/weight.rs | 2 +- xcm/xcm-executor/src/assets.rs | 6 +- xcm/xcm-executor/src/config.rs | 2 +- xcm/xcm-executor/src/lib.rs | 2 +- xcm/xcm-executor/src/traits/conversion.rs | 4 +- .../src/traits/filter_asset_location.rs | 2 +- .../src/traits/matches_fungible.rs | 2 +- .../src/traits/matches_fungibles.rs | 2 +- xcm/xcm-executor/src/traits/on_response.rs | 2 +- xcm/xcm-executor/src/traits/should_execute.rs | 2 +- xcm/xcm-executor/src/traits/transact_asset.rs | 2 +- xcm/xcm-executor/src/traits/weight.rs | 2 +- xcm/xcm-simulator/example/src/lib.rs | 2 +- xcm/xcm-simulator/example/src/relay_chain.rs | 2 +- 37 files changed, 105 insertions(+), 91 deletions(-) rename xcm/src/{v0 => v1}/junction.rs (100%) rename xcm/src/{v0 => v1}/mod.rs (96%) rename xcm/src/{v0 => v1}/multiasset.rs (100%) rename xcm/src/{v0/multi_location.rs => v1/multilocation.rs} (98%) rename xcm/src/{v0 => v1}/order.rs (100%) rename xcm/src/{v0 => v1}/traits.rs (99%) diff --git a/runtime/kusama/src/lib.rs b/runtime/kusama/src/lib.rs index 705bd319efae..c2720c8deed1 100644 --- a/runtime/kusama/src/lib.rs +++ b/runtime/kusama/src/lib.rs @@ -75,7 +75,7 @@ use sp_staking::SessionIndex; use sp_version::NativeVersion; use sp_version::RuntimeVersion; use static_assertions::const_assert; -use xcm::v0::prelude::*; +use xcm::v1::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, BackingToPlurality, ChildParachainAsNative, ChildParachainConvertsVia, diff --git a/runtime/parachains/src/dmp.rs b/runtime/parachains/src/dmp.rs index 7982424800e5..1ff8fed4528d 100644 --- a/runtime/parachains/src/dmp.rs +++ b/runtime/parachains/src/dmp.rs @@ -22,7 +22,7 @@ use frame_support::pallet_prelude::*; use primitives::v1::{DownwardMessage, Hash, Id as ParaId, InboundDownwardMessage}; use sp_runtime::traits::{BlakeTwo256, Hash as HashT, SaturatedConversion}; use sp_std::{fmt, prelude::*}; -use xcm::v0::Error as XcmError; +use xcm::v1::Error as XcmError; pub use pallet::*; diff --git a/runtime/parachains/src/ump.rs b/runtime/parachains/src/ump.rs index c64123537b02..32e7edadaf79 100644 --- a/runtime/parachains/src/ump.rs +++ b/runtime/parachains/src/ump.rs @@ -27,7 +27,7 @@ use sp_std::{ marker::PhantomData, prelude::*, }; -use xcm::v0::Outcome; +use xcm::v1::Outcome; pub use pallet::*; @@ -78,7 +78,7 @@ pub type MessageId = [u8; 32]; /// and will be forwarded to the XCM Executor. pub struct XcmSink<XcmExecutor, Config>(PhantomData<(XcmExecutor, Config)>); -impl<XcmExecutor: xcm::v0::ExecuteXcm<C::Call>, C: Config> UmpSink for XcmSink<XcmExecutor, C> { +impl<XcmExecutor: xcm::v1::ExecuteXcm<C::Call>, C: Config> UmpSink for XcmSink<XcmExecutor, C> { fn process_upward_message( origin: ParaId, data: &[u8], diff --git a/runtime/rococo/src/lib.rs b/runtime/rococo/src/lib.rs index 4086d38ca814..88e6072003ff 100644 --- a/runtime/rococo/src/lib.rs +++ b/runtime/rococo/src/lib.rs @@ -80,7 +80,7 @@ use polkadot_parachain::primitives::Id as ParaId; use constants::{currency::*, fee::*, time::*}; use frame_support::traits::InstanceFilter; -use xcm::v0::prelude::*; +use xcm::v1::prelude::*; use xcm_builder::{ AccountId32Aliases, BackingToPlurality, ChildParachainAsNative, ChildParachainConvertsVia, ChildSystemParachainAsSuperuser, CurrencyAdapter as XcmCurrencyAdapter, FixedWeightBounds, diff --git a/runtime/westend/src/lib.rs b/runtime/westend/src/lib.rs index 12efa280771d..a578ff548afc 100644 --- a/runtime/westend/src/lib.rs +++ b/runtime/westend/src/lib.rs @@ -44,7 +44,7 @@ use runtime_parachains::{ session_info as parachains_session_info, shared as parachains_shared, ump as parachains_ump, }; -use xcm::v0::prelude::*; +use xcm::v1::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, ChildParachainAsNative, ChildParachainConvertsVia, ChildSystemParachainAsSuperuser, diff --git a/xcm/pallet-xcm/src/lib.rs b/xcm/pallet-xcm/src/lib.rs index 95d5c867e781..ece2590f4d53 100644 --- a/xcm/pallet-xcm/src/lib.rs +++ b/xcm/pallet-xcm/src/lib.rs @@ -27,7 +27,7 @@ use codec::{Decode, Encode}; use frame_support::traits::{Contains, EnsureOrigin, Filter, Get, OriginTrait}; use sp_runtime::{traits::BadOrigin, RuntimeDebug}; use sp_std::{boxed::Box, convert::TryInto, marker::PhantomData, prelude::*, vec}; -use xcm::v0::prelude::*; +use xcm::v1::prelude::*; use xcm_executor::traits::ConvertOrigin; use frame_support::PalletId; @@ -82,7 +82,7 @@ pub mod pallet { #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event<T: Config> { - Attempted(xcm::v0::Outcome), + Attempted(xcm::v1::Outcome), Sent(MultiLocation, MultiLocation, Xcm<()>), } diff --git a/xcm/pallet-xcm/src/mock.rs b/xcm/pallet-xcm/src/mock.rs index bd8375dec3b8..eb9136b4ed03 100644 --- a/xcm/pallet-xcm/src/mock.rs +++ b/xcm/pallet-xcm/src/mock.rs @@ -181,7 +181,7 @@ impl pallet_xcm::Config for Test { type SendXcmOrigin = xcm_builder::EnsureXcmOrigin<Origin, LocalOriginToLocation>; type XcmRouter = (TestSendXcmErrX8, TestSendXcm); type ExecuteXcmOrigin = xcm_builder::EnsureXcmOrigin<Origin, LocalOriginToLocation>; - type XcmExecuteFilter = All<(MultiLocation, xcm::v0::Xcm<Call>)>; + type XcmExecuteFilter = All<(MultiLocation, xcm::v1::Xcm<Call>)>; type XcmExecutor = XcmExecutor<XcmConfig>; type XcmTeleportFilter = All<(MultiLocation, Vec<MultiAsset>)>; type XcmReserveTransferFilter = All<(MultiLocation, Vec<MultiAsset>)>; diff --git a/xcm/src/lib.rs b/xcm/src/lib.rs index 4a275d61c4e3..705b4d34933b 100644 --- a/xcm/src/lib.rs +++ b/xcm/src/lib.rs @@ -23,25 +23,50 @@ #![no_std] extern crate alloc; +use core::{result::Result, convert::TryFrom}; use derivative::Derivative; -use parity_scale_codec::{Decode, Encode}; +use parity_scale_codec::{Decode, Encode, Input, Error as CodecError}; -pub mod v0; +pub mod v1; mod double_encoded; pub use double_encoded::DoubleEncoded; +pub enum Unsupported {} +impl Decode for Unsupported { + fn decode<I: Input>(_: &mut I) -> Result<Self, CodecError> { + Err("Not decodable".into()) + } +} + /// A single XCM message, together with its version code. #[derive(Derivative, Encode, Decode)] #[derivative(Clone(bound = ""), Eq(bound = ""), PartialEq(bound = ""), Debug(bound = ""))] #[codec(encode_bound())] #[codec(decode_bound())] pub enum VersionedXcm<Call> { - V0(v0::Xcm<Call>), + V0(Unsupported), + V1(v1::Xcm<Call>), +} + +impl<Call> From<v1::Xcm<Call>> for VersionedXcm<Call> { + fn from(x: v1::Xcm<Call>) -> Self { + VersionedXcm::V0(x) + } +} + +impl<Call> TryFrom<VersionedXcm<Call>> for v1::Xcm<Call> { + type Error = (); + fn try_from(x: VersionedXcm<Call>) -> Result<Self, ()> { + match x { + VersionedXcm::V1(x) => Ok(x), + _ => Err(()), + } + } } pub mod opaque { - pub mod v0 { + pub mod v1 { // Everything from v0 pub use crate::v0::*; // Then override with the opaque types in v0 @@ -55,26 +80,45 @@ pub mod opaque { /// A versioned multi-location, a relative location of a cross-consensus system identifier. #[derive(Clone, Eq, PartialEq, Encode, Decode, Debug)] pub enum VersionedMultiLocation { - V0(v0::MultiLocation), + V0(v1::MultiLocation), + V1(v1::MultiLocation), +} + +impl From<v1::MultiLocation> for VersionedMultiLocation { + fn from(x: v1::MultiLocation) -> Self { + VersionedMultiLocation::V1(x) + } +} + +impl TryFrom<VersionedMultiLocation> for v1::MultiLocation { + type Error = (); + fn try_from(x: VersionedMultiLocation) -> Result<Self, ()> { + match x { + VersionedMultiLocation::V0(x) => Ok(x), + VersionedMultiLocation::V1(x) => Ok(x), + } + } } /// A versioned multi-asset, an identifier for an asset within a consensus system. #[derive(Clone, Eq, PartialEq, Encode, Decode, Debug)] pub enum VersionedMultiAsset { - V0(v0::MultiAsset), + V0(Unsupported), + V1(v1::MultiAsset), } -impl From<v0::MultiAsset> for VersionedMultiAsset { - fn from(x: v0::MultiAsset) -> Self { - VersionedMultiAsset::V0(x) +impl From<v1::MultiAsset> for VersionedMultiAsset { + fn from(x: v1::MultiAsset) -> Self { + VersionedMultiAsset::V1(x) } } -impl core::convert::TryFrom<VersionedMultiAsset> for v0::MultiAsset { +impl core::convert::TryFrom<VersionedMultiAsset> for v1::MultiAsset { type Error = (); fn try_from(x: VersionedMultiAsset) -> core::result::Result<Self, ()> { match x { - VersionedMultiAsset::V0(x) => Ok(x), + VersionedMultiAsset::V1(x) => Ok(x), + _ => Err(()), } } } diff --git a/xcm/src/v0/junction.rs b/xcm/src/v1/junction.rs similarity index 100% rename from xcm/src/v0/junction.rs rename to xcm/src/v1/junction.rs diff --git a/xcm/src/v0/mod.rs b/xcm/src/v1/mod.rs similarity index 96% rename from xcm/src/v0/mod.rs rename to xcm/src/v1/mod.rs index 2bd568e60194..eb97acdeebde 100644 --- a/xcm/src/v0/mod.rs +++ b/xcm/src/v1/mod.rs @@ -23,13 +23,13 @@ use derivative::Derivative; use parity_scale_codec::{self, Decode, Encode}; mod junction; -mod multi_location; +mod multilocation; pub mod multiasset; mod order; mod traits; // the new multiasset. pub use junction::{BodyId, BodyPart, Junction, NetworkId}; -pub use multi_location::MultiLocation; +pub use multilocation::MultiLocation; pub use multiasset::{ AssetId, AssetInstance, Fungibility, MultiAsset, MultiAssetFilter, MultiAssets, WildFungibility, WildMultiAsset, @@ -45,7 +45,7 @@ pub mod prelude { Junction::*, NetworkId::{self, *}, }, - multi_location::MultiLocation::{self, *}, + multilocation::MultiLocation::{self, *}, multiasset::{ AssetId::{self, *}, AssetInstance::{self, *}, @@ -290,21 +290,6 @@ pub enum Xcm<Call> { RelayedFrom { who: MultiLocation, message: alloc::boxed::Box<Xcm<Call>> }, } -impl<Call> From<Xcm<Call>> for VersionedXcm<Call> { - fn from(x: Xcm<Call>) -> Self { - VersionedXcm::V0(x) - } -} - -impl<Call> TryFrom<VersionedXcm<Call>> for Xcm<Call> { - type Error = (); - fn try_from(x: VersionedXcm<Call>) -> result::Result<Self, ()> { - match x { - VersionedXcm::V0(x) => Ok(x), - } - } -} - impl<Call> Xcm<Call> { pub fn into<C>(self) -> Xcm<C> { Xcm::from(self) diff --git a/xcm/src/v0/multiasset.rs b/xcm/src/v1/multiasset.rs similarity index 100% rename from xcm/src/v0/multiasset.rs rename to xcm/src/v1/multiasset.rs diff --git a/xcm/src/v0/multi_location.rs b/xcm/src/v1/multilocation.rs similarity index 98% rename from xcm/src/v0/multi_location.rs rename to xcm/src/v1/multilocation.rs index e45df25a0ff6..af1b289702b2 100644 --- a/xcm/src/v0/multi_location.rs +++ b/xcm/src/v1/multilocation.rs @@ -460,7 +460,7 @@ impl MultiLocation { /// /// # Example /// ```rust - /// # use xcm::v0::{MultiLocation::*, Junction::*}; + /// # use xcm::v1::{MultiLocation::*, Junction::*}; /// # fn main() { /// let mut m = X3(Parent, PalletInstance(3), OnlyChild); /// assert_eq!(m.match_and_split(&X2(Parent, PalletInstance(3))), Some(&OnlyChild)); @@ -600,7 +600,7 @@ impl MultiLocation { /// /// # Example /// ```rust - /// # use xcm::v0::{MultiLocation::*, Junction::*}; + /// # use xcm::v1::{MultiLocation::*, Junction::*}; /// # fn main() { /// let mut m = X3(Parent, Parachain(21), OnlyChild); /// assert_eq!(m.append_with(X2(Parent, PalletInstance(3))), Ok(())); @@ -627,7 +627,7 @@ impl MultiLocation { /// /// # Example /// ```rust - /// # use xcm::v0::{MultiLocation::*, Junction::*, NetworkId::Any}; + /// # use xcm::v1::{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(())); @@ -684,7 +684,7 @@ impl MultiLocation { /// /// # Example /// ```rust - /// # use xcm::v0::{MultiLocation::*, Junction::*, NetworkId::Any}; + /// # use xcm::v1::{MultiLocation::*, Junction::*, NetworkId::Any}; /// # fn main() { /// let parent = X1(Parent); /// assert_eq!(parent.is_interior(), false); @@ -697,21 +697,6 @@ impl MultiLocation { } } -impl From<MultiLocation> for VersionedMultiLocation { - fn from(x: MultiLocation) -> Self { - VersionedMultiLocation::V0(x) - } -} - -impl TryFrom<VersionedMultiLocation> for MultiLocation { - type Error = (); - fn try_from(x: VersionedMultiLocation) -> result::Result<Self, ()> { - match x { - VersionedMultiLocation::V0(x) => Ok(x), - } - } -} - #[cfg(test)] mod tests { use super::MultiLocation::*; diff --git a/xcm/src/v0/order.rs b/xcm/src/v1/order.rs similarity index 100% rename from xcm/src/v0/order.rs rename to xcm/src/v1/order.rs diff --git a/xcm/src/v0/traits.rs b/xcm/src/v1/traits.rs similarity index 99% rename from xcm/src/v0/traits.rs rename to xcm/src/v1/traits.rs index d6ce316726c8..fc1c3ce88b57 100644 --- a/xcm/src/v0/traits.rs +++ b/xcm/src/v1/traits.rs @@ -184,7 +184,7 @@ impl<C> ExecuteXcm<C> for () { /// /// # Example /// ```rust -/// # use xcm::v0::{MultiLocation, Xcm, Junction, Error, OriginKind, SendXcm, Result}; +/// # use xcm::v1::{MultiLocation, Xcm, Junction, Error, OriginKind, SendXcm, Result}; /// # use parity_scale_codec::Encode; /// /// /// A sender that only passes the message through and does nothing. diff --git a/xcm/xcm-builder/src/barriers.rs b/xcm/xcm-builder/src/barriers.rs index 2d870d7525c2..f253be18026f 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::v0::{Junction, MultiLocation, Order, Xcm}; +use xcm::v1::{Junction, MultiLocation, Order, Xcm}; use xcm_executor::traits::{OnResponse, ShouldExecute}; /// Execution barrier that just takes `shallow_weight` from `weight_credit`. diff --git a/xcm/xcm-builder/src/currency_adapter.rs b/xcm/xcm-builder/src/currency_adapter.rs index fcbaa93c5998..ebbdf794209f 100644 --- a/xcm/xcm-builder/src/currency_adapter.rs +++ b/xcm/xcm-builder/src/currency_adapter.rs @@ -19,7 +19,7 @@ use frame_support::traits::{ExistenceRequirement::AllowDeath, Get, WithdrawReasons}; use sp_runtime::traits::{CheckedSub, SaturatedConversion}; use sp_std::{convert::TryInto, marker::PhantomData, result}; -use xcm::v0::{Error as XcmError, MultiAsset, MultiLocation, Result}; +use xcm::v1::{Error as XcmError, MultiAsset, MultiLocation, Result}; use xcm_executor::{ traits::{Convert, MatchesFungible, TransactAsset}, Assets, @@ -53,7 +53,7 @@ impl From<Error> for XcmError { /// # Example /// ``` /// use frame_support::parameter_types; -/// use xcm::v0::{MultiLocation, Junction}; +/// use xcm::v1::{MultiLocation, Junction}; /// use xcm_builder::{ParentIsDefault, CurrencyAdapter, IsConcrete}; /// /// /// Our chain's account id. diff --git a/xcm/xcm-builder/src/filter_asset_location.rs b/xcm/xcm-builder/src/filter_asset_location.rs index cb2fa80be734..99a0e5e8f7f6 100644 --- a/xcm/xcm-builder/src/filter_asset_location.rs +++ b/xcm/xcm-builder/src/filter_asset_location.rs @@ -18,7 +18,7 @@ use frame_support::traits::Get; use sp_std::marker::PhantomData; -use xcm::v0::{AssetId::Concrete, MultiAsset, MultiAssetFilter, MultiLocation}; +use xcm::v1::{AssetId::Concrete, MultiAsset, MultiAssetFilter, MultiLocation}; use xcm_executor::traits::FilterAssetLocation; /// Accepts an asset iff it is a native asset. diff --git a/xcm/xcm-builder/src/fungibles_adapter.rs b/xcm/xcm-builder/src/fungibles_adapter.rs index d81ddd5a575d..048f3d8d3a52 100644 --- a/xcm/xcm-builder/src/fungibles_adapter.rs +++ b/xcm/xcm-builder/src/fungibles_adapter.rs @@ -18,7 +18,7 @@ use frame_support::traits::{tokens::fungibles, Contains, Get}; use sp_std::{borrow::Borrow, marker::PhantomData, prelude::*, result}; -use xcm::v0::{ +use xcm::v1::{ AssetId::{Abstract, Concrete}, Error as XcmError, Fungibility::Fungible, diff --git a/xcm/xcm-builder/src/location_conversion.rs b/xcm/xcm-builder/src/location_conversion.rs index 23612629946e..cbaf0b93063e 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::v0::{Junction, MultiLocation, NetworkId}; +use xcm::v1::{Junction, MultiLocation, NetworkId}; use xcm_executor::traits::{Convert, InvertLocation}; pub struct Account32Hash<Network, AccountId>(PhantomData<(Network, AccountId)>); @@ -155,7 +155,7 @@ impl<Network: Get<NetworkId>, AccountId: From<[u8; 20]> + Into<[u8; 20]> + Clone /// ``` /// ```rust /// # use frame_support::parameter_types; -/// # use xcm::v0::{MultiLocation::{self, *}, Junction::*, NetworkId::Any}; +/// # use xcm::v1::{MultiLocation::{self, *}, Junction::*, NetworkId::Any}; /// # use xcm_builder::LocationInverter; /// # use xcm_executor::traits::InvertLocation; /// # fn main() { @@ -200,7 +200,7 @@ mod tests { use super::*; use frame_support::parameter_types; - use xcm::v0::{Junction::*, MultiLocation::*, NetworkId::Any}; + use xcm::v1::{Junction::*, MultiLocation::*, NetworkId::Any}; fn account20() -> Junction { AccountKey20 { network: Any, key: Default::default() } diff --git a/xcm/xcm-builder/src/matches_fungible.rs b/xcm/xcm-builder/src/matches_fungible.rs index 0b635f3c1cb8..8e61bd2f8439 100644 --- a/xcm/xcm-builder/src/matches_fungible.rs +++ b/xcm/xcm-builder/src/matches_fungible.rs @@ -19,7 +19,7 @@ use frame_support::traits::Get; use sp_runtime::traits::CheckedConversion; use sp_std::{convert::TryFrom, marker::PhantomData}; -use xcm::v0::{ +use xcm::v1::{ AssetId::{Abstract, Concrete}, Fungibility::Fungible, MultiAsset, MultiLocation, @@ -32,7 +32,7 @@ use xcm_executor::traits::MatchesFungible; /// # Example /// /// ``` -/// use xcm::v0::prelude::*; +/// use xcm::v1::prelude::*; /// use xcm_builder::IsConcrete; /// use xcm_executor::traits::MatchesFungible; /// @@ -62,7 +62,7 @@ impl<T: Get<MultiLocation>, B: TryFrom<u128>> MatchesFungible<B> for IsConcrete< /// # Example /// /// ``` -/// use xcm::v0::prelude::*; +/// use xcm::v1::prelude::*; /// use xcm_builder::IsAbstract; /// use xcm_executor::traits::MatchesFungible; /// diff --git a/xcm/xcm-builder/src/mock.rs b/xcm/xcm-builder/src/mock.rs index 6adc5b478343..c8d6036577e7 100644 --- a/xcm/xcm-builder/src/mock.rs +++ b/xcm/xcm-builder/src/mock.rs @@ -34,7 +34,7 @@ pub use sp_std::{ fmt::Debug, marker::PhantomData, }; -pub use xcm::v0::prelude::*; +pub use xcm::v1::prelude::*; pub use xcm_executor::{ traits::{ConvertOrigin, FilterAssetLocation, InvertLocation, OnResponse, TransactAsset}, Assets, Config, @@ -203,7 +203,7 @@ impl FilterAssetLocation for TestIsTeleporter { } } -use xcm::v0::Response; +use xcm::v1::Response; pub enum ResponseSlot { Expecting(MultiLocation), Received(Response), @@ -219,7 +219,7 @@ impl OnResponse for TestResponseHandler { _ => false, }) } - fn on_response(_origin: MultiLocation, query_id: u64, response: xcm::v0::Response) -> Weight { + fn on_response(_origin: MultiLocation, query_id: u64, response: xcm::v1::Response) -> Weight { QUERIES.with(|q| { q.borrow_mut().entry(query_id).and_modify(|v| { if matches!(*v, ResponseSlot::Expecting(..)) { diff --git a/xcm/xcm-builder/src/origin_conversion.rs b/xcm/xcm-builder/src/origin_conversion.rs index 2a1956ca79de..2cc343694fa9 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::v0::{BodyId, BodyPart, Junction, MultiLocation, NetworkId, OriginKind}; +use xcm::v1::{BodyId, BodyPart, Junction, 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`. diff --git a/xcm/xcm-builder/src/tests.rs b/xcm/xcm-builder/src/tests.rs index 5c7465440b29..93c87ce5dad5 100644 --- a/xcm/xcm-builder/src/tests.rs +++ b/xcm/xcm-builder/src/tests.rs @@ -15,7 +15,7 @@ // along with Polkadot. If not, see <http://www.gnu.org/licenses/>. use super::{mock::*, *}; -use xcm::v0::prelude::*; +use xcm::v1::prelude::*; use xcm_executor::{traits::*, Config, XcmExecutor}; #[test] diff --git a/xcm/xcm-builder/src/weight.rs b/xcm/xcm-builder/src/weight.rs index faee6a08f23c..87b7c2f6b488 100644 --- a/xcm/xcm-builder/src/weight.rs +++ b/xcm/xcm-builder/src/weight.rs @@ -21,7 +21,7 @@ use frame_support::{ use parity_scale_codec::Decode; use sp_runtime::traits::{SaturatedConversion, Saturating, Zero}; use sp_std::{convert::TryInto, marker::PhantomData, result::Result}; -use xcm::v0::{AssetId, AssetId::Concrete, Error, MultiAsset, MultiLocation, Order, Xcm}; +use xcm::v1::{AssetId, AssetId::Concrete, Error, MultiAsset, MultiLocation, Order, Xcm}; use xcm_executor::{ traits::{WeightBounds, WeightTrader}, Assets, diff --git a/xcm/xcm-executor/src/assets.rs b/xcm/xcm-executor/src/assets.rs index a7e48662e719..5270a30d44d2 100644 --- a/xcm/xcm-executor/src/assets.rs +++ b/xcm/xcm-executor/src/assets.rs @@ -20,7 +20,7 @@ use sp_std::{ mem, prelude::*, }; -use xcm::v0::{ +use xcm::v1::{ AssetId, AssetInstance, Fungibility::{Fungible, NonFungible}, MultiAsset, MultiAssetFilter, MultiAssets, MultiLocation, @@ -338,7 +338,7 @@ impl Assets { /// /// ``` /// use xcm_executor::Assets; - /// use xcm::v0::prelude::*; + /// use xcm::v1::prelude::*; /// let assets_i_have: Assets = vec![ (Null, 100).into(), (vec![0], 100).into() ].into(); /// let assets_they_want: MultiAssetFilter = vec![ (Null, 200).into(), (vec![0], 50).into() [.into(); /// @@ -387,7 +387,7 @@ impl Assets { #[cfg(test)] mod tests { use super::*; - use xcm::v0::prelude::*; + use xcm::v1::prelude::*; use MultiLocation::Null; #[allow(non_snake_case)] fn AF(id: u8, amount: u128) -> MultiAsset { diff --git a/xcm/xcm-executor/src/config.rs b/xcm/xcm-executor/src/config.rs index ff39be56ef5e..1a38fb44ea50 100644 --- a/xcm/xcm-executor/src/config.rs +++ b/xcm/xcm-executor/src/config.rs @@ -22,7 +22,7 @@ use frame_support::{ dispatch::{Dispatchable, Parameter}, weights::{GetDispatchInfo, PostDispatchInfo}, }; -use xcm::v0::SendXcm; +use xcm::v1::SendXcm; /// The trait to parameterize the `XcmExecutor`. pub trait Config { diff --git a/xcm/xcm-executor/src/lib.rs b/xcm/xcm-executor/src/lib.rs index d6dcbd1f93fd..491558dbdb28 100644 --- a/xcm/xcm-executor/src/lib.rs +++ b/xcm/xcm-executor/src/lib.rs @@ -22,7 +22,7 @@ use frame_support::{ weights::GetDispatchInfo, }; use sp_std::{marker::PhantomData, prelude::*}; -use xcm::v0::{ +use xcm::v1::{ Error as XcmError, ExecuteXcm, MultiAssets, MultiLocation, Order, Outcome, Response, SendXcm, Xcm, }; diff --git a/xcm/xcm-executor/src/traits/conversion.rs b/xcm/xcm-executor/src/traits/conversion.rs index 49f5db698982..df99a05d0064 100644 --- a/xcm/xcm-executor/src/traits/conversion.rs +++ b/xcm/xcm-executor/src/traits/conversion.rs @@ -16,7 +16,7 @@ use parity_scale_codec::{Decode, Encode}; use sp_std::{borrow::Borrow, convert::TryFrom, prelude::*, result::Result}; -use xcm::v0::{MultiLocation, OriginKind}; +use xcm::v1::{MultiLocation, OriginKind}; /// Generic third-party conversion trait. Use this when you don't want to force the user to use default /// implementations of `From` and `Into` for the types you wish to convert between. @@ -139,7 +139,7 @@ impl<T: Clone + Encode + Decode> Convert<Vec<u8>, T> for Decoded { /// which is passed to the next convert item. /// /// ```rust -/// # use xcm::v0::{MultiLocation, Junction, OriginKind}; +/// # use xcm::v1::{MultiLocation, Junction, OriginKind}; /// # use xcm_executor::traits::ConvertOrigin; /// // A convertor that will bump the para id and pass it to the next one. /// struct BumpParaId; diff --git a/xcm/xcm-executor/src/traits/filter_asset_location.rs b/xcm/xcm-executor/src/traits/filter_asset_location.rs index 8b1a7bd1d1dc..a63af84e167c 100644 --- a/xcm/xcm-executor/src/traits/filter_asset_location.rs +++ b/xcm/xcm-executor/src/traits/filter_asset_location.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see <http://www.gnu.org/licenses/>. -use xcm::v0::{MultiAsset, MultiLocation}; +use xcm::v1::{MultiAsset, MultiLocation}; /// Filters assets/location pairs. /// diff --git a/xcm/xcm-executor/src/traits/matches_fungible.rs b/xcm/xcm-executor/src/traits/matches_fungible.rs index 6634d16d0243..ff466af5b21c 100644 --- a/xcm/xcm-executor/src/traits/matches_fungible.rs +++ b/xcm/xcm-executor/src/traits/matches_fungible.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see <http://www.gnu.org/licenses/>. -use xcm::v0::MultiAsset; +use xcm::v1::MultiAsset; pub trait MatchesFungible<Balance> { fn matches_fungible(a: &MultiAsset) -> Option<Balance>; diff --git a/xcm/xcm-executor/src/traits/matches_fungibles.rs b/xcm/xcm-executor/src/traits/matches_fungibles.rs index c1722d000f02..2499eae27531 100644 --- a/xcm/xcm-executor/src/traits/matches_fungibles.rs +++ b/xcm/xcm-executor/src/traits/matches_fungibles.rs @@ -15,7 +15,7 @@ // along with Polkadot. If not, see <http://www.gnu.org/licenses/>. use sp_std::result; -use xcm::v0::{Error as XcmError, MultiAsset}; +use xcm::v1::{Error as XcmError, MultiAsset}; /// Errors associated with [`MatchesFungibles`] operation. pub enum Error { diff --git a/xcm/xcm-executor/src/traits/on_response.rs b/xcm/xcm-executor/src/traits/on_response.rs index 134891b4b704..801aa016d478 100644 --- a/xcm/xcm-executor/src/traits/on_response.rs +++ b/xcm/xcm-executor/src/traits/on_response.rs @@ -15,7 +15,7 @@ // along with Polkadot. If not, see <http://www.gnu.org/licenses/>. use frame_support::weights::Weight; -use xcm::v0::{MultiLocation, Response}; +use xcm::v1::{MultiLocation, Response}; /// Define what needs to be done upon receiving a query response. pub trait OnResponse { diff --git a/xcm/xcm-executor/src/traits/should_execute.rs b/xcm/xcm-executor/src/traits/should_execute.rs index ed92866146c1..a8d9ad1ca79a 100644 --- a/xcm/xcm-executor/src/traits/should_execute.rs +++ b/xcm/xcm-executor/src/traits/should_execute.rs @@ -16,7 +16,7 @@ use frame_support::weights::Weight; use sp_std::result::Result; -use xcm::v0::{MultiLocation, Xcm}; +use xcm::v1::{MultiLocation, Xcm}; /// Trait to determine whether the execution engine should actually execute a given XCM. /// diff --git a/xcm/xcm-executor/src/traits/transact_asset.rs b/xcm/xcm-executor/src/traits/transact_asset.rs index d6114efbe09c..60fb0508c676 100644 --- a/xcm/xcm-executor/src/traits/transact_asset.rs +++ b/xcm/xcm-executor/src/traits/transact_asset.rs @@ -16,7 +16,7 @@ use crate::Assets; use sp_std::result::Result; -use xcm::v0::{Error as XcmError, MultiAsset, MultiLocation, Result as XcmResult}; +use xcm::v1::{Error as XcmError, MultiAsset, MultiLocation, Result as XcmResult}; /// Facility for asset transacting. /// diff --git a/xcm/xcm-executor/src/traits/weight.rs b/xcm/xcm-executor/src/traits/weight.rs index 4e9c805edfbd..c32ec682857c 100644 --- a/xcm/xcm-executor/src/traits/weight.rs +++ b/xcm/xcm-executor/src/traits/weight.rs @@ -17,7 +17,7 @@ use crate::Assets; use frame_support::weights::Weight; use sp_std::result::Result; -use xcm::v0::{Error, MultiAsset, MultiLocation, Xcm}; +use xcm::v1::{Error, MultiAsset, MultiLocation, Xcm}; /// Determine the weight of an XCM message. pub trait WeightBounds<Call> { diff --git a/xcm/xcm-simulator/example/src/lib.rs b/xcm/xcm-simulator/example/src/lib.rs index f318409bf187..00c1f4109421 100644 --- a/xcm/xcm-simulator/example/src/lib.rs +++ b/xcm/xcm-simulator/example/src/lib.rs @@ -100,7 +100,7 @@ mod tests { use codec::Encode; use frame_support::assert_ok; - use xcm::v0::{ + use xcm::v1::{ Junction::{self, Parachain, Parent}, MultiAsset::*, MultiLocation::*, diff --git a/xcm/xcm-simulator/example/src/relay_chain.rs b/xcm/xcm-simulator/example/src/relay_chain.rs index c69f20d05eaf..cd84249ad614 100644 --- a/xcm/xcm-simulator/example/src/relay_chain.rs +++ b/xcm/xcm-simulator/example/src/relay_chain.rs @@ -26,7 +26,7 @@ use sp_runtime::{testing::Header, traits::IdentityLookup, AccountId32}; use polkadot_parachain::primitives::Id as ParaId; use polkadot_runtime_parachains::{configuration, origin, shared, ump}; -use xcm::v0::{MultiAsset, MultiLocation, NetworkId}; +use xcm::v1::{MultiAsset, MultiLocation, NetworkId}; use xcm_builder::{ AccountId32Aliases, AllowUnpaidExecutionFrom, ChildParachainAsNative, ChildParachainConvertsVia, ChildSystemParachainAsSuperuser, From 00ca37b154ed1abefc9aaca907e5e08c0bb0a7e2 Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Tue, 3 Aug 2021 22:38:08 +0200 Subject: [PATCH 058/166] Spelling --- xcm/xcm-simulator/example/src/parachain.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xcm/xcm-simulator/example/src/parachain.rs b/xcm/xcm-simulator/example/src/parachain.rs index f4ad471ff697..781b0a8e6a45 100644 --- a/xcm/xcm-simulator/example/src/parachain.rs +++ b/xcm/xcm-simulator/example/src/parachain.rs @@ -187,7 +187,7 @@ pub mod mock_msg_queue { #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event<T: Config> { // XCMP - /// Some XCM was executed ok. + /// Some XCM was executed OK. Success(Option<T::Hash>), /// Some XCM failed. Fail(Option<T::Hash>, XcmError), From 768c96ae581e41a588e450a010ecfaeac88db372 Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Tue, 3 Aug 2021 22:46:24 +0200 Subject: [PATCH 059/166] warnings --- xcm/src/lib.rs | 8 +++++--- xcm/src/v1/mod.rs | 4 ++-- xcm/src/v1/multilocation.rs | 3 +-- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/xcm/src/lib.rs b/xcm/src/lib.rs index 705b4d34933b..c3b9a06ba141 100644 --- a/xcm/src/lib.rs +++ b/xcm/src/lib.rs @@ -32,7 +32,9 @@ pub mod v1; mod double_encoded; pub use double_encoded::DoubleEncoded; +#[derive(Clone, Eq, PartialEq, Debug)] pub enum Unsupported {} +impl Encode for Unsupported {} impl Decode for Unsupported { fn decode<I: Input>(_: &mut I) -> Result<Self, CodecError> { Err("Not decodable".into()) @@ -51,7 +53,7 @@ pub enum VersionedXcm<Call> { impl<Call> From<v1::Xcm<Call>> for VersionedXcm<Call> { fn from(x: v1::Xcm<Call>) -> Self { - VersionedXcm::V0(x) + VersionedXcm::V1(x) } } @@ -68,9 +70,9 @@ impl<Call> TryFrom<VersionedXcm<Call>> for v1::Xcm<Call> { pub mod opaque { pub mod v1 { // Everything from v0 - pub use crate::v0::*; + pub use crate::v1::*; // Then override with the opaque types in v0 - pub use crate::v0::opaque::{Order, Xcm}; + pub use crate::v1::opaque::{Order, Xcm}; } /// The basic `VersionedXcm` type which just uses the `Vec<u8>` as an encoded call. diff --git a/xcm/src/v1/mod.rs b/xcm/src/v1/mod.rs index eb97acdeebde..38e7cf2c60ce 100644 --- a/xcm/src/v1/mod.rs +++ b/xcm/src/v1/mod.rs @@ -16,9 +16,9 @@ //! Version 0 of the Cross-Consensus Message format data structures. -use crate::{DoubleEncoded, VersionedXcm}; +use crate::DoubleEncoded; use alloc::vec::Vec; -use core::{convert::TryFrom, fmt::Debug, result}; +use core::fmt::Debug; use derivative::Derivative; use parity_scale_codec::{self, Decode, Encode}; diff --git a/xcm/src/v1/multilocation.rs b/xcm/src/v1/multilocation.rs index af1b289702b2..b3a7209404cc 100644 --- a/xcm/src/v1/multilocation.rs +++ b/xcm/src/v1/multilocation.rs @@ -16,10 +16,9 @@ //! Cross-Consensus Message format data structures. -use core::{convert::TryFrom, mem, result}; +use core::{mem, result}; use super::Junction; -use crate::VersionedMultiLocation; use parity_scale_codec::{self, Decode, Encode}; /// A relative path between state-bearing consensus systems. From 2936419d834f6159ac3c68a62ed3bc5fb7ea9694 Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Tue, 3 Aug 2021 22:52:13 +0200 Subject: [PATCH 060/166] Replace some more v0->v1s --- runtime/common/src/xcm_sender.rs | 2 +- runtime/parachains/src/hrmp.rs | 6 +++--- runtime/parachains/src/ump.rs | 2 +- runtime/westend/src/constants.rs | 2 +- xcm/pallet-xcm/src/mock.rs | 6 +++--- xcm/pallet-xcm/src/tests.rs | 4 ++-- xcm/src/v1/multilocation.rs | 2 +- xcm/xcm-simulator/example/src/parachain.rs | 2 +- xcm/xcm-simulator/src/lib.rs | 2 +- 9 files changed, 14 insertions(+), 14 deletions(-) diff --git a/runtime/common/src/xcm_sender.rs b/runtime/common/src/xcm_sender.rs index 151c649a8c4c..819f9b0b0617 100644 --- a/runtime/common/src/xcm_sender.rs +++ b/runtime/common/src/xcm_sender.rs @@ -20,7 +20,7 @@ use parity_scale_codec::Encode; use runtime_parachains::{configuration, dmp}; use sp_std::marker::PhantomData; use xcm::opaque::{ - v0::{Error, Junction, MultiLocation, Result, SendXcm, Xcm}, + v1::{Error, Junction, MultiLocation, Result, SendXcm, Xcm}, VersionedXcm, }; diff --git a/runtime/parachains/src/hrmp.rs b/runtime/parachains/src/hrmp.rs index 906c9d77d39d..901be0ae4b3b 100644 --- a/runtime/parachains/src/hrmp.rs +++ b/runtime/parachains/src/hrmp.rs @@ -1007,7 +1007,7 @@ impl<T: Config> Pallet<T> { let notification_bytes = { use parity_scale_codec::Encode as _; - use xcm::opaque::{v0::Xcm, VersionedXcm}; + use xcm::opaque::{v1::Xcm, VersionedXcm}; VersionedXcm::from(Xcm::HrmpNewChannelOpenRequest { sender: u32::from(origin), @@ -1066,7 +1066,7 @@ impl<T: Config> Pallet<T> { let notification_bytes = { use parity_scale_codec::Encode as _; - use xcm::opaque::{v0::Xcm, VersionedXcm}; + use xcm::opaque::{v1::Xcm, VersionedXcm}; VersionedXcm::from(Xcm::HrmpChannelAccepted { recipient: u32::from(origin) }).encode() }; @@ -1106,7 +1106,7 @@ impl<T: Config> Pallet<T> { let config = <configuration::Pallet<T>>::config(); let notification_bytes = { use parity_scale_codec::Encode as _; - use xcm::opaque::{v0::Xcm, VersionedXcm}; + use xcm::opaque::{v1::Xcm, VersionedXcm}; VersionedXcm::from(Xcm::HrmpChannelClosing { initiator: u32::from(origin), diff --git a/runtime/parachains/src/ump.rs b/runtime/parachains/src/ump.rs index 32e7edadaf79..b1a39405a468 100644 --- a/runtime/parachains/src/ump.rs +++ b/runtime/parachains/src/ump.rs @@ -85,7 +85,7 @@ impl<XcmExecutor: xcm::v1::ExecuteXcm<C::Call>, C: Config> UmpSink for XcmSink<X max_weight: Weight, ) -> Result<Weight, (MessageId, Weight)> { use xcm::{ - v0::{Error as XcmError, Junction, MultiLocation, Xcm}, + v1::{Error as XcmError, Junction, MultiLocation, Xcm}, VersionedXcm, }; diff --git a/runtime/westend/src/constants.rs b/runtime/westend/src/constants.rs index 77bdd954c03b..a6eaba9e2063 100644 --- a/runtime/westend/src/constants.rs +++ b/runtime/westend/src/constants.rs @@ -49,7 +49,7 @@ pub mod fee { use frame_support::weights::{ WeightToFeeCoefficient, WeightToFeeCoefficients, WeightToFeePolynomial, }; - use primitives::v0::Balance; + use primitives::v1::Balance; use runtime_common::ExtrinsicBaseWeight; use smallvec::smallvec; pub use sp_runtime::Perbill; diff --git a/xcm/pallet-xcm/src/mock.rs b/xcm/pallet-xcm/src/mock.rs index eb9136b4ed03..e919be21a21d 100644 --- a/xcm/pallet-xcm/src/mock.rs +++ b/xcm/pallet-xcm/src/mock.rs @@ -25,8 +25,8 @@ use sp_core::H256; use sp_runtime::{testing::Header, traits::IdentityLookup, AccountId32}; pub use sp_std::{cell::RefCell, fmt::Debug, marker::PhantomData}; use xcm::{ - opaque::v0::{Error as XcmError, MultiAsset, Result as XcmResult, SendXcm, Xcm}, - v0::{MultiLocation, NetworkId, Order}, + opaque::v1::{Error as XcmError, MultiAsset, Result as XcmResult, SendXcm, Xcm}, + v1::{MultiLocation, NetworkId, Order}, }; use xcm_builder::{ AccountId32Aliases, AllowTopLevelPaidExecutionFrom, ChildParachainAsNative, @@ -195,7 +195,7 @@ pub(crate) fn last_event() -> Event { } pub(crate) fn buy_execution<C>(debt: Weight) -> Order<C> { - use xcm::opaque::v0::prelude::*; + use xcm::opaque::v1::prelude::*; Order::BuyExecution { fees: All, weight: 0, debt, halt_on_error: false, xcm: vec![] } } diff --git a/xcm/pallet-xcm/src/tests.rs b/xcm/pallet-xcm/src/tests.rs index f0727e619bd2..2fc2de28ef64 100644 --- a/xcm/pallet-xcm/src/tests.rs +++ b/xcm/pallet-xcm/src/tests.rs @@ -18,8 +18,8 @@ use crate::mock::*; use frame_support::{assert_noop, assert_ok, traits::Currency}; use polkadot_parachain::primitives::{AccountIdConversion, Id as ParaId}; use xcm::{ - opaque::v0::prelude::*, - v0::{Junction, Xcm}, + opaque::v1::prelude::*, + v1::{Junction, Xcm}, }; const ALICE: AccountId = AccountId::new([0u8; 32]); diff --git a/xcm/src/v1/multilocation.rs b/xcm/src/v1/multilocation.rs index b3a7209404cc..20a9153b570a 100644 --- a/xcm/src/v1/multilocation.rs +++ b/xcm/src/v1/multilocation.rs @@ -699,7 +699,7 @@ impl MultiLocation { #[cfg(test)] mod tests { use super::MultiLocation::*; - use crate::opaque::v0::{Junction::*, NetworkId::Any}; + use crate::opaque::v1::{Junction::*, NetworkId::Any}; #[test] fn match_and_split_works() { diff --git a/xcm/xcm-simulator/example/src/parachain.rs b/xcm/xcm-simulator/example/src/parachain.rs index 781b0a8e6a45..993aee5de0ca 100644 --- a/xcm/xcm-simulator/example/src/parachain.rs +++ b/xcm/xcm-simulator/example/src/parachain.rs @@ -36,7 +36,7 @@ use polkadot_parachain::primitives::{ DmpMessageHandler, Id as ParaId, Sibling, XcmpMessageFormat, XcmpMessageHandler, }; use xcm::{ - v0::{ + v1::{ Error as XcmError, ExecuteXcm, Junction::{Parachain, Parent}, MultiAsset, diff --git a/xcm/xcm-simulator/src/lib.rs b/xcm/xcm-simulator/src/lib.rs index d68072858e80..f075c7e3d9fb 100644 --- a/xcm/xcm-simulator/src/lib.rs +++ b/xcm/xcm-simulator/src/lib.rs @@ -32,7 +32,7 @@ pub use polkadot_runtime_parachains::{ dmp, ump::{self, MessageId, UmpSink, XcmSink}, }; -pub use xcm::{v0::prelude::*, VersionedXcm}; +pub use xcm::{v1::prelude::*, VersionedXcm}; pub use xcm_executor::XcmExecutor; pub trait TestExt { From 015fff2e1ba83d42f2897e2da39ff4985facffbe Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Tue, 3 Aug 2021 23:00:39 +0200 Subject: [PATCH 061/166] warnings --- xcm/xcm-simulator/example/src/parachain.rs | 17 ++++------------- xcm/xcm-simulator/example/src/relay_chain.rs | 8 ++++---- 2 files changed, 8 insertions(+), 17 deletions(-) diff --git a/xcm/xcm-simulator/example/src/parachain.rs b/xcm/xcm-simulator/example/src/parachain.rs index 993aee5de0ca..4e870abb0315 100644 --- a/xcm/xcm-simulator/example/src/parachain.rs +++ b/xcm/xcm-simulator/example/src/parachain.rs @@ -35,19 +35,10 @@ use polkadot_core_primitives::BlockNumber as RelayBlockNumber; use polkadot_parachain::primitives::{ DmpMessageHandler, Id as ParaId, Sibling, XcmpMessageFormat, XcmpMessageHandler, }; -use xcm::{ - v1::{ - Error as XcmError, ExecuteXcm, - Junction::{Parachain, Parent}, - MultiAsset, - MultiLocation::{self, X1}, - NetworkId, Outcome, Xcm, - }, - VersionedXcm, -}; +use xcm::{v1::prelude::*, VersionedXcm}; use xcm_builder::{ AccountId32Aliases, AllowUnpaidExecutionFrom, CurrencyAdapter as XcmCurrencyAdapter, - EnsureXcmOrigin, FixedRateOfConcreteFungible, FixedWeightBounds, IsConcrete, LocationInverter, + EnsureXcmOrigin, FixedRateOfFungible, FixedWeightBounds, IsConcrete, LocationInverter, NativeAsset, ParentIsDefault, SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, }; @@ -129,7 +120,7 @@ pub type XcmOriginToCallOrigin = ( parameter_types! { pub const UnitWeightCost: Weight = 1; - pub KsmPerSecond: (MultiLocation, u128) = (X1(Parent), 1); + pub KsmPerSecond: (AssetId, u128) = (Concrete(X1(Parent)), 1); } pub type LocalAssetTransactor = @@ -149,7 +140,7 @@ impl Config for XcmConfig { type LocationInverter = LocationInverter<Ancestry>; type Barrier = Barrier; type Weigher = FixedWeightBounds<UnitWeightCost, Call>; - type Trader = FixedRateOfConcreteFungible<KsmPerSecond, ()>; + type Trader = FixedRateOfFungible<KsmPerSecond, ()>; type ResponseHandler = (); } diff --git a/xcm/xcm-simulator/example/src/relay_chain.rs b/xcm/xcm-simulator/example/src/relay_chain.rs index cd84249ad614..b342ebaf7fff 100644 --- a/xcm/xcm-simulator/example/src/relay_chain.rs +++ b/xcm/xcm-simulator/example/src/relay_chain.rs @@ -26,11 +26,11 @@ use sp_runtime::{testing::Header, traits::IdentityLookup, AccountId32}; use polkadot_parachain::primitives::Id as ParaId; use polkadot_runtime_parachains::{configuration, origin, shared, ump}; -use xcm::v1::{MultiAsset, MultiLocation, NetworkId}; +use xcm::v1::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowUnpaidExecutionFrom, ChildParachainAsNative, ChildParachainConvertsVia, ChildSystemParachainAsSuperuser, - CurrencyAdapter as XcmCurrencyAdapter, FixedRateOfConcreteFungible, FixedWeightBounds, + CurrencyAdapter as XcmCurrencyAdapter, FixedRateOfFungible, FixedWeightBounds, IsConcrete, LocationInverter, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, }; @@ -114,7 +114,7 @@ type LocalOriginConverter = ( parameter_types! { pub const BaseXcmWeight: Weight = 1_000; - pub KsmPerSecond: (MultiLocation, u128) = (KsmLocation::get(), 1); + pub KsmPerSecond: (AssetId, u128) = (Concrete(KsmLocation::get()), 1); } pub type XcmRouter = super::RelayChainXcmRouter; @@ -131,7 +131,7 @@ impl Config for XcmConfig { type LocationInverter = LocationInverter<Ancestry>; type Barrier = Barrier; type Weigher = FixedWeightBounds<BaseXcmWeight, Call>; - type Trader = FixedRateOfConcreteFungible<KsmPerSecond, ()>; + type Trader = FixedRateOfFungible<KsmPerSecond, ()>; type ResponseHandler = (); } From b5fe03e83a967793618e737dbb8caec8c1eb1e57 Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Tue, 3 Aug 2021 23:06:01 +0200 Subject: [PATCH 062/166] format --- xcm/src/lib.rs | 4 ++-- xcm/src/v1/mod.rs | 6 +++--- xcm/xcm-simulator/example/src/relay_chain.rs | 5 ++--- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/xcm/src/lib.rs b/xcm/src/lib.rs index c3b9a06ba141..f9ce3a3f5266 100644 --- a/xcm/src/lib.rs +++ b/xcm/src/lib.rs @@ -23,9 +23,9 @@ #![no_std] extern crate alloc; -use core::{result::Result, convert::TryFrom}; +use core::{convert::TryFrom, result::Result}; use derivative::Derivative; -use parity_scale_codec::{Decode, Encode, Input, Error as CodecError}; +use parity_scale_codec::{Decode, Encode, Error as CodecError, Input}; pub mod v1; diff --git a/xcm/src/v1/mod.rs b/xcm/src/v1/mod.rs index 38e7cf2c60ce..375a8d8a3cfc 100644 --- a/xcm/src/v1/mod.rs +++ b/xcm/src/v1/mod.rs @@ -23,17 +23,17 @@ use derivative::Derivative; use parity_scale_codec::{self, Decode, Encode}; mod junction; -mod multilocation; pub mod multiasset; +mod multilocation; mod order; mod traits; // the new multiasset. pub use junction::{BodyId, BodyPart, Junction, NetworkId}; -pub use multilocation::MultiLocation; pub use multiasset::{ AssetId, AssetInstance, Fungibility, MultiAsset, MultiAssetFilter, MultiAssets, WildFungibility, WildMultiAsset, }; +pub use multilocation::MultiLocation; pub use order::Order; pub use traits::{Error, ExecuteXcm, Outcome, Result, SendXcm}; @@ -45,7 +45,6 @@ pub mod prelude { Junction::*, NetworkId::{self, *}, }, - multilocation::MultiLocation::{self, *}, multiasset::{ AssetId::{self, *}, AssetInstance::{self, *}, @@ -56,6 +55,7 @@ pub mod prelude { WildFungibility::{self, Fungible as WildFungible, NonFungible as WildNonFungible}, WildMultiAsset::{self, *}, }, + multilocation::MultiLocation::{self, *}, opaque, order::Order::{self, *}, traits::{Error as XcmError, ExecuteXcm, Outcome, Result as XcmResult, SendXcm}, diff --git a/xcm/xcm-simulator/example/src/relay_chain.rs b/xcm/xcm-simulator/example/src/relay_chain.rs index b342ebaf7fff..7472df198219 100644 --- a/xcm/xcm-simulator/example/src/relay_chain.rs +++ b/xcm/xcm-simulator/example/src/relay_chain.rs @@ -30,9 +30,8 @@ use xcm::v1::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowUnpaidExecutionFrom, ChildParachainAsNative, ChildParachainConvertsVia, ChildSystemParachainAsSuperuser, - CurrencyAdapter as XcmCurrencyAdapter, FixedRateOfFungible, FixedWeightBounds, - IsConcrete, LocationInverter, SignedAccountId32AsNative, SignedToAccountId32, - SovereignSignedViaLocation, + CurrencyAdapter as XcmCurrencyAdapter, FixedRateOfFungible, FixedWeightBounds, IsConcrete, + LocationInverter, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, }; use xcm_executor::{Config, XcmExecutor}; From 608a212fa9ed7ddc1bde53855214a3323bcee5d7 Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Tue, 3 Aug 2021 23:30:51 +0200 Subject: [PATCH 063/166] Add max_assets param --- xcm/src/v1/order.rs | 12 ++++----- xcm/xcm-executor/src/assets.rs | 45 +++++++++++++++++++++++++++++++--- xcm/xcm-executor/src/lib.rs | 8 +++--- 3 files changed, 50 insertions(+), 15 deletions(-) diff --git a/xcm/src/v1/order.rs b/xcm/src/v1/order.rs index aed5a6ff3634..f5ba0e65bc48 100644 --- a/xcm/src/v1/order.rs +++ b/xcm/src/v1/order.rs @@ -39,8 +39,7 @@ pub enum Order<Call> { /// /// Errors: #[codec(index = 1)] - // TODO: https://github.com/paritytech/polkadot/issues/3547 introduce `, max_assets: u32` - DepositAsset { assets: MultiAssetFilter, dest: MultiLocation }, + DepositAsset { assets: MultiAssetFilter, max_assets: u32, dest: MultiLocation }, /// Remove the asset(s) (`assets`) from holding and place equivalent assets under the ownership of `dest` within /// this consensus system. @@ -54,8 +53,7 @@ pub enum Order<Call> { /// /// Errors: #[codec(index = 2)] - // TODO: https://github.com/paritytech/polkadot/issues/3547 introduce `, max_assets: u32` - DepositReserveAsset { assets: MultiAssetFilter, dest: MultiLocation, effects: Vec<Order<()>> }, + DepositReserveAsset { assets: MultiAssetFilter, max_assets: u32, dest: MultiLocation, effects: Vec<Order<()>> }, /// Remove the asset(s) (`give`) from holding and replace them with alternative assets. /// @@ -139,9 +137,9 @@ impl<Call> Order<Call> { use Order::*; match order { Noop => Noop, - DepositAsset { assets, dest } => DepositAsset { assets, dest }, - DepositReserveAsset { assets, dest, effects } => - DepositReserveAsset { assets, dest, effects }, + DepositAsset { assets, max_assets, dest } => DepositAsset { assets, max_assets, dest }, + DepositReserveAsset { assets, max_assets, dest, effects } => + DepositReserveAsset { assets, max_assets, dest, effects }, ExchangeAsset { give, receive } => ExchangeAsset { give, receive }, InitiateReserveWithdraw { assets, reserve, effects } => InitiateReserveWithdraw { assets, reserve, effects }, diff --git a/xcm/xcm-executor/src/assets.rs b/xcm/xcm-executor/src/assets.rs index 5270a30d44d2..f2354e058165 100644 --- a/xcm/xcm-executor/src/assets.rs +++ b/xcm/xcm-executor/src/assets.rs @@ -89,6 +89,11 @@ impl Assets { Self::default() } + /// Total number of distinct assets. + pub fn len(&self) -> usize { + self.fungible.len() + self.non_fungible.len() + } + /// A borrowing iterator over the fungible assets. pub fn fungible_assets_iter<'a>(&'a self) -> impl Iterator<Item = MultiAsset> + 'a { self.fungible @@ -231,10 +236,30 @@ impl Assets { &mut self, mask: MultiAssetFilter, saturate: bool, + limit: usize, ) -> Result<Assets, TakeError> { let mut taken = Assets::new(); match mask { - MultiAssetFilter::Wild(All) => return Ok(self.swapped(Assets::new())), + MultiAssetFilter::Wild(All) => if self.fungible.len() + self.non_fungible.len() <= limit { + return Ok(self.swapped(Assets::new())) + } else { + let fungible = mem::replace(&mut self.fungible, Default::default()); + fungible.into_iter().for_each(|(c, amount)| { + if taken.len() < limit { + taken.fungible.insert(c, amount); + } else { + self.fungible.insert(c, amount); + } + }); + let non_fungible = mem::replace(&mut self.non_fungible, Default::default()); + non_fungible.into_iter().for_each(|(c, instance)| { + if taken.len() < limit { + taken.non_fungible.insert((c, instance)); + } else { + self.non_fungible.insert((c, instance)); + } + }); + }, MultiAssetFilter::Wild(AllOf { fun: WildFungible, id }) => { if let Some((id, amount)) = self.fungible.remove_entry(&id) { taken.fungible.insert(id, amount); @@ -243,7 +268,7 @@ impl Assets { MultiAssetFilter::Wild(AllOf { fun: WildNonFungible, id }) => { let non_fungible = mem::replace(&mut self.non_fungible, Default::default()); non_fungible.into_iter().for_each(|(c, instance)| { - if c == id { + if c == id && taken.len() < limit { taken.non_fungible.insert((c, instance)); } else { self.non_fungible.insert((c, instance)); @@ -279,6 +304,9 @@ impl Assets { } }, } + if taken.len() == limit { + break + } } }, } @@ -290,7 +318,16 @@ impl Assets { /// Returns `Ok` with the non-wildcard equivalence of `mask` taken and mutates `self` to its value minus /// `mask` if `self` contains `asset`, and return `Err` otherwise. pub fn saturating_take(&mut self, asset: MultiAssetFilter) -> Assets { - self.general_take(asset, true) + self.general_take(asset, true, usize::max_value()) + .expect("general_take never results in error when saturating") + } + + /// Mutates `self` to its original value less `mask` and returns `true` iff it contains at least `mask`. + /// + /// Returns `Ok` with the non-wildcard equivalence of `mask` taken and mutates `self` to its value minus + /// `mask` if `self` contains `asset`, and return `Err` otherwise. + pub fn limited_saturating_take(&mut self, asset: MultiAssetFilter, limit: usize) -> Assets { + self.general_take(asset, true, limit) .expect("general_take never results in error when saturating") } @@ -299,7 +336,7 @@ impl Assets { /// Returns `Ok` with the non-wildcard equivalence of `asset` taken and mutates `self` to its value minus /// `asset` if `self` contains `asset`, and return `Err` otherwise. pub fn try_take(&mut self, mask: MultiAssetFilter) -> Result<Assets, TakeError> { - self.general_take(mask, false) + self.general_take(mask, false, usize::max_value()) } /// Consumes `self` and returns its original value excluding `asset` iff it contains at least `asset`. diff --git a/xcm/xcm-executor/src/lib.rs b/xcm/xcm-executor/src/lib.rs index 491558dbdb28..46be5ae644df 100644 --- a/xcm/xcm-executor/src/lib.rs +++ b/xcm/xcm-executor/src/lib.rs @@ -269,14 +269,14 @@ impl<Config: config::Config> XcmExecutor<Config> { ); let mut total_surplus = 0; match effect { - Order::DepositAsset { assets, dest } => { - let deposited = holding.saturating_take(assets); + Order::DepositAsset { assets, max_assets, dest } => { + let deposited = holding.limited_saturating_take(assets, max_assets as usize); for asset in deposited.into_assets_iter() { Config::AssetTransactor::deposit_asset(&asset, &dest)?; } }, - Order::DepositReserveAsset { assets, dest, effects } => { - let deposited = holding.saturating_take(assets); + Order::DepositReserveAsset { assets, max_assets, dest, effects } => { + let deposited = holding.limited_saturating_take(assets, max_assets as usize); for asset in deposited.assets_iter() { Config::AssetTransactor::deposit_asset(&asset, &dest)?; } From dee3be53d9c03ce2e09a974130d7870c7a07637c Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Tue, 3 Aug 2021 23:37:49 +0200 Subject: [PATCH 064/166] building --- xcm/pallet-xcm/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xcm/pallet-xcm/src/lib.rs b/xcm/pallet-xcm/src/lib.rs index ece2590f4d53..38293257c21d 100644 --- a/xcm/pallet-xcm/src/lib.rs +++ b/xcm/pallet-xcm/src/lib.rs @@ -165,7 +165,7 @@ pub mod pallet { halt_on_error: false, xcm: vec![], }, - DepositAsset { assets: Wild(All), dest: beneficiary }, + DepositAsset { assets: Wild(All), max_assets: 1, dest: beneficiary }, ], }], }; @@ -222,7 +222,7 @@ pub mod pallet { halt_on_error: false, xcm: vec![], }, - DepositAsset { assets: Wild(All), dest: beneficiary }, + DepositAsset { assets: Wild(All), max_assets: 1, dest: beneficiary }, ], }; let weight = From a6eaaa2a99ee5800a9c7a9f09535656208826f7e Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Tue, 3 Aug 2021 23:50:02 +0200 Subject: [PATCH 065/166] test fixes --- xcm/pallet-xcm/src/tests.rs | 24 ++++++++++++------------ xcm/src/v1/multiasset.rs | 8 +++++++- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/xcm/pallet-xcm/src/tests.rs b/xcm/pallet-xcm/src/tests.rs index 2fc2de28ef64..da5d4405cc4a 100644 --- a/xcm/pallet-xcm/src/tests.rs +++ b/xcm/pallet-xcm/src/tests.rs @@ -38,12 +38,12 @@ fn send_works() { new_test_ext_with_balances(balances).execute_with(|| { let weight = 2 * BaseXcmWeight::get(); let sender: MultiLocation = - Junction::AccountId32 { network: AnyNetwork::get(), id: ALICE.into() }.into(); - let message = Xcm::ReserveAssetDeposit { - assets: vec![ConcreteFungible { id: Parent.into(), amount: SEND_AMOUNT }], + AccountId32 { network: AnyNetwork::get(), id: ALICE.into() }.into(); + let message = Xcm::ReserveAssetDeposited { + assets: (X1(Parent), SEND_AMOUNT).into(), effects: vec![ buy_execution(weight), - DepositAsset { assets: vec![All], dest: sender.clone() }, + DepositAsset { assets: Wild(All), dest: sender.clone() }, ], }; assert_ok!(XcmPallet::send(Origin::signed(ALICE), RelayLocation::get(), message.clone())); @@ -77,7 +77,7 @@ fn send_fails_when_xcm_router_blocks() { assets: vec![ConcreteFungible { id: Parent.into(), amount: SEND_AMOUNT }], effects: vec![ buy_execution(weight), - DepositAsset { assets: vec![All], dest: sender.clone() }, + DepositAsset { assets: Wild(All), dest: sender.clone() }, ], }; assert_noop!( @@ -114,8 +114,8 @@ fn teleport_assets_works() { assert_ok!(XcmPallet::teleport_assets( Origin::signed(ALICE), RelayLocation::get(), - MultiLocation::X1(Junction::AccountId32 { network: NetworkId::Any, id: BOB.into() }), - vec![ConcreteFungible { id: MultiLocation::Null, amount: SEND_AMOUNT }], + X1(AccountId32 { network: Any, id: BOB.into() }), + (Null, SEND_AMOUNT).into(), weight, )); assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE - SEND_AMOUNT); @@ -143,7 +143,7 @@ fn reserve_transfer_assets_works() { Origin::signed(ALICE), Parachain(PARA_ID).into(), dest.clone(), - vec![ConcreteFungible { id: MultiLocation::Null, amount: SEND_AMOUNT }], + (Null, SEND_AMOUNT).into(), weight )); // Alice spent amount @@ -156,8 +156,8 @@ fn reserve_transfer_assets_works() { vec![( Parachain(PARA_ID).into(), Xcm::ReserveAssetDeposit { - assets: vec![ConcreteFungible { id: Parent.into(), amount: SEND_AMOUNT }], - effects: vec![buy_execution(weight), DepositAsset { assets: vec![All], dest },] + assets: (X1(Parent), SEND_AMOUNT).into(), + effects: vec![buy_execution(weight), DepositAsset { assets: Wild(All), dest },] } )] ); @@ -184,8 +184,8 @@ fn execute_withdraw_to_deposit_works() { assert_ok!(XcmPallet::execute( Origin::signed(ALICE), Box::new(Xcm::WithdrawAsset { - assets: vec![ConcreteFungible { id: MultiLocation::Null, amount: SEND_AMOUNT }], - effects: vec![buy_execution(weight), DepositAsset { assets: vec![All], dest }], + assets: (Null, SEND_AMOUNT).into(), + effects: vec![buy_execution(weight), DepositAsset { assets: Wild(All), dest }], }), weight )); diff --git a/xcm/src/v1/multiasset.rs b/xcm/src/v1/multiasset.rs index c11110ed571c..572146ad34ad 100644 --- a/xcm/src/v1/multiasset.rs +++ b/xcm/src/v1/multiasset.rs @@ -23,7 +23,7 @@ //! - `MultiAssetFilter`: A combination of `Wild` and `MultiAssets` designed for efficiently filtering an XCM holding //! account. -use super::MultiLocation; +use super::{Junction, MultiLocation::{self, X1}}; use alloc::{vec, vec::Vec}; use core::cmp::Ordering; use parity_scale_codec::{self as codec, Decode, Encode}; @@ -70,6 +70,12 @@ impl From<MultiLocation> for AssetId { } } +impl From<Junction> for AssetId { + fn from(x: Junction) -> Self { + Self::Concrete(X1(x)) + } +} + impl From<Vec<u8>> for AssetId { fn from(x: Vec<u8>) -> Self { Self::Abstract(x) From f58a65931f9aa606c01e1aadacd1b8c7d3480996 Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Tue, 3 Aug 2021 23:59:12 +0200 Subject: [PATCH 066/166] tests --- xcm/pallet-xcm/src/mock.rs | 10 +++++----- xcm/pallet-xcm/src/tests.rs | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/xcm/pallet-xcm/src/mock.rs b/xcm/pallet-xcm/src/mock.rs index e919be21a21d..b347b3520882 100644 --- a/xcm/pallet-xcm/src/mock.rs +++ b/xcm/pallet-xcm/src/mock.rs @@ -26,12 +26,12 @@ use sp_runtime::{testing::Header, traits::IdentityLookup, AccountId32}; pub use sp_std::{cell::RefCell, fmt::Debug, marker::PhantomData}; use xcm::{ opaque::v1::{Error as XcmError, MultiAsset, Result as XcmResult, SendXcm, Xcm}, - v1::{MultiLocation, NetworkId, Order}, + v1::prelude::*, }; use xcm_builder::{ AccountId32Aliases, AllowTopLevelPaidExecutionFrom, ChildParachainAsNative, ChildParachainConvertsVia, ChildSystemParachainAsSuperuser, - CurrencyAdapter as XcmCurrencyAdapter, FixedRateOfConcreteFungible, FixedWeightBounds, + CurrencyAdapter as XcmCurrencyAdapter, FixedRateOfFungible, FixedWeightBounds, IsConcrete, LocationInverter, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, }; @@ -154,7 +154,7 @@ type LocalOriginConverter = ( parameter_types! { pub const BaseXcmWeight: Weight = 1_000; - pub CurrencyPerSecond: (MultiLocation, u128) = (RelayLocation::get(), 1); + pub CurrencyPerSecond: (AssetId, u128) = (Concrete(RelayLocation::get()), 1); } pub type Barrier = (TakeWeightCredit, AllowTopLevelPaidExecutionFrom<All<MultiLocation>>); @@ -170,7 +170,7 @@ impl xcm_executor::Config for XcmConfig { type LocationInverter = LocationInverter<Ancestry>; type Barrier = Barrier; type Weigher = FixedWeightBounds<BaseXcmWeight, Call>; - type Trader = FixedRateOfConcreteFungible<CurrencyPerSecond, ()>; + type Trader = FixedRateOfFungible<CurrencyPerSecond, ()>; type ResponseHandler = (); } @@ -196,7 +196,7 @@ pub(crate) fn last_event() -> Event { pub(crate) fn buy_execution<C>(debt: Weight) -> Order<C> { use xcm::opaque::v1::prelude::*; - Order::BuyExecution { fees: All, weight: 0, debt, halt_on_error: false, xcm: vec![] } + Order::BuyExecution { fees: (RelayLocation::get(), 1).into(), weight: 0, debt, halt_on_error: false, xcm: vec![] } } pub(crate) fn new_test_ext_with_balances( diff --git a/xcm/pallet-xcm/src/tests.rs b/xcm/pallet-xcm/src/tests.rs index da5d4405cc4a..6c1a7c6203cc 100644 --- a/xcm/pallet-xcm/src/tests.rs +++ b/xcm/pallet-xcm/src/tests.rs @@ -73,8 +73,8 @@ fn send_fails_when_xcm_router_blocks() { let weight = 2 * BaseXcmWeight::get(); let sender: MultiLocation = Junction::AccountId32 { network: AnyNetwork::get(), id: ALICE.into() }.into(); - let message = Xcm::ReserveAssetDeposit { - assets: vec![ConcreteFungible { id: Parent.into(), amount: SEND_AMOUNT }], + let message = Xcm::ReserveAssetDeposited { + assets: (Parent, SEND_AMOUNT).into(), effects: vec![ buy_execution(weight), DepositAsset { assets: Wild(All), dest: sender.clone() }, @@ -155,7 +155,7 @@ fn reserve_transfer_assets_works() { sent_xcm(), vec![( Parachain(PARA_ID).into(), - Xcm::ReserveAssetDeposit { + Xcm::ReserveAssetDeposited { assets: (X1(Parent), SEND_AMOUNT).into(), effects: vec![buy_execution(weight), DepositAsset { assets: Wild(All), dest },] } From 8a7810001e4583ccf789ca89733aedeeed75459a Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Wed, 4 Aug 2021 00:03:38 +0200 Subject: [PATCH 067/166] another test --- xcm/xcm-builder/src/weight.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/xcm/xcm-builder/src/weight.rs b/xcm/xcm-builder/src/weight.rs index 87b7c2f6b488..028ce6b061e4 100644 --- a/xcm/xcm-builder/src/weight.rs +++ b/xcm/xcm-builder/src/weight.rs @@ -162,6 +162,9 @@ impl<T: Get<(AssetId, u128)>, R: TakeRevenue> WeightTrader for FixedRateOfFungib let (id, units_per_second) = T::get(); use frame_support::weights::constants::WEIGHT_PER_SECOND; let amount = units_per_second * (weight as u128) / (WEIGHT_PER_SECOND as u128); + if amount == 0 { + return Ok(payment) + } let unused = payment.checked_sub((id, amount).into()).map_err(|_| Error::TooExpensive)?; self.0 = self.0.saturating_add(weight); self.1 = self.1.saturating_add(amount); From 6eb75ad84691b42fa1898b93279f82296c66a047 Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Wed, 4 Aug 2021 00:04:55 +0200 Subject: [PATCH 068/166] final test --- xcm/pallet-xcm/src/mock.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xcm/pallet-xcm/src/mock.rs b/xcm/pallet-xcm/src/mock.rs index b347b3520882..1051a171c06a 100644 --- a/xcm/pallet-xcm/src/mock.rs +++ b/xcm/pallet-xcm/src/mock.rs @@ -196,7 +196,7 @@ pub(crate) fn last_event() -> Event { pub(crate) fn buy_execution<C>(debt: Weight) -> Order<C> { use xcm::opaque::v1::prelude::*; - Order::BuyExecution { fees: (RelayLocation::get(), 1).into(), weight: 0, debt, halt_on_error: false, xcm: vec![] } + Order::BuyExecution { fees: (RelayLocation::get(), 10).into(), weight: 0, debt, halt_on_error: false, xcm: vec![] } } pub(crate) fn new_test_ext_with_balances( From c4f61f3390e57ca2f94e74dee11ef4d66fc75625 Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Wed, 4 Aug 2021 02:32:00 -0700 Subject: [PATCH 069/166] Update rustdocs and add debug_assert where sensible --- xcm/src/v0/multi_location.rs | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/xcm/src/v0/multi_location.rs b/xcm/src/v0/multi_location.rs index 77d30bc7fb5a..e9ae0fe11061 100644 --- a/xcm/src/v0/multi_location.rs +++ b/xcm/src/v0/multi_location.rs @@ -38,15 +38,17 @@ use parity_scale_codec::{self, Decode, Encode, Input, Output}; /// 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 `Null` simply refers to the interpreting consensus system. +/// 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, Eq, PartialEq, Ord, PartialOrd, Debug)] pub struct MultiLocation { + /// The number of parent junctions at the beginning of this `MultiLocation`. parents: u8, + /// The interior (i.e. non-parent) junctions that this `MultiLocation` contains. interior: Junctions, } @@ -121,6 +123,8 @@ impl MultiLocation { } /// Creates a new `MultiLocation` with 0 parents and a `Null` interior. + /// + /// The resulting `MultiLocation` can be interpreted as the "current consensus system". pub const fn empty() -> MultiLocation { MultiLocation { parents: 0, interior: Junctions::Null } } @@ -144,6 +148,9 @@ impl MultiLocation { /// Creates a new `MultiLocation` with no parents and a single `Parachain` interior junction /// specified by `para_id`. + /// + /// The resulting `MultiLocation` can be interpreted as the child-parachain of the current + /// consensus system. pub const fn with_parachain_interior(para_id: u32) -> MultiLocation { MultiLocation { parents: 0, interior: Junctions::X1(Junction::Parachain(para_id)) } } @@ -170,7 +177,9 @@ impl MultiLocation { /// Returns the number of parents and junctions in `self`. pub const fn len(&self) -> usize { - self.parent_count() as usize + self.interior.len() + let len = self.parent_count() as usize + self.interior.len(); + debug_assert!(len <= MAX_MULTILOCATION_LENGTH); + len } /// Returns the first interior junction, or `None` if the location is empty or contains only @@ -530,6 +539,11 @@ impl From<[Junction; 8]> for MultiLocation { } } +/// 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. From a25f3ea2448e27f016283d1a8fcfd319cc4d5921 Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Wed, 4 Aug 2021 02:38:01 -0700 Subject: [PATCH 070/166] Revert debug_assert in const fn len() --- xcm/src/v0/multi_location.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/xcm/src/v0/multi_location.rs b/xcm/src/v0/multi_location.rs index e9ae0fe11061..7ce2989a59cb 100644 --- a/xcm/src/v0/multi_location.rs +++ b/xcm/src/v0/multi_location.rs @@ -177,9 +177,7 @@ impl MultiLocation { /// Returns the number of parents and junctions in `self`. pub const fn len(&self) -> usize { - let len = self.parent_count() as usize + self.interior.len(); - debug_assert!(len <= MAX_MULTILOCATION_LENGTH); - len + self.parent_count() as usize + self.interior.len() } /// Returns the first interior junction, or `None` if the location is empty or contains only From 9d0b9f9900070115363ae4fb5198acce109763b9 Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Wed, 4 Aug 2021 11:56:32 +0200 Subject: [PATCH 071/166] tests --- xcm/pallet-xcm/src/mock.rs | 14 ++++++++++---- xcm/src/v1/multiasset.rs | 5 ++++- xcm/xcm-simulator/example/src/lib.rs | 10 ++-------- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/xcm/pallet-xcm/src/mock.rs b/xcm/pallet-xcm/src/mock.rs index 1051a171c06a..0fa4ba225ce2 100644 --- a/xcm/pallet-xcm/src/mock.rs +++ b/xcm/pallet-xcm/src/mock.rs @@ -31,9 +31,9 @@ use xcm::{ use xcm_builder::{ AccountId32Aliases, AllowTopLevelPaidExecutionFrom, ChildParachainAsNative, ChildParachainConvertsVia, ChildSystemParachainAsSuperuser, - CurrencyAdapter as XcmCurrencyAdapter, FixedRateOfFungible, FixedWeightBounds, - IsConcrete, LocationInverter, SignedAccountId32AsNative, SignedToAccountId32, - SovereignSignedViaLocation, TakeWeightCredit, + CurrencyAdapter as XcmCurrencyAdapter, FixedRateOfFungible, FixedWeightBounds, IsConcrete, + LocationInverter, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, + TakeWeightCredit, }; use xcm_executor::XcmExecutor; @@ -196,7 +196,13 @@ pub(crate) fn last_event() -> Event { pub(crate) fn buy_execution<C>(debt: Weight) -> Order<C> { use xcm::opaque::v1::prelude::*; - Order::BuyExecution { fees: (RelayLocation::get(), 10).into(), weight: 0, debt, halt_on_error: false, xcm: vec![] } + Order::BuyExecution { + fees: (RelayLocation::get(), 10).into(), + weight: 0, + debt, + halt_on_error: false, + xcm: vec![], + } } pub(crate) fn new_test_ext_with_balances( diff --git a/xcm/src/v1/multiasset.rs b/xcm/src/v1/multiasset.rs index 572146ad34ad..5716a7b5c980 100644 --- a/xcm/src/v1/multiasset.rs +++ b/xcm/src/v1/multiasset.rs @@ -23,7 +23,10 @@ //! - `MultiAssetFilter`: A combination of `Wild` and `MultiAssets` designed for efficiently filtering an XCM holding //! account. -use super::{Junction, MultiLocation::{self, X1}}; +use super::{ + Junction, + MultiLocation::{self, X1}, +}; use alloc::{vec, vec::Vec}; use core::cmp::Ordering; use parity_scale_codec::{self as codec, Decode, Encode}; diff --git a/xcm/xcm-simulator/example/src/lib.rs b/xcm/xcm-simulator/example/src/lib.rs index 00c1f4109421..978795a1546e 100644 --- a/xcm/xcm-simulator/example/src/lib.rs +++ b/xcm/xcm-simulator/example/src/lib.rs @@ -100,13 +100,7 @@ mod tests { use codec::Encode; use frame_support::assert_ok; - use xcm::v1::{ - Junction::{self, Parachain, Parent}, - MultiAsset::*, - MultiLocation::*, - NetworkId, OriginKind, - Xcm::*, - }; + use xcm::v1::prelude::*; use xcm_simulator::TestExt; #[test] @@ -199,7 +193,7 @@ mod tests { relay_chain::Origin::signed(ALICE), X1(Parachain(1)), X1(Junction::AccountId32 { network: NetworkId::Any, id: ALICE.into() }), - vec![ConcreteFungible { id: Null, amount: 123 }], + (Null, 123).into(), 123, )); }); From b5b63c8208dce9c29f3d9af9bffee57dc8739870 Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Wed, 4 Aug 2021 12:26:48 +0200 Subject: [PATCH 072/166] Rename Null -> Here --- runtime/kusama/src/lib.rs | 6 +-- runtime/rococo/src/lib.rs | 4 +- runtime/westend/src/lib.rs | 4 +- xcm/pallet-xcm/src/lib.rs | 8 ++-- xcm/pallet-xcm/src/mock.rs | 4 +- xcm/pallet-xcm/src/tests.rs | 16 +++---- xcm/src/v1/mod.rs | 29 ++++++------ xcm/src/v1/multilocation.rs | 40 ++++++++-------- xcm/src/v1/order.rs | 15 ++++-- xcm/xcm-builder/src/barriers.rs | 2 +- xcm/xcm-builder/src/mock.rs | 4 +- xcm/xcm-builder/src/origin_conversion.rs | 2 +- xcm/xcm-builder/src/tests.rs | 46 +++++++++---------- xcm/xcm-builder/src/weight.rs | 4 +- xcm/xcm-executor/src/assets.rs | 20 ++++---- xcm/xcm-executor/src/lib.rs | 12 ++--- xcm/xcm-executor/src/traits/transact_asset.rs | 10 ++-- xcm/xcm-simulator/example/src/lib.rs | 8 ++-- xcm/xcm-simulator/example/src/relay_chain.rs | 4 +- 19 files changed, 122 insertions(+), 116 deletions(-) diff --git a/runtime/kusama/src/lib.rs b/runtime/kusama/src/lib.rs index c2720c8deed1..6fc6b8ac3524 100644 --- a/runtime/kusama/src/lib.rs +++ b/runtime/kusama/src/lib.rs @@ -1199,14 +1199,14 @@ impl auctions::Config for Runtime { 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 `Null` location, which means "equivalent to + /// 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::Null; + pub const KsmLocation: MultiLocation = MultiLocation::Here; /// 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::Null; + pub const Ancestry: MultiLocation = MultiLocation::Here; /// The check account, which holds any native assets that have been teleported out and not back in (yet). pub CheckAccount: AccountId = XcmPallet::check_account(); } diff --git a/runtime/rococo/src/lib.rs b/runtime/rococo/src/lib.rs index 88e6072003ff..f05de3d26771 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::Null; + pub const RocLocation: MultiLocation = MultiLocation::Here; pub const RococoNetwork: NetworkId = NetworkId::Polkadot; - pub const Ancestry: MultiLocation = MultiLocation::Null; + pub const Ancestry: MultiLocation = MultiLocation::Here; pub CheckAccount: AccountId = XcmPallet::check_account(); } diff --git a/runtime/westend/src/lib.rs b/runtime/westend/src/lib.rs index a578ff548afc..d0304022c602 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::Null; - pub const Ancestry: MultiLocation = MultiLocation::Null; + pub const WndLocation: MultiLocation = MultiLocation::Here; + pub const Ancestry: MultiLocation = MultiLocation::Here; pub WestendNetwork: NetworkId = NetworkId::Named(b"Westend".to_vec()); pub CheckAccount: AccountId = XcmPallet::check_account(); } diff --git a/xcm/pallet-xcm/src/lib.rs b/xcm/pallet-xcm/src/lib.rs index ece2590f4d53..3486e9777a94 100644 --- a/xcm/pallet-xcm/src/lib.rs +++ b/xcm/pallet-xcm/src/lib.rs @@ -165,7 +165,7 @@ pub mod pallet { halt_on_error: false, xcm: vec![], }, - DepositAsset { assets: Wild(All), dest: beneficiary }, + DepositAsset { assets: Wild(All), beneficiary }, ], }], }; @@ -222,7 +222,7 @@ pub mod pallet { halt_on_error: false, xcm: vec![], }, - DepositAsset { assets: Wild(All), dest: beneficiary }, + DepositAsset { assets: Wild(All), beneficiary }, ], }; let weight = @@ -269,7 +269,7 @@ pub mod pallet { message: Xcm<()>, ) -> Result<(), XcmError> { let message = match interior { - MultiLocation::Null => message, + MultiLocation::Here => message, who => Xcm::<()>::RelayedFrom { who, message: Box::new(message) }, }; log::trace!(target: "xcm::send_xcm", "dest: {:?}, message: {:?}", &dest, &message); @@ -346,7 +346,7 @@ where #[cfg(feature = "runtime-benchmarks")] fn successful_origin() -> O { - O::from(Origin::Xcm(MultiLocation::Null)) + O::from(Origin::Xcm(MultiLocation::Here)) } } diff --git a/xcm/pallet-xcm/src/mock.rs b/xcm/pallet-xcm/src/mock.rs index 0fa4ba225ce2..b3c12f9531e3 100644 --- a/xcm/pallet-xcm/src/mock.rs +++ b/xcm/pallet-xcm/src/mock.rs @@ -133,9 +133,9 @@ impl pallet_balances::Config for Test { } parameter_types! { - pub const RelayLocation: MultiLocation = MultiLocation::Null; + pub const RelayLocation: MultiLocation = MultiLocation::Here; pub const AnyNetwork: NetworkId = NetworkId::Any; - pub Ancestry: MultiLocation = MultiLocation::Null; + pub Ancestry: MultiLocation = MultiLocation::Here; pub UnitWeightCost: Weight = 1_000; } diff --git a/xcm/pallet-xcm/src/tests.rs b/xcm/pallet-xcm/src/tests.rs index 6c1a7c6203cc..0e8b086e8290 100644 --- a/xcm/pallet-xcm/src/tests.rs +++ b/xcm/pallet-xcm/src/tests.rs @@ -43,14 +43,14 @@ fn send_works() { assets: (X1(Parent), SEND_AMOUNT).into(), effects: vec![ buy_execution(weight), - DepositAsset { assets: Wild(All), dest: sender.clone() }, + DepositAsset { assets: Wild(All), beneficiary: sender.clone() }, ], }; assert_ok!(XcmPallet::send(Origin::signed(ALICE), RelayLocation::get(), message.clone())); assert_eq!( sent_xcm(), vec![( - MultiLocation::Null, + MultiLocation::Here, RelayedFrom { who: sender.clone(), message: Box::new(message.clone()) } )] ); @@ -77,7 +77,7 @@ fn send_fails_when_xcm_router_blocks() { assets: (Parent, SEND_AMOUNT).into(), effects: vec![ buy_execution(weight), - DepositAsset { assets: Wild(All), dest: sender.clone() }, + DepositAsset { assets: Wild(All), beneficiary: sender.clone() }, ], }; assert_noop!( @@ -115,7 +115,7 @@ fn teleport_assets_works() { Origin::signed(ALICE), RelayLocation::get(), X1(AccountId32 { network: Any, id: BOB.into() }), - (Null, SEND_AMOUNT).into(), + (Here, SEND_AMOUNT).into(), weight, )); assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE - SEND_AMOUNT); @@ -143,7 +143,7 @@ fn reserve_transfer_assets_works() { Origin::signed(ALICE), Parachain(PARA_ID).into(), dest.clone(), - (Null, SEND_AMOUNT).into(), + (Here, SEND_AMOUNT).into(), weight )); // Alice spent amount @@ -157,7 +157,7 @@ fn reserve_transfer_assets_works() { Parachain(PARA_ID).into(), Xcm::ReserveAssetDeposited { assets: (X1(Parent), SEND_AMOUNT).into(), - effects: vec![buy_execution(weight), DepositAsset { assets: Wild(All), dest },] + effects: vec![buy_execution(weight), DepositAsset { assets: Wild(All), beneficiary: dest },] } )] ); @@ -184,8 +184,8 @@ fn execute_withdraw_to_deposit_works() { assert_ok!(XcmPallet::execute( Origin::signed(ALICE), Box::new(Xcm::WithdrawAsset { - assets: (Null, SEND_AMOUNT).into(), - effects: vec![buy_execution(weight), DepositAsset { assets: Wild(All), dest }], + assets: (Here, SEND_AMOUNT).into(), + effects: vec![buy_execution(weight), DepositAsset { assets: Wild(All), beneficiary: dest }], }), weight )); diff --git a/xcm/src/v1/mod.rs b/xcm/src/v1/mod.rs index 375a8d8a3cfc..5f7bae368d85 100644 --- a/xcm/src/v1/mod.rs +++ b/xcm/src/v1/mod.rs @@ -143,19 +143,19 @@ pub enum Xcm<Call> { /// created on this system. /// /// Some orders are given (`effects`) which should be executed once the corresponding derivative assets have - /// been placed into `holding`. + /// been placed into the Holding Register. /// - /// - `assets`: The asset(s) that are minted into holding. - /// - `effects`: The order(s) to execute on the holding register. + /// - `assets`: The asset(s) that are minted into the Holding Register. + /// - `effects`: The order(s) to execute on the Holding Register. /// - /// Safety: `origin` must be trusted to have irrevocably destroyed the `assets` prior as a consequence of - /// sending this message. + /// Safety: `origin` must be trusted to have irrevocably destroyed the corresponding`assets` prior as a consequence + /// of sending this message. /// /// Kind: *Trusted Indication*. /// /// Errors: #[codec(index = 2)] - TeleportAsset { assets: MultiAssets, effects: Vec<Order<Call>> }, + ReceiveTeleportedAsset { assets: MultiAssets, effects: Vec<Order<Call>> }, /// Indication of the contents of the holding register corresponding to the `QueryHolding` order of `query_id`. /// @@ -175,10 +175,10 @@ pub enum Xcm<Call> { }, /// Withdraw asset(s) (`assets`) from the ownership of `origin` and place equivalent assets under the - /// ownership of `dest` within this consensus system. + /// ownership of `beneficiary`. /// /// - `assets`: The asset(s) to be withdrawn. - /// - `dest`: The new owner for the assets. + /// - `beneficiary`: The new owner for the assets. /// /// Safety: No concerns. /// @@ -186,15 +186,16 @@ pub enum Xcm<Call> { /// /// Errors: #[codec(index = 4)] - TransferAsset { assets: MultiAssets, dest: MultiLocation }, + TransferAsset { assets: MultiAssets, beneficiary: MultiLocation }, /// Withdraw asset(s) (`assets`) from the ownership of `origin` and place equivalent assets under the - /// ownership of `dest` within this consensus system. + /// ownership of `dest` within this consensus system (i.e. its sovereign account). /// /// Send an onward XCM message to `dest` of `ReserveAssetDeposited` with the given `effects`. /// /// - `assets`: The asset(s) to be withdrawn. - /// - `dest`: The new owner for the assets. + /// - `dest`: The location whose sovereign account will own the assets and thus the effective beneficiary for the + /// assets and the notification target for the reserve asset deposit message. /// - `effects`: The orders that should be contained in the `ReserveAssetDeposited` which is sent onwards to /// `dest`. /// @@ -303,10 +304,10 @@ impl<Call> Xcm<Call> { assets, effects: effects.into_iter().map(Order::into).collect(), }, - TeleportAsset { assets, effects } => - TeleportAsset { assets, effects: effects.into_iter().map(Order::into).collect() }, + ReceiveTeleportedAsset { assets, effects } => + ReceiveTeleportedAsset { assets, effects: effects.into_iter().map(Order::into).collect() }, QueryResponse { query_id: u64, response } => QueryResponse { query_id: u64, response }, - TransferAsset { assets, dest } => TransferAsset { assets, dest }, + TransferAsset { assets, beneficiary } => TransferAsset { assets, beneficiary }, TransferReserveAsset { assets, dest, effects } => TransferReserveAsset { assets, dest, effects }, HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } => diff --git a/xcm/src/v1/multilocation.rs b/xcm/src/v1/multilocation.rs index 20a9153b570a..e44d5f76a289 100644 --- a/xcm/src/v1/multilocation.rs +++ b/xcm/src/v1/multilocation.rs @@ -42,11 +42,11 @@ use parity_scale_codec::{self, Decode, Encode}; /// /// This specific `MultiLocation` implementation uses a Rust `enum` in order to make pattern matching easier. /// -/// The `MultiLocation` value of `Null` simply refers to the interpreting consensus system. +/// 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. - Null, + Here, /// A relative path comprising 1 junction. X1(Junction), /// A relative path comprising 2 junctions. @@ -76,7 +76,7 @@ impl From<Junction> for MultiLocation { impl From<()> for MultiLocation { fn from(_: ()) -> Self { - MultiLocation::Null + MultiLocation::Here } } impl From<(Junction,)> for MultiLocation { @@ -128,7 +128,7 @@ impl From<(Junction, Junction, Junction, Junction, Junction, Junction, Junction, impl From<[Junction; 0]> for MultiLocation { fn from(_: [Junction; 0]) -> Self { - MultiLocation::Null + MultiLocation::Here } } impl From<[Junction; 1]> for MultiLocation { @@ -219,7 +219,7 @@ impl MultiLocation { /// Returns first junction, or `None` if the location is empty. pub fn first(&self) -> Option<&Junction> { match &self { - MultiLocation::Null => None, + MultiLocation::Here => None, MultiLocation::X1(ref a) => Some(a), MultiLocation::X2(ref a, ..) => Some(a), MultiLocation::X3(ref a, ..) => Some(a), @@ -234,7 +234,7 @@ impl MultiLocation { /// Returns last junction, or `None` if the location is empty. pub fn last(&self) -> Option<&Junction> { match &self { - MultiLocation::Null => None, + MultiLocation::Here => None, MultiLocation::X1(ref a) => Some(a), MultiLocation::X2(.., ref a) => Some(a), MultiLocation::X3(.., ref a) => Some(a), @@ -250,8 +250,8 @@ impl MultiLocation { /// (second item in tuple) or `None` if it was empty. pub fn split_first(self) -> (MultiLocation, Option<Junction>) { match self { - MultiLocation::Null => (MultiLocation::Null, None), - MultiLocation::X1(a) => (MultiLocation::Null, Some(a)), + 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)), @@ -268,8 +268,8 @@ impl MultiLocation { /// (second item in tuple) or `None` if it was empty. pub fn split_last(self) -> (MultiLocation, Option<Junction>) { match self { - MultiLocation::Null => (MultiLocation::Null, None), - MultiLocation::X1(a) => (MultiLocation::Null, Some(a)), + 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)), @@ -284,7 +284,7 @@ impl MultiLocation { /// Removes the first element from `self`, returning it (or `None` if it was empty). pub fn take_first(&mut self) -> Option<Junction> { - let mut d = MultiLocation::Null; + let mut d = MultiLocation::Here; mem::swap(&mut *self, &mut d); let (tail, head) = d.split_first(); *self = tail; @@ -293,7 +293,7 @@ impl MultiLocation { /// Removes the last element from `self`, returning it (or `None` if it was empty). pub fn take_last(&mut self) -> Option<Junction> { - let mut d = MultiLocation::Null; + let mut d = MultiLocation::Here; mem::swap(&mut *self, &mut d); let (head, tail) = d.split_last(); *self = head; @@ -304,7 +304,7 @@ impl MultiLocation { /// `self` in case of overflow. pub fn pushed_with(self, new: Junction) -> result::Result<Self, Self> { Ok(match self { - MultiLocation::Null => MultiLocation::X1(new), + 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), @@ -320,7 +320,7 @@ impl MultiLocation { /// `self` in case of overflow. pub fn pushed_front_with(self, new: Junction) -> result::Result<Self, Self> { Ok(match self { - MultiLocation::Null => MultiLocation::X1(new), + 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), @@ -335,7 +335,7 @@ impl MultiLocation { /// Returns the number of junctions in `self`. pub fn len(&self) -> usize { match &self { - MultiLocation::Null => 0, + MultiLocation::Here => 0, MultiLocation::X1(..) => 1, MultiLocation::X2(..) => 2, MultiLocation::X3(..) => 3, @@ -480,7 +480,7 @@ impl MultiLocation { /// 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::Null; + let mut n = MultiLocation::Here; mem::swap(&mut *self, &mut n); match n.pushed_with(new) { Ok(result) => { @@ -496,7 +496,7 @@ impl MultiLocation { /// 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::Null; + let mut n = MultiLocation::Here; mem::swap(&mut *self, &mut n); match n.pushed_front_with(new) { Ok(result) => { @@ -564,7 +564,7 @@ impl MultiLocation { /// 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::Null; + 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 @@ -787,7 +787,7 @@ mod tests { let mut m = X6(Parachain(1), Parent, Parachain(2), Parent, Parachain(3), Parent); m.canonicalize(); - assert_eq!(m, Null); + assert_eq!(m, Here); let mut m = X5(Parachain(1), Parent, Parent, Parent, Parachain(3)); m.canonicalize(); @@ -795,7 +795,7 @@ mod tests { let mut m = X4(Parachain(1), Parachain(2), Parent, Parent); m.canonicalize(); - assert_eq!(m, Null); + assert_eq!(m, Here); let mut m = X4(Parent, Parent, Parachain(1), Parachain(2)); m.canonicalize(); diff --git a/xcm/src/v1/order.rs b/xcm/src/v1/order.rs index aed5a6ff3634..61d3530d8c45 100644 --- a/xcm/src/v1/order.rs +++ b/xcm/src/v1/order.rs @@ -40,15 +40,16 @@ pub enum Order<Call> { /// Errors: #[codec(index = 1)] // TODO: https://github.com/paritytech/polkadot/issues/3547 introduce `, max_assets: u32` - DepositAsset { assets: MultiAssetFilter, dest: MultiLocation }, + DepositAsset { assets: MultiAssetFilter, beneficiary: MultiLocation }, /// Remove the asset(s) (`assets`) from holding and place equivalent assets under the ownership of `dest` within - /// this consensus system. + /// this consensus system (i.e. its sovereign account). /// /// Send an onward XCM message to `dest` of `ReserveAssetDeposited` with the given `effects`. /// /// - `assets`: The asset(s) to remove from holding. - /// - `dest`: The new owner for the assets. + /// - `dest`: The location whose sovereign account will own the assets and thus the effective beneficiary for the + /// assets and the notification target for the reserve asset deposit message. /// - `effects`: The orders that should be contained in the `ReserveAssetDeposited` which is sent onwards to /// `dest`. /// @@ -84,12 +85,16 @@ pub enum Order<Call> { effects: Vec<Order<()>>, }, - /// Remove the asset(s) (`assets`) from holding and send a `TeleportAsset` XCM message to a destination location. + /// Remove the asset(s) (`assets`) from holding and send a `ReceiveTeleportedAsset` XCM message to a `destination` + /// location. /// /// - `assets`: The asset(s) to remove from holding. /// - `destination`: A valid location that has a bi-lateral teleportation arrangement. /// - `effects`: The orders to execute on the assets once arrived *on the destination location*. /// + /// NOTE: The `destination` location *MUST* respect this origin as a valid teleportation origin for all `assets`. + /// If it does not, then the assets may be lost. + /// /// Errors: #[codec(index = 5)] InitiateTeleport { assets: MultiAssetFilter, dest: MultiLocation, effects: Vec<Order<()>> }, @@ -139,7 +144,7 @@ impl<Call> Order<Call> { use Order::*; match order { Noop => Noop, - DepositAsset { assets, dest } => DepositAsset { assets, dest }, + DepositAsset { assets, beneficiary } => DepositAsset { assets, beneficiary }, DepositReserveAsset { assets, dest, effects } => DepositReserveAsset { assets, dest, effects }, ExchangeAsset { give, receive } => ExchangeAsset { give, receive }, diff --git a/xcm/xcm-builder/src/barriers.rs b/xcm/xcm-builder/src/barriers.rs index f253be18026f..ec1b5d0c7f63 100644 --- a/xcm/xcm-builder/src/barriers.rs +++ b/xcm/xcm-builder/src/barriers.rs @@ -51,7 +51,7 @@ impl<T: Contains<MultiLocation>> ShouldExecute for AllowTopLevelPaidExecutionFro ensure!(T::contains(origin), ()); ensure!(top_level, ()); match message { - Xcm::TeleportAsset { effects, .. } | + Xcm::ReceiveTeleportedAsset { effects, .. } | Xcm::WithdrawAsset { effects, .. } | Xcm::ReserveAssetDeposited { effects, .. } if matches!( diff --git a/xcm/xcm-builder/src/mock.rs b/xcm/xcm-builder/src/mock.rs index c8d6036577e7..af568a5fc8de 100644 --- a/xcm/xcm-builder/src/mock.rs +++ b/xcm/xcm-builder/src/mock.rs @@ -152,7 +152,7 @@ pub fn to_account(l: MultiLocation) -> Result<u64, MultiLocation> { // Children at 1000+id X1(Parachain(id)) => 1000 + id as u64, // Self at 3000 - Null => 3000, + Here => 3000, // Parent at 3001 X1(Parent) => 3001, l => return Err(l), @@ -251,7 +251,7 @@ parameter_types! { pub static AllowUnpaidFrom: Vec<MultiLocation> = vec![]; pub static AllowPaidFrom: Vec<MultiLocation> = vec![]; // 1_000_000_000_000 => 1 unit of asset for 1 unit of Weight. - pub static WeightPrice: (AssetId, u128) = (Null.into(), 1_000_000_000_000); + pub static WeightPrice: (AssetId, u128) = (Here.into(), 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 2cc343694fa9..1432738263cd 100644 --- a/xcm/xcm-builder/src/origin_conversion.rs +++ b/xcm/xcm-builder/src/origin_conversion.rs @@ -170,7 +170,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::Null) + Ok(MultiLocation::Here) } else { Err(o) } diff --git a/xcm/xcm-builder/src/tests.rs b/xcm/xcm-builder/src/tests.rs index 93c87ce5dad5..3c66ff705eac 100644 --- a/xcm/xcm-builder/src/tests.rs +++ b/xcm/xcm-builder/src/tests.rs @@ -32,7 +32,7 @@ fn basic_setup_works() { 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(Null), Ok(3000)); + assert_eq!(to_account(Here), Ok(3000)); } #[test] @@ -47,7 +47,7 @@ fn weigher_should_work() { halt_on_error: true, xcm: vec![], }, - Order::DepositAsset { assets: All.into(), dest: Null }, + Order::DepositAsset { assets: All.into(), beneficiary: Here }, ], } .into(); @@ -56,7 +56,7 @@ fn weigher_should_work() { #[test] fn take_weight_credit_barrier_should_work() { - let mut message = opaque::Xcm::TransferAsset { assets: (X1(Parent), 100).into(), dest: Null }; + let mut message = opaque::Xcm::TransferAsset { assets: (X1(Parent), 100).into(), beneficiary: Here }; let mut weight_credit = 10; let r = @@ -72,7 +72,7 @@ fn take_weight_credit_barrier_should_work() { #[test] fn allow_unpaid_should_work() { - let mut message = opaque::Xcm::TransferAsset { assets: (X1(Parent), 100).into(), dest: Null }; + let mut message = opaque::Xcm::TransferAsset { assets: (X1(Parent), 100).into(), beneficiary: Here }; AllowUnpaidFrom::set(vec![X1(Parent)]); @@ -99,7 +99,7 @@ fn allow_unpaid_should_work() { fn allow_paid_should_work() { AllowPaidFrom::set(vec![X1(Parent)]); - let mut message = opaque::Xcm::TransferAsset { assets: (X1(Parent), 100).into(), dest: Null }; + let mut message = opaque::Xcm::TransferAsset { assets: (X1(Parent), 100).into(), beneficiary: Here }; let r = AllowTopLevelPaidExecutionFrom::<IsInVec<AllowPaidFrom>>::should_execute( &X1(Parachain(1)), @@ -115,7 +115,7 @@ fn allow_paid_should_work() { assets: (X1(Parent), 100).into(), effects: vec![ Order::BuyExecution { fees, weight: 0, debt: 20, halt_on_error: true, xcm: vec![] }, - Order::DepositAsset { assets: All.into(), dest: Null }, + Order::DepositAsset { assets: All.into(), beneficiary: Here }, ], }; @@ -133,7 +133,7 @@ fn allow_paid_should_work() { assets: (X1(Parent), 100).into(), effects: vec![ Order::BuyExecution { fees, weight: 0, debt: 30, halt_on_error: true, xcm: vec![] }, - Order::DepositAsset { assets: All.into(), dest: Null }, + Order::DepositAsset { assets: All.into(), beneficiary: Here }, ], }; @@ -159,8 +159,8 @@ fn allow_paid_should_work() { #[test] fn paying_reserve_deposit_should_work() { AllowPaidFrom::set(vec![X1(Parent)]); - add_reserve(X1(Parent), (X1(Parent), WildFungible).into()); - WeightPrice::set((X1(Parent).into(), 1_000_000_000_000)); + add_reserve(X1(Parent), (Parent, WildFungible).into()); + WeightPrice::set((Parent.into(), 1_000_000_000_000)); let origin = X1(Parent); let fees = (X1(Parent), 30).into(); @@ -174,7 +174,7 @@ fn paying_reserve_deposit_should_work() { halt_on_error: true, xcm: vec![], }, - Order::<TestCall>::DepositAsset { assets: All.into(), dest: Null }, + Order::<TestCall>::DepositAsset { assets: All.into(), beneficiary: Here }, ], }; let weight_limit = 50; @@ -188,19 +188,19 @@ fn transfer_should_work() { // we'll let them have message execution for free. AllowUnpaidFrom::set(vec![X1(Parachain(1))]); // Child parachain #1 owns 1000 tokens held by us in reserve. - add_asset(1001, (Null, 1000).into()); + add_asset(1001, (Here, 1000).into()); // They want to transfer 100 of them to their sibling parachain #2 let r = XcmExecutor::<TestConfig>::execute_xcm( X1(Parachain(1)), Xcm::TransferAsset { - assets: (Null, 100).into(), - dest: X1(AccountIndex64 { index: 3, network: Any }), + assets: (Here, 100).into(), + beneficiary: X1(AccountIndex64 { index: 3, network: Any }), }, 50, ); assert_eq!(r, Outcome::Complete(10)); - assert_eq!(assets(3), vec![(Null, 100).into()]); - assert_eq!(assets(1001), vec![(Null, 900).into()]); + assert_eq!(assets(3), vec![(Here, 100).into()]); + assert_eq!(assets(1001), vec![(Here, 900).into()]); assert_eq!(sent_xcm(), vec![]); } @@ -208,7 +208,7 @@ fn transfer_should_work() { fn reserve_transfer_should_work() { AllowUnpaidFrom::set(vec![X1(Parachain(1))]); // Child parachain #1 owns 1000 tokens held by us in reserve. - add_asset(1001, (Null, 1000).into()); + add_asset(1001, (Here, 1000).into()); // The remote account owned by gav. let three = X1(AccountIndex64 { index: 3, network: Any }); @@ -217,22 +217,22 @@ fn reserve_transfer_should_work() { let r = XcmExecutor::<TestConfig>::execute_xcm( X1(Parachain(1)), Xcm::TransferReserveAsset { - assets: (Null, 100).into(), + assets: (Here, 100).into(), dest: X1(Parachain(2)), - effects: vec![Order::DepositAsset { assets: All.into(), dest: three.clone() }], + effects: vec![Order::DepositAsset { assets: All.into(), beneficiary: three.clone() }], }, 50, ); assert_eq!(r, Outcome::Complete(10)); - assert_eq!(assets(1002), vec![(Null, 100).into()]); + assert_eq!(assets(1002), vec![(Here, 100).into()]); assert_eq!( sent_xcm(), vec![( X1(Parachain(2)), Xcm::ReserveAssetDeposited { assets: (X1(Parent), 100).into(), - effects: vec![Order::DepositAsset { assets: All.into(), dest: three }], + effects: vec![Order::DepositAsset { assets: All.into(), beneficiary: three }], } )] ); @@ -287,8 +287,8 @@ fn transacting_should_refund_weight() { fn paid_transacting_should_refund_payment_for_unused_weight() { let one = X1(AccountIndex64 { index: 1, network: Any }); AllowPaidFrom::set(vec![one.clone()]); - add_asset(1, (X1(Parent), 100).into()); - WeightPrice::set((X1(Parent).into(), 1_000_000_000_000)); + 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(); @@ -307,7 +307,7 @@ fn paid_transacting_should_refund_payment_for_unused_weight() { call: TestCall::Any(60, Some(10)).encode().into(), }], }, - Order::<TestCall>::DepositAsset { assets: All.into(), dest: one.clone() }, + Order::<TestCall>::DepositAsset { assets: All.into(), beneficiary: one.clone() }, ], }; let weight_limit = 100; diff --git a/xcm/xcm-builder/src/weight.rs b/xcm/xcm-builder/src/weight.rs index 028ce6b061e4..5e197fee89fa 100644 --- a/xcm/xcm-builder/src/weight.rs +++ b/xcm/xcm-builder/src/weight.rs @@ -37,7 +37,7 @@ impl<T: Get<Weight>, C: Decode + GetDispatchInfo> WeightBounds<C> for FixedWeigh T::get().saturating_add(Self::shallow(message.as_mut())?), Xcm::WithdrawAsset { effects, .. } | Xcm::ReserveAssetDeposited { effects, .. } | - Xcm::TeleportAsset { effects, .. } => { + Xcm::ReceiveTeleportedAsset { effects, .. } => { let inner: Weight = effects .iter_mut() .map(|effect| match effect { @@ -62,7 +62,7 @@ impl<T: Get<Weight>, C: Decode + GetDispatchInfo> WeightBounds<C> for FixedWeigh Xcm::RelayedFrom { ref mut message, .. } => Self::deep(message.as_mut())?, Xcm::WithdrawAsset { effects, .. } | Xcm::ReserveAssetDeposited { effects, .. } | - Xcm::TeleportAsset { effects, .. } => { + Xcm::ReceiveTeleportedAsset { effects, .. } => { let mut extra = 0; for effect in effects.iter_mut() { match effect { diff --git a/xcm/xcm-executor/src/assets.rs b/xcm/xcm-executor/src/assets.rs index 5270a30d44d2..8ce2ee4e2de2 100644 --- a/xcm/xcm-executor/src/assets.rs +++ b/xcm/xcm-executor/src/assets.rs @@ -339,12 +339,12 @@ impl Assets { /// ``` /// use xcm_executor::Assets; /// use xcm::v1::prelude::*; - /// let assets_i_have: Assets = vec![ (Null, 100).into(), (vec![0], 100).into() ].into(); - /// let assets_they_want: MultiAssetFilter = vec![ (Null, 200).into(), (vec![0], 50).into() [.into(); + /// let assets_i_have: Assets = vec![ (Here, 100).into(), (vec![0], 100).into() ].into(); + /// let assets_they_want: MultiAssetFilter = vec![ (Here, 200).into(), (vec![0], 50).into() [.into(); /// /// let assets_we_can_trade: Assets = assets_i_have.min(&assets_they_want); /// assert_eq!(assets_we_can_trade.into_assets_iter().collect::<Vec<_>>(), vec![ - /// (Null, 100).into(), (vec![0], 50).into(), + /// (Here, 100).into(), (vec![0], 50).into(), /// ]); /// ``` pub fn min(&self, mask: &MultiAssetFilter) -> Assets { @@ -388,7 +388,7 @@ impl Assets { mod tests { use super::*; use xcm::v1::prelude::*; - use MultiLocation::Null; + use MultiLocation::Here; #[allow(non_snake_case)] fn AF(id: u8, amount: u128) -> MultiAsset { (vec![id], amount).into() @@ -399,11 +399,11 @@ mod tests { } #[allow(non_snake_case)] fn CF(amount: u128) -> MultiAsset { - (Null, amount).into() + (Here, amount).into() } #[allow(non_snake_case)] fn CNF(instance_id: u128) -> MultiAsset { - (Null, AssetInstance::Index { id: instance_id }).into() + (Here, AssetInstance::Index { id: instance_id }).into() } fn test_assets() -> Assets { @@ -517,8 +517,8 @@ mod tests { #[test] fn min_all_concrete_works() { let assets = test_assets(); - let fungible = Wild((Null, WildFungible).into()); - let non_fungible = Wild((Null, WildNonFungible).into()); + let fungible = Wild((Here, WildFungible).into()); + let non_fungible = Wild((Here, WildNonFungible).into()); let fungible = assets.min(&fungible); let fungible = fungible.assets_iter().collect::<Vec<_>>(); @@ -581,8 +581,8 @@ mod tests { #[test] fn saturating_take_all_concrete_works() { let mut assets = test_assets(); - let fungible = Wild((Null, WildFungible).into()); - let non_fungible = Wild((Null, WildNonFungible).into()); + let fungible = Wild((Here, WildFungible).into()); + let non_fungible = Wild((Here, WildNonFungible).into()); let fungible = assets.saturating_take(fungible); let fungible = fungible.assets_iter().collect::<Vec<_>>(); diff --git a/xcm/xcm-executor/src/lib.rs b/xcm/xcm-executor/src/lib.rs index 491558dbdb28..ed7f0b8e5053 100644 --- a/xcm/xcm-executor/src/lib.rs +++ b/xcm/xcm-executor/src/lib.rs @@ -162,10 +162,10 @@ impl<Config: config::Config> XcmExecutor<Config> { } Some((assets.into(), effects)) }, - (origin, Xcm::TransferAsset { assets, dest }) => { + (origin, Xcm::TransferAsset { assets, beneficiary }) => { // Take `assets` from the origin account (on-chain) and place into dest account. for asset in assets.inner() { - Config::AssetTransactor::beam_asset(&asset, &origin, &dest)?; + Config::AssetTransactor::beam_asset(&asset, &origin, &beneficiary)?; } None }, @@ -179,7 +179,7 @@ impl<Config: config::Config> XcmExecutor<Config> { Config::XcmSender::send_xcm(dest, Xcm::ReserveAssetDeposited { assets, effects })?; None }, - (origin, Xcm::TeleportAsset { assets, effects }) => { + (origin, Xcm::ReceiveTeleportedAsset { assets, effects }) => { // check whether we trust origin to teleport this asset to us via config trait. for asset in assets.inner() { // We only trust the origin to send us assets that they identify as their @@ -269,10 +269,10 @@ impl<Config: config::Config> XcmExecutor<Config> { ); let mut total_surplus = 0; match effect { - Order::DepositAsset { assets, dest } => { + Order::DepositAsset { assets, beneficiary } => { let deposited = holding.saturating_take(assets); for asset in deposited.into_assets_iter() { - Config::AssetTransactor::deposit_asset(&asset, &dest)?; + Config::AssetTransactor::deposit_asset(&asset, &beneficiary)?; } }, Order::DepositReserveAsset { assets, dest, effects } => { @@ -294,7 +294,7 @@ impl<Config: config::Config> XcmExecutor<Config> { Config::AssetTransactor::check_out(&origin, &asset); } let assets = Self::reanchored(assets, &dest); - Config::XcmSender::send_xcm(dest, Xcm::TeleportAsset { assets, effects })?; + Config::XcmSender::send_xcm(dest, Xcm::ReceiveTeleportedAsset { assets, effects })?; }, Order::QueryHolding { query_id, dest, assets } => { let assets = Self::reanchored(holding.min(&assets), &dest); diff --git a/xcm/xcm-executor/src/traits/transact_asset.rs b/xcm/xcm-executor/src/traits/transact_asset.rs index 60fb0508c676..a810ce173ca3 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::Null; + use MultiLocation::Here; pub struct UnimplementedTransactor; impl TransactAsset for UnimplementedTransactor {} @@ -273,7 +273,7 @@ mod tests { (UnimplementedTransactor, NotFoundTransactor, UnimplementedTransactor); assert_eq!( - MultiTransactor::deposit_asset(&(Null, 1).into(), &Null), + MultiTransactor::deposit_asset(&(Here, 1).into(), &Here), 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(&(Null, 1).into(), &Null), Ok(())); + assert_eq!(MultiTransactor::deposit_asset(&(Here, 1).into(), &Here), Ok(())); } #[test] @@ -290,7 +290,7 @@ mod tests { type MultiTransactor = (OverflowTransactor, SuccessfulTransactor); assert_eq!( - MultiTransactor::deposit_asset(&(Null, 1).into(), &Null), + MultiTransactor::deposit_asset(&(Here, 1).into(), &Here), Err(XcmError::Overflow) ); } @@ -299,6 +299,6 @@ mod tests { fn success_stops_iteration() { type MultiTransactor = (SuccessfulTransactor, OverflowTransactor); - assert_eq!(MultiTransactor::deposit_asset(&(Null, 1).into(), &Null), Ok(())); + assert_eq!(MultiTransactor::deposit_asset(&(Here, 1).into(), &Here), Ok(())); } } diff --git a/xcm/xcm-simulator/example/src/lib.rs b/xcm/xcm-simulator/example/src/lib.rs index 978795a1546e..305865508bf5 100644 --- a/xcm/xcm-simulator/example/src/lib.rs +++ b/xcm/xcm-simulator/example/src/lib.rs @@ -112,7 +112,7 @@ mod tests { ); Relay::execute_with(|| { assert_ok!(RelayChainPalletXcm::send_xcm( - Null, + Here, X1(Parachain(1)), Transact { origin_type: OriginKind::SovereignAccount, @@ -139,7 +139,7 @@ mod tests { ); ParaA::execute_with(|| { assert_ok!(ParachainPalletXcm::send_xcm( - Null, + Here, X1(Parent), Transact { origin_type: OriginKind::SovereignAccount, @@ -166,7 +166,7 @@ mod tests { ); ParaA::execute_with(|| { assert_ok!(ParachainPalletXcm::send_xcm( - Null, + Here, X2(Parent, Parachain(2)), Transact { origin_type: OriginKind::SovereignAccount, @@ -193,7 +193,7 @@ mod tests { relay_chain::Origin::signed(ALICE), X1(Parachain(1)), X1(Junction::AccountId32 { network: NetworkId::Any, id: ALICE.into() }), - (Null, 123).into(), + (Here, 123).into(), 123, )); }); diff --git a/xcm/xcm-simulator/example/src/relay_chain.rs b/xcm/xcm-simulator/example/src/relay_chain.rs index 7472df198219..e691e3e7ad35 100644 --- a/xcm/xcm-simulator/example/src/relay_chain.rs +++ b/xcm/xcm-simulator/example/src/relay_chain.rs @@ -91,10 +91,10 @@ impl shared::Config for Runtime {} impl configuration::Config for Runtime {} parameter_types! { - pub const KsmLocation: MultiLocation = MultiLocation::Null; + pub const KsmLocation: MultiLocation = MultiLocation::Here; pub const KusamaNetwork: NetworkId = NetworkId::Kusama; pub const AnyNetwork: NetworkId = NetworkId::Any; - pub Ancestry: MultiLocation = MultiLocation::Null; + pub Ancestry: MultiLocation = MultiLocation::Here; pub UnitWeightCost: Weight = 1_000; } From e9dbc72d84f15711d3b03d7daedb77559a2f8d31 Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Wed, 4 Aug 2021 12:32:43 +0200 Subject: [PATCH 073/166] Introduce --- xcm/src/lib.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/xcm/src/lib.rs b/xcm/src/lib.rs index f9ce3a3f5266..e7d31a2a7d74 100644 --- a/xcm/src/lib.rs +++ b/xcm/src/lib.rs @@ -29,6 +29,10 @@ use parity_scale_codec::{Decode, Encode, Error as CodecError, Input}; pub mod v1; +pub mod latest { + pub use super::v1::*; +} + mod double_encoded; pub use double_encoded::DoubleEncoded; @@ -75,6 +79,10 @@ pub mod opaque { pub use crate::v1::opaque::{Order, Xcm}; } + pub mod latest { + pub use super::v1::*; + } + /// The basic `VersionedXcm` type which just uses the `Vec<u8>` as an encoded call. pub type VersionedXcm = super::VersionedXcm<()>; } From 36ccb47bdc1cb1e20e45c2c6dcee4b9dac325624 Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Wed, 4 Aug 2021 13:00:12 +0200 Subject: [PATCH 074/166] More ergonomics --- xcm/src/v1/multiasset.rs | 53 +++++++++++++++++++++---- xcm/xcm-executor/src/assets.rs | 70 +++++++++++++++++----------------- 2 files changed, 81 insertions(+), 42 deletions(-) diff --git a/xcm/src/v1/multiasset.rs b/xcm/src/v1/multiasset.rs index 5716a7b5c980..cc0672b2d2d8 100644 --- a/xcm/src/v1/multiasset.rs +++ b/xcm/src/v1/multiasset.rs @@ -39,10 +39,7 @@ pub enum AssetInstance { /// A compact index. Technically this could be greater than `u128`, but this implementation supports only /// values up to `2**128 - 1`. - Index { - #[codec(compact)] - id: u128, - }, + Index(#[codec(compact)] u128), /// A 4-byte fixed-length datum. Array4([u8; 4]), @@ -60,6 +57,48 @@ pub enum AssetInstance { Blob(Vec<u8>), } +impl From<()> for AssetInstance { + fn from(_: ()) -> Self { + Self::Undefined + } +} + +/*impl From<u128> for AssetInstance { + fn from(x: u128) -> Self { + Self::Index(x) + } +}*/ + +impl From<[u8; 4]> for AssetInstance { + fn from(x: [u8; 4]) -> Self { + Self::Array4(x) + } +} + +impl From<[u8; 8]> for AssetInstance { + fn from(x: [u8; 8]) -> Self { + Self::Array8(x) + } +} + +impl From<[u8; 16]> for AssetInstance { + fn from(x: [u8; 16]) -> Self { + Self::Array16(x) + } +} + +impl From<[u8; 32]> for AssetInstance { + fn from(x: [u8; 32]) -> Self { + Self::Array32(x) + } +} + +impl From<Vec<u8>> for AssetInstance { + fn from(x: Vec<u8>) -> Self { + Self::Blob(x) + } +} + /// Classification of an asset being concrete or abstract. #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, Decode)] pub enum AssetId { @@ -128,9 +167,9 @@ impl From<u128> for Fungibility { } } -impl From<AssetInstance> for Fungibility { - fn from(instance: AssetInstance) -> Fungibility { - Fungibility::NonFungible(instance) +impl<T: Into<AssetInstance>> From<T> for Fungibility { + fn from(instance: T) -> Fungibility { + Fungibility::NonFungible(instance.into()) } } diff --git a/xcm/xcm-executor/src/assets.rs b/xcm/xcm-executor/src/assets.rs index 8ce2ee4e2de2..fb9394d22d1d 100644 --- a/xcm/xcm-executor/src/assets.rs +++ b/xcm/xcm-executor/src/assets.rs @@ -394,24 +394,24 @@ mod tests { (vec![id], amount).into() } #[allow(non_snake_case)] - fn ANF(class: u8, instance_id: u128) -> MultiAsset { - (vec![class], AssetInstance::Index { id: instance_id }).into() + fn ANF(class: u8, instance_id: u8) -> MultiAsset { + (vec![class], vec![instance_id]).into() } #[allow(non_snake_case)] fn CF(amount: u128) -> MultiAsset { (Here, amount).into() } #[allow(non_snake_case)] - fn CNF(instance_id: u128) -> MultiAsset { - (Here, AssetInstance::Index { id: instance_id }).into() + fn CNF(instance_id: u8) -> MultiAsset { + (Here, [instance_id; 4]).into() } fn test_assets() -> Assets { let mut assets = Assets::new(); assets.subsume(AF(1, 100)); - assets.subsume(ANF(2, 200)); + assets.subsume(ANF(2, 20)); assets.subsume(CF(300)); - assets.subsume(CNF(400)); + assets.subsume(CNF(40)); assets } @@ -420,9 +420,9 @@ mod tests { let t1 = test_assets(); let mut t2 = Assets::new(); t2.subsume(AF(1, 50)); - t2.subsume(ANF(2, 100)); + t2.subsume(ANF(2, 10)); t2.subsume(CF(300)); - t2.subsume(CNF(500)); + t2.subsume(CNF(50)); let mut r1 = t1.clone(); r1.subsume_assets(t2.clone()); let mut r2 = t1.clone(); @@ -443,12 +443,12 @@ mod tests { let t = t.checked_sub(CF(151)).unwrap_err(); let t = t.checked_sub(CF(150)).unwrap(); let t = t.checked_sub(CF(1)).unwrap_err(); - let t = t.checked_sub(ANF(2, 201)).unwrap_err(); - let t = t.checked_sub(ANF(2, 200)).unwrap(); - let t = t.checked_sub(ANF(2, 200)).unwrap_err(); - let t = t.checked_sub(CNF(401)).unwrap_err(); - let t = t.checked_sub(CNF(400)).unwrap(); - let t = t.checked_sub(CNF(400)).unwrap_err(); + let t = t.checked_sub(ANF(2, 21)).unwrap_err(); + let t = t.checked_sub(ANF(2, 20)).unwrap(); + let t = t.checked_sub(ANF(2, 20)).unwrap_err(); + let t = t.checked_sub(CNF(41)).unwrap_err(); + let t = t.checked_sub(CNF(40)).unwrap(); + let t = t.checked_sub(CNF(40)).unwrap_err(); assert_eq!(t, Assets::new()); } @@ -459,8 +459,8 @@ mod tests { // Order defined by implementation: CF, AF, CNF, ANF assert_eq!(Some(CF(300)), iter.next()); assert_eq!(Some(AF(1, 100)), iter.next()); - assert_eq!(Some(CNF(400)), iter.next()); - assert_eq!(Some(ANF(2, 200)), iter.next()); + assert_eq!(Some(CNF(40)), iter.next()); + assert_eq!(Some(ANF(2, 20)), iter.next()); assert_eq!(None, iter.next()); } @@ -468,14 +468,14 @@ mod tests { fn assets_into_works() { let mut assets_vec: Vec<MultiAsset> = Vec::new(); assets_vec.push(AF(1, 100)); - assets_vec.push(ANF(2, 200)); + assets_vec.push(ANF(2, 20)); assets_vec.push(CF(300)); - assets_vec.push(CNF(400)); + assets_vec.push(CNF(40)); // Push same group of tokens again assets_vec.push(AF(1, 100)); - assets_vec.push(ANF(2, 200)); + assets_vec.push(ANF(2, 20)); assets_vec.push(CF(300)); - assets_vec.push(CNF(400)); + assets_vec.push(CNF(40)); let assets: Assets = assets_vec.into(); let mut iter = assets.into_assets_iter(); @@ -483,8 +483,8 @@ mod tests { assert_eq!(Some(CF(600)), iter.next()); assert_eq!(Some(AF(1, 200)), iter.next()); // Non-fungibles collapse - assert_eq!(Some(CNF(400)), iter.next()); - assert_eq!(Some(ANF(2, 200)), iter.next()); + assert_eq!(Some(CNF(40)), iter.next()); + assert_eq!(Some(ANF(2, 20)), iter.next()); assert_eq!(None, iter.next()); } @@ -511,7 +511,7 @@ mod tests { assert_eq!(fungible, vec![AF(1, 100)]); let non_fungible = assets.min(&non_fungible); let non_fungible = non_fungible.assets_iter().collect::<Vec<_>>(); - assert_eq!(non_fungible, vec![ANF(2, 200)]); + assert_eq!(non_fungible, vec![ANF(2, 20)]); } #[test] @@ -525,7 +525,7 @@ mod tests { assert_eq!(fungible, vec![CF(300)]); let non_fungible = assets.min(&non_fungible); let non_fungible = non_fungible.assets_iter().collect::<Vec<_>>(); - assert_eq!(non_fungible, vec![CNF(400)]); + assert_eq!(non_fungible, vec![CNF(40)]); } #[test] @@ -536,16 +536,16 @@ mod tests { // This is less than 100, so it will decrease to 50 assets2.subsume(AF(1, 50)); // This asset does not exist, so not included - assets2.subsume(ANF(2, 400)); + assets2.subsume(ANF(2, 40)); // This is more then 300, so it should stay at 300 assets2.subsume(CF(600)); // This asset should be included - assets2.subsume(CNF(400)); + assets2.subsume(CNF(40)); let assets2: MultiAssets = assets2.into(); let assets_min = assets1.min(&assets2.into()); let assets_min = assets_min.into_assets_iter().collect::<Vec<_>>(); - assert_eq!(assets_min, vec![CF(300), AF(1, 50), CNF(400)]); + assert_eq!(assets_min, vec![CF(300), AF(1, 50), CNF(40)]); } #[test] @@ -572,10 +572,10 @@ mod tests { assert_eq!(fungible, vec![AF(1, 100)]); let non_fungible = assets.saturating_take(non_fungible); let non_fungible = non_fungible.assets_iter().collect::<Vec<_>>(); - assert_eq!(non_fungible, vec![ANF(2, 200)]); + assert_eq!(non_fungible, vec![ANF(2, 20)]); // Assets drained of abstract let final_assets = assets.assets_iter().collect::<Vec<_>>(); - assert_eq!(final_assets, vec![CF(300), CNF(400)]); + assert_eq!(final_assets, vec![CF(300), CNF(40)]); } #[test] @@ -589,10 +589,10 @@ mod tests { assert_eq!(fungible, vec![CF(300)]); let non_fungible = assets.saturating_take(non_fungible); let non_fungible = non_fungible.assets_iter().collect::<Vec<_>>(); - assert_eq!(non_fungible, vec![CNF(400)]); + assert_eq!(non_fungible, vec![CNF(40)]); // Assets drained of concrete let assets = assets.assets_iter().collect::<Vec<_>>(); - assert_eq!(assets, vec![AF(1, 100), ANF(2, 200)]); + assert_eq!(assets, vec![AF(1, 100), ANF(2, 20)]); } #[test] @@ -603,18 +603,18 @@ mod tests { // We should take 50 assets2.subsume(AF(1, 50)); // This asset should not be taken - assets2.subsume(ANF(2, 400)); + assets2.subsume(ANF(2, 40)); // This is more then 300, so it takes everything assets2.subsume(CF(600)); // This asset should be taken - assets2.subsume(CNF(400)); + assets2.subsume(CNF(40)); let assets2: MultiAssets = assets2.into(); let taken = assets1.saturating_take(assets2.into()); let taken = taken.into_assets_iter().collect::<Vec<_>>(); - assert_eq!(taken, vec![CF(300), AF(1, 50), CNF(400)]); + assert_eq!(taken, vec![CF(300), AF(1, 50), CNF(40)]); let assets = assets1.into_assets_iter().collect::<Vec<_>>(); - assert_eq!(assets, vec![AF(1, 50), ANF(2, 200)]); + assert_eq!(assets, vec![AF(1, 50), ANF(2, 20)]); } } From de33d7d1cc392a16f47989a727520de3fbd32478 Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Wed, 4 Aug 2021 13:00:20 +0200 Subject: [PATCH 075/166] More ergonomics --- xcm/pallet-xcm/src/tests.rs | 10 ++++++++-- xcm/src/v1/mod.rs | 6 ++++-- xcm/xcm-builder/src/tests.rs | 9 ++++++--- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/xcm/pallet-xcm/src/tests.rs b/xcm/pallet-xcm/src/tests.rs index 0e8b086e8290..9285817c5270 100644 --- a/xcm/pallet-xcm/src/tests.rs +++ b/xcm/pallet-xcm/src/tests.rs @@ -157,7 +157,10 @@ fn reserve_transfer_assets_works() { Parachain(PARA_ID).into(), Xcm::ReserveAssetDeposited { assets: (X1(Parent), SEND_AMOUNT).into(), - effects: vec![buy_execution(weight), DepositAsset { assets: Wild(All), beneficiary: dest },] + effects: vec![ + buy_execution(weight), + DepositAsset { assets: Wild(All), beneficiary: dest }, + ] } )] ); @@ -185,7 +188,10 @@ fn execute_withdraw_to_deposit_works() { Origin::signed(ALICE), Box::new(Xcm::WithdrawAsset { assets: (Here, SEND_AMOUNT).into(), - effects: vec![buy_execution(weight), DepositAsset { assets: Wild(All), beneficiary: dest }], + effects: vec![ + buy_execution(weight), + DepositAsset { assets: Wild(All), beneficiary: dest } + ], }), weight )); diff --git a/xcm/src/v1/mod.rs b/xcm/src/v1/mod.rs index 5f7bae368d85..c27bb1788069 100644 --- a/xcm/src/v1/mod.rs +++ b/xcm/src/v1/mod.rs @@ -304,8 +304,10 @@ impl<Call> Xcm<Call> { assets, effects: effects.into_iter().map(Order::into).collect(), }, - ReceiveTeleportedAsset { assets, effects } => - ReceiveTeleportedAsset { assets, effects: effects.into_iter().map(Order::into).collect() }, + ReceiveTeleportedAsset { assets, effects } => ReceiveTeleportedAsset { + assets, + effects: effects.into_iter().map(Order::into).collect(), + }, QueryResponse { query_id: u64, response } => QueryResponse { query_id: u64, response }, TransferAsset { assets, beneficiary } => TransferAsset { assets, beneficiary }, TransferReserveAsset { assets, dest, effects } => diff --git a/xcm/xcm-builder/src/tests.rs b/xcm/xcm-builder/src/tests.rs index 3c66ff705eac..f918fb67124e 100644 --- a/xcm/xcm-builder/src/tests.rs +++ b/xcm/xcm-builder/src/tests.rs @@ -56,7 +56,8 @@ 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 }; + let mut message = + opaque::Xcm::TransferAsset { assets: (X1(Parent), 100).into(), beneficiary: Here }; let mut weight_credit = 10; let r = @@ -72,7 +73,8 @@ 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 }; + let mut message = + opaque::Xcm::TransferAsset { assets: (X1(Parent), 100).into(), beneficiary: Here }; AllowUnpaidFrom::set(vec![X1(Parent)]); @@ -99,7 +101,8 @@ fn allow_unpaid_should_work() { fn allow_paid_should_work() { AllowPaidFrom::set(vec![X1(Parent)]); - let mut message = opaque::Xcm::TransferAsset { assets: (X1(Parent), 100).into(), beneficiary: Here }; + let mut message = + opaque::Xcm::TransferAsset { assets: (X1(Parent), 100).into(), beneficiary: Here }; let r = AllowTopLevelPaidExecutionFrom::<IsInVec<AllowPaidFrom>>::should_execute( &X1(Parachain(1)), From 7ff049359905c9bd54e018e97d01bebcd5459f11 Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Wed, 4 Aug 2021 14:42:05 +0200 Subject: [PATCH 076/166] test fix --- xcm/xcm-simulator/example/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xcm/xcm-simulator/example/src/lib.rs b/xcm/xcm-simulator/example/src/lib.rs index 305865508bf5..12e39a51e30f 100644 --- a/xcm/xcm-simulator/example/src/lib.rs +++ b/xcm/xcm-simulator/example/src/lib.rs @@ -192,7 +192,7 @@ mod tests { assert_ok!(RelayChainPalletXcm::reserve_transfer_assets( relay_chain::Origin::signed(ALICE), X1(Parachain(1)), - X1(Junction::AccountId32 { network: NetworkId::Any, id: ALICE.into() }), + X1(AccountId32 { network: Any, id: ALICE.into() }), (Here, 123).into(), 123, )); From 84c44f8244732e3fbf499a5ce54806aa42191ad2 Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Wed, 4 Aug 2021 14:48:47 +0200 Subject: [PATCH 077/166] test fixes --- xcm/pallet-xcm/src/tests.rs | 8 ++++---- xcm/xcm-builder/src/tests.rs | 14 +++++++------- xcm/xcm-executor/src/lib.rs | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/xcm/pallet-xcm/src/tests.rs b/xcm/pallet-xcm/src/tests.rs index 9285817c5270..dd86ca3a05e0 100644 --- a/xcm/pallet-xcm/src/tests.rs +++ b/xcm/pallet-xcm/src/tests.rs @@ -43,7 +43,7 @@ fn send_works() { assets: (X1(Parent), SEND_AMOUNT).into(), effects: vec![ buy_execution(weight), - DepositAsset { assets: Wild(All), beneficiary: sender.clone() }, + DepositAsset { assets: All.into(), max_assets: 1, beneficiary: sender.clone() }, ], }; assert_ok!(XcmPallet::send(Origin::signed(ALICE), RelayLocation::get(), message.clone())); @@ -77,7 +77,7 @@ fn send_fails_when_xcm_router_blocks() { assets: (Parent, SEND_AMOUNT).into(), effects: vec![ buy_execution(weight), - DepositAsset { assets: Wild(All), beneficiary: sender.clone() }, + DepositAsset { assets: All.into(), max_assets: 1, beneficiary: sender.clone() }, ], }; assert_noop!( @@ -159,7 +159,7 @@ fn reserve_transfer_assets_works() { assets: (X1(Parent), SEND_AMOUNT).into(), effects: vec![ buy_execution(weight), - DepositAsset { assets: Wild(All), beneficiary: dest }, + DepositAsset { assets: All.into(), max_assets: 1, beneficiary: dest }, ] } )] @@ -190,7 +190,7 @@ fn execute_withdraw_to_deposit_works() { assets: (Here, SEND_AMOUNT).into(), effects: vec![ buy_execution(weight), - DepositAsset { assets: Wild(All), beneficiary: dest } + DepositAsset { assets: All.into(), max_assets: 1, beneficiary: dest } ], }), weight diff --git a/xcm/xcm-builder/src/tests.rs b/xcm/xcm-builder/src/tests.rs index f918fb67124e..86ad5ccc7720 100644 --- a/xcm/xcm-builder/src/tests.rs +++ b/xcm/xcm-builder/src/tests.rs @@ -47,7 +47,7 @@ fn weigher_should_work() { halt_on_error: true, xcm: vec![], }, - Order::DepositAsset { assets: All.into(), beneficiary: Here }, + Order::DepositAsset { assets: All.into(), max_assets: 1, beneficiary: Here }, ], } .into(); @@ -118,7 +118,7 @@ fn allow_paid_should_work() { assets: (X1(Parent), 100).into(), effects: vec![ Order::BuyExecution { fees, weight: 0, debt: 20, halt_on_error: true, xcm: vec![] }, - Order::DepositAsset { assets: All.into(), beneficiary: Here }, + Order::DepositAsset { assets: All.into(), max_assets: 1, beneficiary: Here }, ], }; @@ -136,7 +136,7 @@ fn allow_paid_should_work() { assets: (X1(Parent), 100).into(), effects: vec![ Order::BuyExecution { fees, weight: 0, debt: 30, halt_on_error: true, xcm: vec![] }, - Order::DepositAsset { assets: All.into(), beneficiary: Here }, + Order::DepositAsset { assets: All.into(), max_assets: 1, beneficiary: Here }, ], }; @@ -177,7 +177,7 @@ fn paying_reserve_deposit_should_work() { halt_on_error: true, xcm: vec![], }, - Order::<TestCall>::DepositAsset { assets: All.into(), beneficiary: Here }, + Order::<TestCall>::DepositAsset { assets: All.into(), max_assets: 1, beneficiary: Here }, ], }; let weight_limit = 50; @@ -222,7 +222,7 @@ fn reserve_transfer_should_work() { Xcm::TransferReserveAsset { assets: (Here, 100).into(), dest: X1(Parachain(2)), - effects: vec![Order::DepositAsset { assets: All.into(), beneficiary: three.clone() }], + effects: vec![Order::DepositAsset { assets: All.into(), max_assets: 1, beneficiary: three.clone() }], }, 50, ); @@ -235,7 +235,7 @@ fn reserve_transfer_should_work() { X1(Parachain(2)), Xcm::ReserveAssetDeposited { assets: (X1(Parent), 100).into(), - effects: vec![Order::DepositAsset { assets: All.into(), beneficiary: three }], + effects: vec![Order::DepositAsset { assets: All.into(), max_assets: 1, beneficiary: three }], } )] ); @@ -310,7 +310,7 @@ fn paid_transacting_should_refund_payment_for_unused_weight() { call: TestCall::Any(60, Some(10)).encode().into(), }], }, - Order::<TestCall>::DepositAsset { assets: All.into(), beneficiary: one.clone() }, + Order::<TestCall>::DepositAsset { assets: All.into(), max_assets: 1, beneficiary: one.clone() }, ], }; let weight_limit = 100; diff --git a/xcm/xcm-executor/src/lib.rs b/xcm/xcm-executor/src/lib.rs index e01f8ebbd0a7..e59aa54a1fd8 100644 --- a/xcm/xcm-executor/src/lib.rs +++ b/xcm/xcm-executor/src/lib.rs @@ -270,7 +270,7 @@ impl<Config: config::Config> XcmExecutor<Config> { let mut total_surplus = 0; match effect { Order::DepositAsset { assets, max_assets, beneficiary } => { - let deposited = holding.limited_saturating_take(assets, max_assets); + let deposited = holding.limited_saturating_take(assets, max_assets as usize); for asset in deposited.into_assets_iter() { Config::AssetTransactor::deposit_asset(&asset, &beneficiary)?; } From 7d52b93684791097df80d0a44f16801397a00659 Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Wed, 4 Aug 2021 14:59:56 +0200 Subject: [PATCH 078/166] docs --- xcm/src/v1/order.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/xcm/src/v1/order.rs b/xcm/src/v1/order.rs index f17b12357a7d..b9f1c6afd2b2 100644 --- a/xcm/src/v1/order.rs +++ b/xcm/src/v1/order.rs @@ -31,11 +31,14 @@ pub enum Order<Call> { #[codec(index = 0)] Noop, - /// Remove the asset(s) (`assets`) from holding and place equivalent assets under the ownership of `dest` within - /// this consensus system. + /// Remove the asset(s) (`assets`) from holding and place equivalent assets under the ownership of `beneficiary` + /// within this consensus system. /// /// - `assets`: The asset(s) to remove from holding. - /// - `dest`: The new owner for the assets. + /// - `max_assets`: The maximum number of unique assets/asset instances to remove from holding. Only the first + /// `max_assets` assets/instances of those matched by `assets` will be removed, prioritised under standard asset + /// ordering. Any others will remain in holding. + /// - `beneficiary`: The new owner for the assets. /// /// Errors: #[codec(index = 1)] @@ -47,6 +50,9 @@ pub enum Order<Call> { /// Send an onward XCM message to `dest` of `ReserveAssetDeposited` with the given `effects`. /// /// - `assets`: The asset(s) to remove from holding. + /// - `max_assets`: The maximum number of unique assets/asset instances to remove from holding. Only the first + /// `max_assets` assets/instances of those matched by `assets` will be removed, prioritised under standard asset + /// ordering. Any others will remain in holding. /// - `dest`: The location whose sovereign account will own the assets and thus the effective beneficiary for the /// assets and the notification target for the reserve asset deposit message. /// - `effects`: The orders that should be contained in the `ReserveAssetDeposited` which is sent onwards to From 51c7d0554c4822df1b9bc7122c92da5ba9f19fe9 Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Wed, 4 Aug 2021 15:43:04 +0200 Subject: [PATCH 079/166] BuyExecution includes --- xcm/pallet-xcm/src/lib.rs | 6 ++- xcm/pallet-xcm/src/mock.rs | 3 +- xcm/src/v1/order.rs | 35 +++++++++++++----- xcm/xcm-builder/src/tests.rs | 37 ++++++++++++++----- xcm/xcm-builder/src/weight.rs | 67 +++++++++++++++++++++------------- xcm/xcm-executor/src/assets.rs | 41 +++++++++++---------- xcm/xcm-executor/src/lib.rs | 30 ++++++++++----- 7 files changed, 144 insertions(+), 75 deletions(-) diff --git a/xcm/pallet-xcm/src/lib.rs b/xcm/pallet-xcm/src/lib.rs index 676c3205bd65..bbbcfe1163b3 100644 --- a/xcm/pallet-xcm/src/lib.rs +++ b/xcm/pallet-xcm/src/lib.rs @@ -163,7 +163,8 @@ pub mod pallet { weight: 0, debt: dest_weight, halt_on_error: false, - xcm: vec![], + orders: vec![], + instructions: vec![], }, DepositAsset { assets: Wild(All), max_assets: 1, beneficiary }, ], @@ -220,7 +221,8 @@ pub mod pallet { weight: 0, debt: dest_weight, halt_on_error: false, - xcm: vec![], + orders: vec![], + instructions: vec![], }, DepositAsset { assets: Wild(All), max_assets: 1, beneficiary }, ], diff --git a/xcm/pallet-xcm/src/mock.rs b/xcm/pallet-xcm/src/mock.rs index b3c12f9531e3..50a2471d74d7 100644 --- a/xcm/pallet-xcm/src/mock.rs +++ b/xcm/pallet-xcm/src/mock.rs @@ -201,7 +201,8 @@ pub(crate) fn buy_execution<C>(debt: Weight) -> Order<C> { weight: 0, debt, halt_on_error: false, - xcm: vec![], + orders: vec![], + instructions: vec![], } } diff --git a/xcm/src/v1/order.rs b/xcm/src/v1/order.rs index b9f1c6afd2b2..6a2b04e9acf3 100644 --- a/xcm/src/v1/order.rs +++ b/xcm/src/v1/order.rs @@ -60,7 +60,12 @@ pub enum Order<Call> { /// /// Errors: #[codec(index = 2)] - DepositReserveAsset { assets: MultiAssetFilter, max_assets: u32, dest: MultiLocation, effects: Vec<Order<()>> }, + DepositReserveAsset { + assets: MultiAssetFilter, + max_assets: u32, + dest: MultiLocation, + effects: Vec<Order<()>>, + }, /// Remove the asset(s) (`give`) from holding and replace them with alternative assets. /// @@ -120,11 +125,20 @@ pub enum Order<Call> { assets: MultiAssetFilter, }, - /// Pay for the execution of some XCM with up to `weight` picoseconds of execution time, paying for this with - /// up to `fees` from the holding register. + /// Pay for the execution of some XCM `instructions` and `orders` with up to `weight` picoseconds of execution time, + /// paying for this with up to `fees` from the Holding Register. /// /// - `fees`: The asset(s) to remove from holding to pay for fees. - /// + /// - `weight`: The amount of weight to purchase; this should be at least the shallow weight of `effects` and `xcm`. + /// - `debt`: The amount of weight-debt already incurred to be pay off; this should be equal to the unpaid weight of + /// any surrounding operations/orders. + /// - `halt_on_error`: If `true`, the execution of the `orders` and `operations` will halt on the first failure. If + /// `false`, then execution will continue regardless. + /// - `orders`: Orders to be executed with the existing Holding Register; execution of these orders happens PRIOR to + /// execution of the `operations`. The (shallow) weight for these must be paid for with the `weight` purchased. + /// - `instructions`: XCM instructions to be executed outside of the context of the current Holding Register; + /// execution of these instructions happens AFTER the execution of the `orders`. The (shallow) weight for these + /// must be paid for with the `weight` purchased. /// Errors: #[codec(index = 7)] BuyExecution { @@ -132,7 +146,8 @@ pub enum Order<Call> { weight: u64, debt: u64, halt_on_error: bool, - xcm: Vec<Xcm<Call>>, + orders: Vec<Order<Call>>, + instructions: Vec<Xcm<Call>>, }, } @@ -148,7 +163,8 @@ impl<Call> Order<Call> { use Order::*; match order { Noop => Noop, - DepositAsset { assets, max_assets, beneficiary } => DepositAsset { assets, max_assets, beneficiary }, + DepositAsset { assets, max_assets, beneficiary } => + DepositAsset { assets, max_assets, beneficiary }, DepositReserveAsset { assets, max_assets, dest, effects } => DepositReserveAsset { assets, max_assets, dest, effects }, ExchangeAsset { give, receive } => ExchangeAsset { give, receive }, @@ -157,9 +173,10 @@ impl<Call> Order<Call> { InitiateTeleport { assets, dest, effects } => InitiateTeleport { assets, dest, effects }, QueryHolding { query_id, dest, assets } => QueryHolding { query_id, dest, assets }, - BuyExecution { fees, weight, debt, halt_on_error, xcm } => { - let xcm = xcm.into_iter().map(Xcm::from).collect(); - BuyExecution { fees, weight, debt, halt_on_error, xcm } + BuyExecution { fees, weight, debt, halt_on_error, orders, instructions } => { + let orders = orders.into_iter().map(Order::from).collect(); + let instructions = instructions.into_iter().map(Xcm::from).collect(); + BuyExecution { fees, weight, debt, halt_on_error, orders, instructions } }, } } diff --git a/xcm/xcm-builder/src/tests.rs b/xcm/xcm-builder/src/tests.rs index 86ad5ccc7720..0f250ddbb954 100644 --- a/xcm/xcm-builder/src/tests.rs +++ b/xcm/xcm-builder/src/tests.rs @@ -45,7 +45,8 @@ fn weigher_should_work() { weight: 0, debt: 30, halt_on_error: true, - xcm: vec![], + orders: vec![], + instructions: vec![], }, Order::DepositAsset { assets: All.into(), max_assets: 1, beneficiary: Here }, ], @@ -117,7 +118,7 @@ fn allow_paid_should_work() { let mut underpaying_message = opaque::Xcm::ReserveAssetDeposited { assets: (X1(Parent), 100).into(), effects: vec![ - Order::BuyExecution { fees, weight: 0, debt: 20, halt_on_error: true, xcm: vec![] }, + Order::BuyExecution { fees, weight: 0, debt: 20, halt_on_error: true, orders: vec![], instructions: vec![] }, Order::DepositAsset { assets: All.into(), max_assets: 1, beneficiary: Here }, ], }; @@ -135,7 +136,7 @@ fn allow_paid_should_work() { let mut paying_message = opaque::Xcm::ReserveAssetDeposited { assets: (X1(Parent), 100).into(), effects: vec![ - Order::BuyExecution { fees, weight: 0, debt: 30, halt_on_error: true, xcm: vec![] }, + Order::BuyExecution { fees, weight: 0, debt: 30, halt_on_error: true, orders: vec![], instructions: vec![] }, Order::DepositAsset { assets: All.into(), max_assets: 1, beneficiary: Here }, ], }; @@ -175,9 +176,14 @@ fn paying_reserve_deposit_should_work() { weight: 0, debt: 30, halt_on_error: true, - xcm: vec![], + orders: vec![], + instructions: vec![], + }, + Order::<TestCall>::DepositAsset { + assets: All.into(), + max_assets: 1, + beneficiary: Here, }, - Order::<TestCall>::DepositAsset { assets: All.into(), max_assets: 1, beneficiary: Here }, ], }; let weight_limit = 50; @@ -222,7 +228,11 @@ fn reserve_transfer_should_work() { Xcm::TransferReserveAsset { assets: (Here, 100).into(), dest: X1(Parachain(2)), - effects: vec![Order::DepositAsset { assets: All.into(), max_assets: 1, beneficiary: three.clone() }], + effects: vec![Order::DepositAsset { + assets: All.into(), + max_assets: 1, + beneficiary: three.clone(), + }], }, 50, ); @@ -235,7 +245,11 @@ fn reserve_transfer_should_work() { X1(Parachain(2)), Xcm::ReserveAssetDeposited { assets: (X1(Parent), 100).into(), - effects: vec![Order::DepositAsset { assets: All.into(), max_assets: 1, beneficiary: three }], + effects: vec![Order::DepositAsset { + assets: All.into(), + max_assets: 1, + beneficiary: three + }], } )] ); @@ -303,14 +317,19 @@ fn paid_transacting_should_refund_payment_for_unused_weight() { weight: 70, debt: 30, halt_on_error: true, - xcm: vec![Xcm::<TestCall>::Transact { + orders: vec![], + instructions: vec![Xcm::<TestCall>::Transact { origin_type: OriginKind::Native, require_weight_at_most: 60, // call estimated at 70 but only takes 10. call: TestCall::Any(60, Some(10)).encode().into(), }], }, - Order::<TestCall>::DepositAsset { assets: All.into(), max_assets: 1, beneficiary: one.clone() }, + Order::<TestCall>::DepositAsset { + assets: All.into(), + max_assets: 1, + beneficiary: one.clone(), + }, ], }; let weight_limit = 100; diff --git a/xcm/xcm-builder/src/weight.rs b/xcm/xcm-builder/src/weight.rs index 5e197fee89fa..679aa0928216 100644 --- a/xcm/xcm-builder/src/weight.rs +++ b/xcm/xcm-builder/src/weight.rs @@ -38,21 +38,11 @@ impl<T: Get<Weight>, C: Decode + GetDispatchInfo> WeightBounds<C> for FixedWeigh Xcm::WithdrawAsset { effects, .. } | Xcm::ReserveAssetDeposited { effects, .. } | Xcm::ReceiveTeleportedAsset { effects, .. } => { - let inner: Weight = effects - .iter_mut() - .map(|effect| match effect { - Order::BuyExecution { .. } => { - // On success, execution of this will result in more weight being consumed but - // we don't count it here since this is only the *shallow*, non-negotiable weight - // spend and doesn't count weight placed behind a `BuyExecution` since it will not - // be definitely consumed from any existing weight credit if execution of the message - // is attempted. - T::get() - }, - _ => T::get(), - }) - .sum(); - T::get().saturating_add(inner) + let mut extra = T::get(); + for order in effects.iter_mut() { + extra.saturating_accrue(Self::shallow_order(order)?); + } + extra }, _ => T::get(), }) @@ -64,16 +54,43 @@ impl<T: Get<Weight>, C: Decode + GetDispatchInfo> WeightBounds<C> for FixedWeigh Xcm::ReserveAssetDeposited { effects, .. } | Xcm::ReceiveTeleportedAsset { effects, .. } => { let mut extra = 0; - for effect in effects.iter_mut() { - match effect { - Order::BuyExecution { xcm, .. } => - for message in xcm.iter_mut() { - extra.saturating_accrue( - Self::shallow(message)?.saturating_add(Self::deep(message)?), - ); - }, - _ => {}, - } + for order in effects.iter_mut() { + extra.saturating_accrue(Self::deep_order(order)?); + } + extra + }, + _ => 0, + }) + } +} + +impl<T: Get<Weight>, C: Decode + GetDispatchInfo> FixedWeightBounds<T, C> { + fn shallow_order(order: &mut Order<C>) -> Result<Weight, ()> { + Ok(match order { + Order::BuyExecution { .. } => { + // On success, execution of this will result in more weight being consumed but + // we don't count it here since this is only the *shallow*, non-negotiable weight + // spend and doesn't count weight placed behind a `BuyExecution` since it will not + // be definitely consumed from any existing weight credit if execution of the message + // is attempted. + T::get() + }, + _ => T::get(), + }) + } + fn deep_order(order: &mut Order<C>) -> Result<Weight, ()> { + Ok(match order { + Order::BuyExecution { orders, instructions, .. } => { + let mut extra = 0; + for instruction in instructions.iter_mut() { + extra.saturating_accrue( + Self::shallow(instruction)?.saturating_add(Self::deep(instruction)?), + ); + } + for order in orders.iter_mut() { + extra.saturating_accrue( + Self::shallow_order(order)?.saturating_add(Self::deep_order(order)?), + ); } extra }, diff --git a/xcm/xcm-executor/src/assets.rs b/xcm/xcm-executor/src/assets.rs index 6a939935b46d..f90e4b0a0e03 100644 --- a/xcm/xcm-executor/src/assets.rs +++ b/xcm/xcm-executor/src/assets.rs @@ -240,26 +240,27 @@ impl Assets { ) -> Result<Assets, TakeError> { let mut taken = Assets::new(); match mask { - MultiAssetFilter::Wild(All) => if self.fungible.len() + self.non_fungible.len() <= limit { - return Ok(self.swapped(Assets::new())) - } else { - let fungible = mem::replace(&mut self.fungible, Default::default()); - fungible.into_iter().for_each(|(c, amount)| { - if taken.len() < limit { - taken.fungible.insert(c, amount); - } else { - self.fungible.insert(c, amount); - } - }); - let non_fungible = mem::replace(&mut self.non_fungible, Default::default()); - non_fungible.into_iter().for_each(|(c, instance)| { - if taken.len() < limit { - taken.non_fungible.insert((c, instance)); - } else { - self.non_fungible.insert((c, instance)); - } - }); - }, + MultiAssetFilter::Wild(All) => + if self.fungible.len() + self.non_fungible.len() <= limit { + return Ok(self.swapped(Assets::new())) + } else { + let fungible = mem::replace(&mut self.fungible, Default::default()); + fungible.into_iter().for_each(|(c, amount)| { + if taken.len() < limit { + taken.fungible.insert(c, amount); + } else { + self.fungible.insert(c, amount); + } + }); + let non_fungible = mem::replace(&mut self.non_fungible, Default::default()); + non_fungible.into_iter().for_each(|(c, instance)| { + if taken.len() < limit { + taken.non_fungible.insert((c, instance)); + } else { + self.non_fungible.insert((c, instance)); + } + }); + }, MultiAssetFilter::Wild(AllOf { fun: WildFungible, id }) => { if let Some((id, amount)) = self.fungible.remove_entry(&id) { taken.fungible.insert(id, amount); diff --git a/xcm/xcm-executor/src/lib.rs b/xcm/xcm-executor/src/lib.rs index e59aa54a1fd8..88fe03ad27d7 100644 --- a/xcm/xcm-executor/src/lib.rs +++ b/xcm/xcm-executor/src/lib.rs @@ -247,28 +247,28 @@ impl<Config: config::Config> XcmExecutor<Config> { if let Some((mut holding, effects)) = maybe_holding_effects { for effect in effects.into_iter() { - total_surplus += Self::execute_effects(&origin, &mut holding, effect, trader)?; + total_surplus += Self::execute_orders(&origin, &mut holding, effect, trader)?; } } Ok(total_surplus) } - fn execute_effects( + fn execute_orders( origin: &MultiLocation, holding: &mut Assets, - effect: Order<Config::Call>, + order: Order<Config::Call>, trader: &mut Config::Trader, ) -> Result<Weight, XcmError> { log::trace!( - target: "xcm::execute_effects", + target: "xcm::execute_orders", "origin: {:?}, holding: {:?}, effect: {:?}", origin, holding, - effect, + order, ); let mut total_surplus = 0; - match effect { + match order { Order::DepositAsset { assets, max_assets, beneficiary } => { let deposited = holding.limited_saturating_take(assets, max_assets as usize); for asset in deposited.into_assets_iter() { @@ -303,7 +303,7 @@ impl<Config: config::Config> XcmExecutor<Config> { Xcm::QueryResponse { query_id, response: Response::Assets(assets) }, )?; }, - Order::BuyExecution { fees, weight, debt, halt_on_error, xcm } => { + Order::BuyExecution { fees, weight, debt, halt_on_error, orders, instructions } => { // pay for `weight` using up to `fees` of the holding register. let purchasing_weight = Weight::from(weight.checked_add(debt).ok_or(XcmError::Overflow)?); @@ -313,11 +313,23 @@ impl<Config: config::Config> XcmExecutor<Config> { holding.subsume_assets(unspent); let mut remaining_weight = weight; - for message in xcm.into_iter() { + for order in orders.into_iter() { + match Self::execute_orders( + origin, + holding, + order, + trader, + ) { + Err(e) if halt_on_error => return Err(e), + Err(_) => {}, + Ok(surplus) => total_surplus += surplus, + } + } + for instruction in instructions.into_iter() { match Self::do_execute_xcm( origin.clone(), false, - message, + instruction, &mut remaining_weight, None, trader, From 851b00e8139c8b2762ff82843a722d207caac3a4 Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Wed, 4 Aug 2021 17:00:05 +0200 Subject: [PATCH 080/166] Fix XCM extrinsics --- runtime/kusama/src/lib.rs | 1 + runtime/rococo/src/lib.rs | 1 + runtime/westend/src/lib.rs | 1 + xcm/pallet-xcm/src/lib.rs | 36 +++++++++++++++----- xcm/pallet-xcm/src/mock.rs | 5 +-- xcm/pallet-xcm/src/tests.rs | 10 +++--- xcm/src/v1/multiasset.rs | 16 +++++++++ xcm/xcm-builder/src/tests.rs | 18 ++++++++-- xcm/xcm-executor/src/lib.rs | 7 +--- xcm/xcm-simulator/example/src/lib.rs | 6 ++-- xcm/xcm-simulator/example/src/parachain.rs | 1 + xcm/xcm-simulator/example/src/relay_chain.rs | 1 + 12 files changed, 78 insertions(+), 25 deletions(-) diff --git a/runtime/kusama/src/lib.rs b/runtime/kusama/src/lib.rs index 6fc6b8ac3524..32a5455b8d13 100644 --- a/runtime/kusama/src/lib.rs +++ b/runtime/kusama/src/lib.rs @@ -1323,6 +1323,7 @@ impl pallet_xcm::Config for Runtime { type XcmTeleportFilter = All<(MultiLocation, Vec<MultiAsset>)>; type XcmReserveTransferFilter = All<(MultiLocation, Vec<MultiAsset>)>; type Weigher = FixedWeightBounds<BaseXcmWeight, Call>; + type LocationInverter = LocationInverter<Ancestry>; } parameter_types! { diff --git a/runtime/rococo/src/lib.rs b/runtime/rococo/src/lib.rs index f05de3d26771..c82e777f7f02 100644 --- a/runtime/rococo/src/lib.rs +++ b/runtime/rococo/src/lib.rs @@ -695,6 +695,7 @@ impl pallet_xcm::Config for Runtime { type XcmTeleportFilter = All<(MultiLocation, Vec<MultiAsset>)>; type XcmReserveTransferFilter = All<(MultiLocation, Vec<MultiAsset>)>; type Weigher = FixedWeightBounds<BaseXcmWeight, Call>; + type LocationInverter = LocationInverter<Ancestry>; } impl parachains_session_info::Config for Runtime {} diff --git a/runtime/westend/src/lib.rs b/runtime/westend/src/lib.rs index d0304022c602..9944efa1f5f4 100644 --- a/runtime/westend/src/lib.rs +++ b/runtime/westend/src/lib.rs @@ -956,6 +956,7 @@ impl pallet_xcm::Config for Runtime { type XcmTeleportFilter = All<(MultiLocation, Vec<MultiAsset>)>; type XcmReserveTransferFilter = All<(MultiLocation, Vec<MultiAsset>)>; type Weigher = FixedWeightBounds<BaseXcmWeight, Call>; + type LocationInverter = LocationInverter<Ancestry>; } construct_runtime! { diff --git a/xcm/pallet-xcm/src/lib.rs b/xcm/pallet-xcm/src/lib.rs index bbbcfe1163b3..779898a604bb 100644 --- a/xcm/pallet-xcm/src/lib.rs +++ b/xcm/pallet-xcm/src/lib.rs @@ -39,7 +39,7 @@ pub mod pallet { use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; use sp_runtime::traits::AccountIdConversion; - use xcm_executor::traits::WeightBounds; + use xcm_executor::traits::{WeightBounds, InvertLocation}; #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] @@ -77,6 +77,9 @@ pub mod pallet { /// Means of measuring the weight consumed by an XCM message locally. type Weigher: WeightBounds<Self::Call>; + + /// Means of inverting a location. + type LocationInverter: InvertLocation; } #[pallet::event] @@ -96,6 +99,8 @@ 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. + CannotReanchor, } #[pallet::hooks] @@ -143,13 +148,20 @@ pub mod pallet { dest: MultiLocation, beneficiary: MultiLocation, assets: MultiAssets, + fee_asset_item: u32, dest_weight: Weight, ) -> DispatchResult { let origin_location = T::ExecuteXcmOrigin::ensure_origin(origin)?; let value = (origin_location, assets.drain()); ensure!(T::XcmTeleportFilter::contains(&value), Error::<T>::Filtered); let (origin_location, assets) = value; - let fees = assets.first().ok_or(Error::<T>::Empty)?.clone(); + let inv_dest = T::LocationInverter::invert_location(&dest); + let fees = assets.get(fee_asset_item as usize) + .ok_or(Error::<T>::Empty)? + .clone() + .reanchored(&inv_dest) + .map_err(|_| Error::<T>::CannotReanchor)?; + let max_assets = assets.len() as u32; let assets = assets.into(); let mut message = Xcm::WithdrawAsset { assets, @@ -166,7 +178,7 @@ pub mod pallet { orders: vec![], instructions: vec![], }, - DepositAsset { assets: Wild(All), max_assets: 1, beneficiary }, + DepositAsset { assets: Wild(All), max_assets, beneficiary }, ], }], }; @@ -203,13 +215,21 @@ pub mod pallet { dest: MultiLocation, beneficiary: MultiLocation, assets: MultiAssets, + fee_asset_item: u32, dest_weight: Weight, ) -> DispatchResult { let origin_location = T::ExecuteXcmOrigin::ensure_origin(origin)?; let value = (origin_location, assets.drain()); ensure!(T::XcmReserveTransferFilter::contains(&value), Error::<T>::Filtered); - let (origin_location, assets) = value; - let fees = assets.first().ok_or(Error::<T>::Empty)?.clone(); + let (origin_location, mut assets) = value; + let inv_dest = T::LocationInverter::invert_location(&dest); + let fees = assets.get(fee_asset_item as usize) + .ok_or(Error::<T>::Empty)? + .clone() + .reanchored(&inv_dest) + .map_err(|_| Error::<T>::CannotReanchor)?; + let max_assets = assets.len() as u32; + assets.sort(); let assets = assets.into(); let mut message = Xcm::TransferReserveAsset { assets, @@ -217,14 +237,14 @@ pub mod pallet { effects: vec![ BuyExecution { fees, - // Zero weight for additional XCM (since there are none to execute) + // Zero weight for additional instructions/orders (since there are none to execute) weight: 0, - debt: dest_weight, + debt: dest_weight, // covers this, `TransferReserveAsset` xcm, and `DepositAsset` order. halt_on_error: false, orders: vec![], instructions: vec![], }, - DepositAsset { assets: Wild(All), max_assets: 1, beneficiary }, + DepositAsset { assets: Wild(All), max_assets, beneficiary }, ], }; let weight = diff --git a/xcm/pallet-xcm/src/mock.rs b/xcm/pallet-xcm/src/mock.rs index 50a2471d74d7..ca143ce11db0 100644 --- a/xcm/pallet-xcm/src/mock.rs +++ b/xcm/pallet-xcm/src/mock.rs @@ -186,6 +186,7 @@ impl pallet_xcm::Config for Test { type XcmTeleportFilter = All<(MultiLocation, Vec<MultiAsset>)>; type XcmReserveTransferFilter = All<(MultiLocation, Vec<MultiAsset>)>; type Weigher = FixedWeightBounds<BaseXcmWeight, Call>; + type LocationInverter = LocationInverter<Ancestry>; } impl origin::Config for Test {} @@ -194,10 +195,10 @@ pub(crate) fn last_event() -> Event { System::events().pop().expect("Event expected").event } -pub(crate) fn buy_execution<C>(debt: Weight) -> Order<C> { +pub(crate) fn buy_execution<C>(fees: impl Into<MultiAsset>, debt: Weight) -> Order<C> { use xcm::opaque::v1::prelude::*; Order::BuyExecution { - fees: (RelayLocation::get(), 10).into(), + fees: fees.into(), weight: 0, debt, halt_on_error: false, diff --git a/xcm/pallet-xcm/src/tests.rs b/xcm/pallet-xcm/src/tests.rs index dd86ca3a05e0..f10e0490484d 100644 --- a/xcm/pallet-xcm/src/tests.rs +++ b/xcm/pallet-xcm/src/tests.rs @@ -42,7 +42,7 @@ fn send_works() { let message = Xcm::ReserveAssetDeposited { assets: (X1(Parent), SEND_AMOUNT).into(), effects: vec![ - buy_execution(weight), + buy_execution((Parent, SEND_AMOUNT), weight), DepositAsset { assets: All.into(), max_assets: 1, beneficiary: sender.clone() }, ], }; @@ -76,7 +76,7 @@ fn send_fails_when_xcm_router_blocks() { let message = Xcm::ReserveAssetDeposited { assets: (Parent, SEND_AMOUNT).into(), effects: vec![ - buy_execution(weight), + buy_execution((Parent, SEND_AMOUNT), weight), DepositAsset { assets: All.into(), max_assets: 1, beneficiary: sender.clone() }, ], }; @@ -116,6 +116,7 @@ fn teleport_assets_works() { RelayLocation::get(), X1(AccountId32 { network: Any, id: BOB.into() }), (Here, SEND_AMOUNT).into(), + 0, weight, )); assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE - SEND_AMOUNT); @@ -144,6 +145,7 @@ fn reserve_transfer_assets_works() { Parachain(PARA_ID).into(), dest.clone(), (Here, SEND_AMOUNT).into(), + 0, weight )); // Alice spent amount @@ -158,7 +160,7 @@ fn reserve_transfer_assets_works() { Xcm::ReserveAssetDeposited { assets: (X1(Parent), SEND_AMOUNT).into(), effects: vec![ - buy_execution(weight), + buy_execution((Parent, SEND_AMOUNT), weight), DepositAsset { assets: All.into(), max_assets: 1, beneficiary: dest }, ] } @@ -189,7 +191,7 @@ fn execute_withdraw_to_deposit_works() { Box::new(Xcm::WithdrawAsset { assets: (Here, SEND_AMOUNT).into(), effects: vec![ - buy_execution(weight), + buy_execution((Here, SEND_AMOUNT), weight), DepositAsset { assets: All.into(), max_assets: 1, beneficiary: dest } ], }), diff --git a/xcm/src/v1/multiasset.rs b/xcm/src/v1/multiasset.rs index cc0672b2d2d8..dc3c4641e232 100644 --- a/xcm/src/v1/multiasset.rs +++ b/xcm/src/v1/multiasset.rs @@ -217,6 +217,12 @@ impl MultiAsset { self.id.reanchor(prepend) } + /// Prepend a `MultiLocation` to a concrete asset, giving it a new root location. + pub fn reanchored(mut self, prepend: &MultiLocation) -> Result<Self, ()> { + self.reanchor(prepend)?; + Ok(self) + } + /// Returns true if `self` is a super-set of the given `inner`. pub fn contains(&self, inner: &MultiAsset) -> bool { use Fungibility::*; @@ -307,10 +313,20 @@ impl MultiAssets { &self.0 } + /// Return the number of distinct asset instances contained. + pub fn len(&self) -> usize { + self.0.len() + } + /// Prepend a `MultiLocation` to any concrete asset items, giving it a new root location. pub fn reanchor(&mut self, prepend: &MultiLocation) -> Result<(), ()> { self.0.iter_mut().try_for_each(|i| i.reanchor(prepend)) } + + /// Return a reference to an item at a specific index or `None` if it doesn't exist. + pub fn get(&self, index: usize) -> Option<&MultiAsset> { + self.0.get(index) + } } /// Classification of whether an asset is fungible or not, along with an optional amount or instance. #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, Decode)] diff --git a/xcm/xcm-builder/src/tests.rs b/xcm/xcm-builder/src/tests.rs index 0f250ddbb954..8f95687f29cf 100644 --- a/xcm/xcm-builder/src/tests.rs +++ b/xcm/xcm-builder/src/tests.rs @@ -118,7 +118,14 @@ fn allow_paid_should_work() { let mut underpaying_message = opaque::Xcm::ReserveAssetDeposited { assets: (X1(Parent), 100).into(), effects: vec![ - Order::BuyExecution { fees, weight: 0, debt: 20, halt_on_error: true, orders: vec![], instructions: vec![] }, + Order::BuyExecution { + fees, + weight: 0, + debt: 20, + halt_on_error: true, + orders: vec![], + instructions: vec![], + }, Order::DepositAsset { assets: All.into(), max_assets: 1, beneficiary: Here }, ], }; @@ -136,7 +143,14 @@ fn allow_paid_should_work() { let mut paying_message = opaque::Xcm::ReserveAssetDeposited { assets: (X1(Parent), 100).into(), effects: vec![ - Order::BuyExecution { fees, weight: 0, debt: 30, halt_on_error: true, orders: vec![], instructions: vec![] }, + Order::BuyExecution { + fees, + weight: 0, + debt: 30, + halt_on_error: true, + orders: vec![], + instructions: vec![], + }, Order::DepositAsset { assets: All.into(), max_assets: 1, beneficiary: Here }, ], }; diff --git a/xcm/xcm-executor/src/lib.rs b/xcm/xcm-executor/src/lib.rs index 88fe03ad27d7..c30c5d3f9a77 100644 --- a/xcm/xcm-executor/src/lib.rs +++ b/xcm/xcm-executor/src/lib.rs @@ -314,12 +314,7 @@ impl<Config: config::Config> XcmExecutor<Config> { let mut remaining_weight = weight; for order in orders.into_iter() { - match Self::execute_orders( - origin, - holding, - order, - trader, - ) { + match Self::execute_orders(origin, holding, order, trader) { Err(e) if halt_on_error => return Err(e), Err(_) => {}, Ok(surplus) => total_surplus += surplus, diff --git a/xcm/xcm-simulator/example/src/lib.rs b/xcm/xcm-simulator/example/src/lib.rs index 12e39a51e30f..a02aeaaff456 100644 --- a/xcm/xcm-simulator/example/src/lib.rs +++ b/xcm/xcm-simulator/example/src/lib.rs @@ -17,10 +17,9 @@ mod parachain; mod relay_chain; -use sp_runtime::AccountId32; use xcm_simulator::{decl_test_network, decl_test_parachain, decl_test_relay_chain}; -pub const ALICE: AccountId32 = AccountId32::new([0u8; 32]); +pub const ALICE: sp_runtime::AccountId32 = sp_runtime::AccountId32::new([0u8; 32]); decl_test_parachain! { pub struct ParaA { @@ -194,7 +193,8 @@ mod tests { X1(Parachain(1)), X1(AccountId32 { network: Any, id: ALICE.into() }), (Here, 123).into(), - 123, + 0, + 3, )); }); diff --git a/xcm/xcm-simulator/example/src/parachain.rs b/xcm/xcm-simulator/example/src/parachain.rs index 4e870abb0315..3e7212c48fa4 100644 --- a/xcm/xcm-simulator/example/src/parachain.rs +++ b/xcm/xcm-simulator/example/src/parachain.rs @@ -293,6 +293,7 @@ impl pallet_xcm::Config for Runtime { type XcmTeleportFilter = (); type XcmReserveTransferFilter = All<(MultiLocation, Vec<MultiAsset>)>; type Weigher = FixedWeightBounds<UnitWeightCost, Call>; + type LocationInverter = LocationInverter<Ancestry>; } type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Runtime>; diff --git a/xcm/xcm-simulator/example/src/relay_chain.rs b/xcm/xcm-simulator/example/src/relay_chain.rs index e691e3e7ad35..adbf0b965f41 100644 --- a/xcm/xcm-simulator/example/src/relay_chain.rs +++ b/xcm/xcm-simulator/example/src/relay_chain.rs @@ -147,6 +147,7 @@ impl pallet_xcm::Config for Runtime { type XcmTeleportFilter = All<(MultiLocation, Vec<MultiAsset>)>; type XcmReserveTransferFilter = All<(MultiLocation, Vec<MultiAsset>)>; type Weigher = FixedWeightBounds<BaseXcmWeight, Call>; + type LocationInverter = LocationInverter<Ancestry>; } parameter_types! { From 20bb7140a0eec64d2416d3dd0fc9e0fdc2283db2 Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Wed, 4 Aug 2021 17:04:34 +0200 Subject: [PATCH 081/166] fmt --- xcm/pallet-xcm/src/lib.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/xcm/pallet-xcm/src/lib.rs b/xcm/pallet-xcm/src/lib.rs index 779898a604bb..b6742e9b58d0 100644 --- a/xcm/pallet-xcm/src/lib.rs +++ b/xcm/pallet-xcm/src/lib.rs @@ -39,7 +39,7 @@ pub mod pallet { use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; use sp_runtime::traits::AccountIdConversion; - use xcm_executor::traits::{WeightBounds, InvertLocation}; + use xcm_executor::traits::{InvertLocation, WeightBounds}; #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] @@ -156,7 +156,8 @@ pub mod pallet { ensure!(T::XcmTeleportFilter::contains(&value), Error::<T>::Filtered); let (origin_location, assets) = value; let inv_dest = T::LocationInverter::invert_location(&dest); - let fees = assets.get(fee_asset_item as usize) + let fees = assets + .get(fee_asset_item as usize) .ok_or(Error::<T>::Empty)? .clone() .reanchored(&inv_dest) @@ -223,7 +224,8 @@ pub mod pallet { ensure!(T::XcmReserveTransferFilter::contains(&value), Error::<T>::Filtered); let (origin_location, mut assets) = value; let inv_dest = T::LocationInverter::invert_location(&dest); - let fees = assets.get(fee_asset_item as usize) + let fees = assets + .get(fee_asset_item as usize) .ok_or(Error::<T>::Empty)? .clone() .reanchored(&inv_dest) @@ -239,7 +241,7 @@ pub mod pallet { fees, // Zero weight for additional instructions/orders (since there are none to execute) weight: 0, - debt: dest_weight, // covers this, `TransferReserveAsset` xcm, and `DepositAsset` order. + debt: dest_weight, // covers this, `TransferReserveAsset` xcm, and `DepositAsset` order. halt_on_error: false, orders: vec![], instructions: vec![], From 3f85ebd8de67c8bc27a2cefceb1e72bac5fad608 Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Wed, 4 Aug 2021 17:58:34 +0200 Subject: [PATCH 082/166] Make Vec<MultiAsset>/MultiAssets conversions safe --- xcm/src/v1/multiasset.rs | 66 +++++++++++++++++++++++++++++----------- 1 file changed, 49 insertions(+), 17 deletions(-) diff --git a/xcm/src/v1/multiasset.rs b/xcm/src/v1/multiasset.rs index dc3c4641e232..ea7d17212749 100644 --- a/xcm/src/v1/multiasset.rs +++ b/xcm/src/v1/multiasset.rs @@ -243,27 +243,40 @@ pub struct MultiAssets(Vec<MultiAsset>); impl Decode for MultiAssets { fn decode<I: codec::Input>(input: &mut I) -> Result<Self, parity_scale_codec::Error> { - let r = Vec::<MultiAsset>::decode(input)?; - if r.is_empty() { - return Ok(Self(Vec::new())) - } - r.iter().skip(1).try_fold( - &r[0], - |a, b| -> Result<&MultiAsset, parity_scale_codec::Error> { - if a.id < b.id || a < b && (a.is_non_fungible(None) || b.is_non_fungible(None)) { - Ok(b) - } else { - Err("Out of order".into()) - } - }, - )?; - Ok(Self(r)) + Self::from_sorted_and_deduplicated(Vec::<MultiAsset>::decode(input)?) + .map_err(|()| "Out of order".into()) } } impl From<Vec<MultiAsset>> for MultiAssets { - fn from(x: Vec<MultiAsset>) -> Self { - Self(x) + fn from(mut assets: Vec<MultiAsset>) -> Self { + let mut res = Vec::with_capacity(assets.len()); + if !assets.is_empty() { + assets.sort(); + let mut iter = assets.into_iter(); + if let Some(first) = iter.next() { + let last = iter.fold(first, |a, b| -> MultiAsset { + match (a, b) { + ( + MultiAsset { fun: Fungibility::Fungible(a_amount), id: a_id }, + MultiAsset { fun: Fungibility::Fungible(b_amount), id: b_id }, + ) if a_id == b_id => + MultiAsset { id: a_id, fun: Fungibility::Fungible(a_amount + b_amount) }, + ( + MultiAsset { fun: Fungibility::NonFungible(a_instance), id: a_id }, + MultiAsset { fun: Fungibility::NonFungible(b_instance), id: b_id }, + ) if a_id == b_id && a_instance == b_instance => + MultiAsset { fun: Fungibility::NonFungible(a_instance), id: a_id }, + (to_push, to_remember) => { + res.push(to_push); + to_remember + }, + } + }); + res.push(last); + } + } + Self(res) } } @@ -279,6 +292,25 @@ impl MultiAssets { Self(Vec::new()) } + /// Create a new instance of `MultiAssets` from a `Vec<MultiAsset>` whose contents are sorted and + /// which contain no duplicates. + /// + /// Returns `Ok` if the operation succeeds and `Err` if `r` is out of order or had duplicates. If you can't + /// guarantee that `r` is sorted and deduplicated, then use `From::<Vec<MultiAsset>>::from` which is infallible. + pub fn from_sorted_and_deduplicated(r: Vec<MultiAsset>) -> Result<Self, ()> { + if r.is_empty() { + return Ok(Self(Vec::new())) + } + r.iter().skip(1).try_fold(&r[0], |a, b| -> Result<&MultiAsset, ()> { + if a.id < b.id || a < b && (a.is_non_fungible(None) || b.is_non_fungible(None)) { + Ok(b) + } else { + Err(()) + } + })?; + Ok(Self(r)) + } + /// Add some asset onto the list. This is quite a laborious operation since it maintains the ordering. pub fn push(&mut self, a: MultiAsset) { if let Fungibility::Fungible(ref amount) = a.fun { From 61a2231c2fba6bc9579e27b24076dd8a4f543f7a Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Wed, 4 Aug 2021 18:07:41 +0200 Subject: [PATCH 083/166] More MultiAssets conversion safety --- xcm/src/v1/multiasset.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/xcm/src/v1/multiasset.rs b/xcm/src/v1/multiasset.rs index ea7d17212749..7b90b8581984 100644 --- a/xcm/src/v1/multiasset.rs +++ b/xcm/src/v1/multiasset.rs @@ -311,6 +311,27 @@ impl MultiAssets { Ok(Self(r)) } + /// Create a new instance of `MultiAssets` from a `Vec<MultiAsset>` whose contents are sorted and + /// which contain no duplicates. + /// + /// In release mode, this skips any checks to ensure that `r` is correct, making it a negligible-cost operation. + /// Generally though you should avoid using it unless you have a strict proof that `r` is valid. + #[cfg(test)] + pub fn from_sorted_and_deduplicated_skip_checks(r: Vec<MultiAsset>) -> Self { + Self::from_sorted_and_deduplicated(r).expect("Invalid input r is not sorted/deduped") + } + /// Create a new instance of `MultiAssets` from a `Vec<MultiAsset>` whose contents are sorted and + /// which contain no duplicates. + /// + /// In release mode, this skips any checks to ensure that `r` is correct, making it a negligible-cost operation. + /// Generally though you should avoid using it unless you have a strict proof that `r` is valid. + /// + /// In test mode, this checks anyway and panics on fail. + #[cfg(not(test))] + pub fn from_sorted_and_deduplicated_skip_checks(r: Vec<MultiAsset>) -> Self { + Self(r) + } + /// Add some asset onto the list. This is quite a laborious operation since it maintains the ordering. pub fn push(&mut self, a: MultiAsset) { if let Fungibility::Fungible(ref amount) = a.fun { From 86442655ad27960910cee7e6ed5ec64977eb4849 Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Wed, 4 Aug 2021 19:12:37 +0200 Subject: [PATCH 084/166] spelling --- xcm/src/v1/order.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xcm/src/v1/order.rs b/xcm/src/v1/order.rs index 6a2b04e9acf3..f311b5f9bf05 100644 --- a/xcm/src/v1/order.rs +++ b/xcm/src/v1/order.rs @@ -36,7 +36,7 @@ pub enum Order<Call> { /// /// - `assets`: The asset(s) to remove from holding. /// - `max_assets`: The maximum number of unique assets/asset instances to remove from holding. Only the first - /// `max_assets` assets/instances of those matched by `assets` will be removed, prioritised under standard asset + /// `max_assets` assets/instances of those matched by `assets` will be removed, prioritized under standard asset /// ordering. Any others will remain in holding. /// - `beneficiary`: The new owner for the assets. /// @@ -51,7 +51,7 @@ pub enum Order<Call> { /// /// - `assets`: The asset(s) to remove from holding. /// - `max_assets`: The maximum number of unique assets/asset instances to remove from holding. Only the first - /// `max_assets` assets/instances of those matched by `assets` will be removed, prioritised under standard asset + /// `max_assets` assets/instances of those matched by `assets` will be removed, prioritized under standard asset /// ordering. Any others will remain in holding. /// - `dest`: The location whose sovereign account will own the assets and thus the effective beneficiary for the /// assets and the notification target for the reserve asset deposit message. From 1e75953246dab079422496ad8de9659d2a483f6f Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Wed, 4 Aug 2021 19:14:40 +0200 Subject: [PATCH 085/166] fix doc test --- xcm/xcm-executor/src/assets.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xcm/xcm-executor/src/assets.rs b/xcm/xcm-executor/src/assets.rs index f90e4b0a0e03..212f60cdc9b6 100644 --- a/xcm/xcm-executor/src/assets.rs +++ b/xcm/xcm-executor/src/assets.rs @@ -378,7 +378,7 @@ impl Assets { /// use xcm_executor::Assets; /// use xcm::v1::prelude::*; /// let assets_i_have: Assets = vec![ (Here, 100).into(), (vec![0], 100).into() ].into(); - /// let assets_they_want: MultiAssetFilter = vec![ (Here, 200).into(), (vec![0], 50).into() [.into(); + /// let assets_they_want: MultiAssetFilter = vec![ (Here, 200).into(), (vec![0], 50).into() ].into(); /// /// let assets_we_can_trade: Assets = assets_i_have.min(&assets_they_want); /// assert_eq!(assets_we_can_trade.into_assets_iter().collect::<Vec<_>>(), vec![ From 669dcb0ff9f441267c3fd2cbb3066c7f1c863ca6 Mon Sep 17 00:00:00 2001 From: Gavin Wood <gavin@parity.io> Date: Thu, 5 Aug 2021 11:14:39 +0200 Subject: [PATCH 086/166] Apply suggestions from code review Co-authored-by: Amar Singh <asinghchrony@protonmail.com> --- xcm/src/lib.rs | 2 +- xcm/src/v1/multiasset.rs | 10 ++-------- xcm/src/v1/order.rs | 2 +- xcm/xcm-executor/src/assets.rs | 4 ++++ 4 files changed, 8 insertions(+), 10 deletions(-) diff --git a/xcm/src/lib.rs b/xcm/src/lib.rs index e7d31a2a7d74..d7d318225200 100644 --- a/xcm/src/lib.rs +++ b/xcm/src/lib.rs @@ -73,7 +73,7 @@ impl<Call> TryFrom<VersionedXcm<Call>> for v1::Xcm<Call> { pub mod opaque { pub mod v1 { - // Everything from v0 + // Everything from v1 pub use crate::v1::*; // Then override with the opaque types in v0 pub use crate::v1::opaque::{Order, Xcm}; diff --git a/xcm/src/v1/multiasset.rs b/xcm/src/v1/multiasset.rs index 7b90b8581984..61a82b7c32e1 100644 --- a/xcm/src/v1/multiasset.rs +++ b/xcm/src/v1/multiasset.rs @@ -34,7 +34,7 @@ use parity_scale_codec::{self as codec, Decode, Encode}; /// A general identifier for an instance of a non-fungible asset class. #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug)] pub enum AssetInstance { - /// Undefined - used if the NFA class has only one instance. + /// Undefined - used if the non-fungible asset class has only one instance. Undefined, /// A compact index. Technically this could be greater than `u128`, but this implementation supports only @@ -63,12 +63,6 @@ impl From<()> for AssetInstance { } } -/*impl From<u128> for AssetInstance { - fn from(x: u128) -> Self { - Self::Index(x) - } -}*/ - impl From<[u8; 4]> for AssetInstance { fn from(x: [u8; 4]) -> Self { Self::Array4(x) @@ -381,7 +375,7 @@ impl MultiAssets { self.0.get(index) } } -/// Classification of whether an asset is fungible or not, along with an optional amount or instance. +/// Classification of whether an asset is fungible or not. #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, Decode)] pub enum WildFungibility { Fungible, diff --git a/xcm/src/v1/order.rs b/xcm/src/v1/order.rs index f311b5f9bf05..0c92e5c4ce8c 100644 --- a/xcm/src/v1/order.rs +++ b/xcm/src/v1/order.rs @@ -130,7 +130,7 @@ pub enum Order<Call> { /// /// - `fees`: The asset(s) to remove from holding to pay for fees. /// - `weight`: The amount of weight to purchase; this should be at least the shallow weight of `effects` and `xcm`. - /// - `debt`: The amount of weight-debt already incurred to be pay off; this should be equal to the unpaid weight of + /// - `debt`: The amount of weight-debt already incurred to be paid off; this should be equal to the unpaid weight of /// any surrounding operations/orders. /// - `halt_on_error`: If `true`, the execution of the `orders` and `operations` will halt on the first failure. If /// `false`, then execution will continue regardless. diff --git a/xcm/xcm-executor/src/assets.rs b/xcm/xcm-executor/src/assets.rs index 212f60cdc9b6..adc48b899d23 100644 --- a/xcm/xcm-executor/src/assets.rs +++ b/xcm/xcm-executor/src/assets.rs @@ -428,18 +428,22 @@ mod tests { use xcm::v1::prelude::*; use MultiLocation::Here; #[allow(non_snake_case)] + /// Abstract fungible constructor fn AF(id: u8, amount: u128) -> MultiAsset { (vec![id], amount).into() } #[allow(non_snake_case)] + /// Abstract non-fungible constructor fn ANF(class: u8, instance_id: u8) -> MultiAsset { (vec![class], vec![instance_id]).into() } #[allow(non_snake_case)] + /// Concrete fungible constructor fn CF(amount: u128) -> MultiAsset { (Here, amount).into() } #[allow(non_snake_case)] + /// Concrete non-fungible constructor fn CNF(instance_id: u8) -> MultiAsset { (Here, [instance_id; 4]).into() } From 767bdb597970201712757e5149f81e4e44ea4490 Mon Sep 17 00:00:00 2001 From: Gavin Wood <gavin@parity.io> Date: Thu, 5 Aug 2021 11:17:20 +0200 Subject: [PATCH 087/166] Apply suggestions from code review Co-authored-by: Amar Singh <asinghchrony@protonmail.com> --- xcm/src/lib.rs | 2 +- xcm/src/v1/mod.rs | 2 +- xcm/src/v1/multiasset.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/xcm/src/lib.rs b/xcm/src/lib.rs index d7d318225200..3addd73421e5 100644 --- a/xcm/src/lib.rs +++ b/xcm/src/lib.rs @@ -75,7 +75,7 @@ pub mod opaque { pub mod v1 { // Everything from v1 pub use crate::v1::*; - // Then override with the opaque types in v0 + // Then override with the opaque types in v1 pub use crate::v1::opaque::{Order, Xcm}; } diff --git a/xcm/src/v1/mod.rs b/xcm/src/v1/mod.rs index c27bb1788069..c78506c5c042 100644 --- a/xcm/src/v1/mod.rs +++ b/xcm/src/v1/mod.rs @@ -148,7 +148,7 @@ pub enum Xcm<Call> { /// - `assets`: The asset(s) that are minted into the Holding Register. /// - `effects`: The order(s) to execute on the Holding Register. /// - /// Safety: `origin` must be trusted to have irrevocably destroyed the corresponding`assets` prior as a consequence + /// Safety: `origin` must be trusted to have irrevocably destroyed the corresponding `assets` prior as a consequence /// of sending this message. /// /// Kind: *Trusted Indication*. diff --git a/xcm/src/v1/multiasset.rs b/xcm/src/v1/multiasset.rs index 61a82b7c32e1..a52725a58c1a 100644 --- a/xcm/src/v1/multiasset.rs +++ b/xcm/src/v1/multiasset.rs @@ -386,7 +386,7 @@ pub enum WildFungibility { #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, Decode)] pub enum WildMultiAsset { /// All assets in the holding register, up to `usize` individual assets (different instances of non-fungibles could - /// as separate assets). + /// be separate assets). All, /// All assets in the holding register of a given fungibility and ID. If operating on non-fungibles, then a limit /// is provided for the maximum amount of matching instances. From ec2c1e98345233243e7ca3198457acbcb96b24e2 Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Thu, 5 Aug 2021 11:26:10 +0200 Subject: [PATCH 088/166] fmt --- xcm/xcm-executor/src/assets.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/xcm/xcm-executor/src/assets.rs b/xcm/xcm-executor/src/assets.rs index adc48b899d23..f04483f1a6fa 100644 --- a/xcm/xcm-executor/src/assets.rs +++ b/xcm/xcm-executor/src/assets.rs @@ -428,22 +428,22 @@ mod tests { use xcm::v1::prelude::*; use MultiLocation::Here; #[allow(non_snake_case)] - /// Abstract fungible constructor + /// Abstract fungible constructor fn AF(id: u8, amount: u128) -> MultiAsset { (vec![id], amount).into() } #[allow(non_snake_case)] - /// Abstract non-fungible constructor + /// Abstract non-fungible constructor fn ANF(class: u8, instance_id: u8) -> MultiAsset { (vec![class], vec![instance_id]).into() } #[allow(non_snake_case)] - /// Concrete fungible constructor + /// Concrete fungible constructor fn CF(amount: u128) -> MultiAsset { (Here, amount).into() } #[allow(non_snake_case)] - /// Concrete non-fungible constructor + /// Concrete non-fungible constructor fn CNF(instance_id: u8) -> MultiAsset { (Here, [instance_id; 4]).into() } From 740f6f305a9d201e7a90a0ec20002caffa6da0e3 Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Thu, 5 Aug 2021 11:29:11 +0200 Subject: [PATCH 089/166] Add v0, remove VersionedMultiAsset --- xcm/src/lib.rs | 33 +- xcm/src/v0/junction.rs | 194 +++++++++ xcm/src/v0/mod.rs | 331 ++++++++++++++ xcm/src/v0/multi_asset.rs | 380 ++++++++++++++++ xcm/src/v0/multi_location.rs | 820 +++++++++++++++++++++++++++++++++++ xcm/src/v0/order.rs | 154 +++++++ xcm/src/v0/traits.rs | 261 +++++++++++ 7 files changed, 2148 insertions(+), 25 deletions(-) create mode 100644 xcm/src/v0/junction.rs create mode 100644 xcm/src/v0/mod.rs create mode 100644 xcm/src/v0/multi_asset.rs create mode 100644 xcm/src/v0/multi_location.rs create mode 100644 xcm/src/v0/order.rs create mode 100644 xcm/src/v0/traits.rs diff --git a/xcm/src/lib.rs b/xcm/src/lib.rs index 3addd73421e5..0300e8f23c6d 100644 --- a/xcm/src/lib.rs +++ b/xcm/src/lib.rs @@ -51,7 +51,7 @@ impl Decode for Unsupported { #[codec(encode_bound())] #[codec(decode_bound())] pub enum VersionedXcm<Call> { - V0(Unsupported), + V0(v0::Xcm<Call>), V1(v1::Xcm<Call>), } @@ -72,6 +72,12 @@ impl<Call> TryFrom<VersionedXcm<Call>> for v1::Xcm<Call> { } pub mod opaque { + pub mod v0 { + // Everything from v0 + pub use crate::v0::*; + // Then override with the opaque types in v0 + pub use crate::v0::opaque::{Order, Xcm}; + } pub mod v1 { // Everything from v1 pub use crate::v1::*; @@ -90,7 +96,7 @@ pub mod opaque { /// A versioned multi-location, a relative location of a cross-consensus system identifier. #[derive(Clone, Eq, PartialEq, Encode, Decode, Debug)] pub enum VersionedMultiLocation { - V0(v1::MultiLocation), + V0(v0::MultiLocation), V1(v1::MultiLocation), } @@ -109,26 +115,3 @@ impl TryFrom<VersionedMultiLocation> for v1::MultiLocation { } } } - -/// A versioned multi-asset, an identifier for an asset within a consensus system. -#[derive(Clone, Eq, PartialEq, Encode, Decode, Debug)] -pub enum VersionedMultiAsset { - V0(Unsupported), - V1(v1::MultiAsset), -} - -impl From<v1::MultiAsset> for VersionedMultiAsset { - fn from(x: v1::MultiAsset) -> Self { - VersionedMultiAsset::V1(x) - } -} - -impl core::convert::TryFrom<VersionedMultiAsset> for v1::MultiAsset { - type Error = (); - fn try_from(x: VersionedMultiAsset) -> core::result::Result<Self, ()> { - match x { - VersionedMultiAsset::V1(x) => Ok(x), - _ => Err(()), - } - } -} diff --git a/xcm/src/v0/junction.rs b/xcm/src/v0/junction.rs new file mode 100644 index 000000000000..cf474f62851a --- /dev/null +++ b/xcm/src/v0/junction.rs @@ -0,0 +1,194 @@ +// 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 <http://www.gnu.org/licenses/>. + +//! Support data structures for `MultiLocation`, primarily the `Junction` datatype. + +use alloc::vec::Vec; +use parity_scale_codec::{self, Decode, Encode}; + +/// A global identifier of an account-bearing consensus system. +#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug)] +pub enum NetworkId { + /// Unidentified/any. + Any, + /// Some named network. + Named(Vec<u8>), + /// The Polkadot Relay chain + Polkadot, + /// Kusama. + Kusama, +} + +/// An identifier of a pluralistic body. +#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug)] +pub enum BodyId { + /// The only body in its context. + Unit, + /// A named body. + Named(Vec<u8>), + /// An indexed body. + // TODO: parity-scale-codec#262: Change to be a tuple. + Index { + #[codec(compact)] + id: u32, + }, + /// The unambiguous executive body (for Polkadot, this would be the Polkadot council). + Executive, + /// The unambiguous technical body (for Polkadot, this would be the Technical Committee). + Technical, + /// The unambiguous legislative body (for Polkadot, this could be considered the opinion of a majority of + /// lock-voters). + Legislative, + /// The unambiguous judicial body (this doesn't exist on Polkadot, but if it were to get a "grand oracle", it + /// may be considered as that). + Judicial, +} + +/// A part of a pluralistic body. +#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug)] +pub enum BodyPart { + /// The body's declaration, under whatever means it decides. + Voice, + /// A given number of members of the body. + Members { + #[codec(compact)] + count: u32, + }, + /// A given number of members of the body, out of some larger caucus. + Fraction { + #[codec(compact)] + nom: u32, + #[codec(compact)] + denom: u32, + }, + /// No less than the given proportion of members of the body. + AtLeastProportion { + #[codec(compact)] + nom: u32, + #[codec(compact)] + denom: u32, + }, + /// More than than the given proportion of members of the body. + MoreThanProportion { + #[codec(compact)] + nom: u32, + #[codec(compact)] + denom: u32, + }, +} + +impl BodyPart { + /// Returns `true` if the part represents a strict majority (> 50%) of the body in question. + pub fn is_majority(&self) -> bool { + match self { + BodyPart::Fraction { nom, denom } if *nom * 2 > *denom => true, + BodyPart::AtLeastProportion { nom, denom } if *nom * 2 > *denom => true, + BodyPart::MoreThanProportion { nom, denom } if *nom * 2 >= *denom => true, + _ => false, + } + } +} + +/// 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 { + /// The consensus system of which the context is a member and state-wise super-set. + /// + /// NOTE: This item is *not* a sub-consensus item: a consensus system may not identify itself trustlessly as + /// a location that includes this junction. + Parent, + /// 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)] + id: 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<u8>), + /// 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 Junction { + /// Returns true if this junction is a `Parent` item. + pub fn is_parent(&self) -> bool { + match self { + Junction::Parent => true, + _ => false, + } + } + + /// Returns true if this junction can be considered an interior part of its context. This is generally `true`, + /// except for the `Parent` item. + pub fn is_interior(&self) -> bool { + match self { + Junction::Parent => false, + + Junction::Parachain(..) | + Junction::AccountId32 { .. } | + Junction::AccountIndex64 { .. } | + Junction::AccountKey20 { .. } | + Junction::PalletInstance { .. } | + Junction::GeneralIndex { .. } | + Junction::GeneralKey(..) | + Junction::OnlyChild | + Junction::Plurality { .. } => true, + } + } +} diff --git a/xcm/src/v0/mod.rs b/xcm/src/v0/mod.rs new file mode 100644 index 000000000000..6ebfe3a960a1 --- /dev/null +++ b/xcm/src/v0/mod.rs @@ -0,0 +1,331 @@ +// 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 <http://www.gnu.org/licenses/>. + +//! Version 0 of the Cross-Consensus Message format data structures. + +use crate::{DoubleEncoded, VersionedXcm}; +use alloc::vec::Vec; +use core::{convert::TryFrom, fmt::Debug, result}; +use derivative::Derivative; +use parity_scale_codec::{self, Decode, Encode}; + +mod junction; +mod multi_asset; +mod multi_location; +mod order; +mod traits; +pub use junction::{BodyId, BodyPart, Junction, NetworkId}; +pub use multi_asset::{AssetInstance, MultiAsset}; +pub use multi_location::MultiLocation; +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, BodyPart, Junction::*, NetworkId}, + multi_asset::{ + AssetInstance::{self, *}, + MultiAsset::{self, *}, + }, + multi_location::MultiLocation::{self, *}, + order::Order::{self, *}, + traits::{Error as XcmError, ExecuteXcm, Outcome, Result as XcmResult, SendXcm}, + OriginKind, + Xcm::{self, *}, + }; +} + +// TODO: #2841 #XCMENCODE Efficient encodings for Vec<MultiAsset>, Vec<Order>, using initial byte values 128+ to encode +// the number of items in the vector. + +/// Basically just the XCM (more general) version of `ParachainDispatchOrigin`. +#[derive(Copy, Clone, Eq, PartialEq, Encode, Decode, Debug)] +pub enum OriginKind { + /// Origin should just be the native dispatch origin representation for the sender in the + /// local runtime framework. For Cumulus/Frame chains this is the `Parachain` or `Relay` origin + /// if coming from a chain, though there may be others if the `MultiLocation` XCM origin has a + /// primary/native dispatch origin form. + Native, + + /// Origin should just be the standard account-based origin with the sovereign account of + /// the sender. For Cumulus/Frame chains, this is the `Signed` origin. + SovereignAccount, + + /// Origin should be the super-user. For Cumulus/Frame chains, this is the `Root` origin. + /// This will not usually be an available option. + Superuser, + + /// Origin should be interpreted as an XCM native origin and the `MultiLocation` should be + /// encoded directly in the dispatch origin unchanged. For Cumulus/Frame chains, this will be + /// the `pallet_xcm::Origin::Xcm` type. + Xcm, +} + +/// Response data to a query. +#[derive(Clone, Eq, PartialEq, Encode, Decode, Debug)] +pub enum Response { + /// Some assets. + Assets(Vec<MultiAsset>), +} + +/// Cross-Consensus Message: A message from one consensus system to another. +/// +/// Consensus systems that may send and receive messages include blockchains and smart contracts. +/// +/// All messages are delivered from a known *origin*, expressed as a `MultiLocation`. +/// +/// This is the inner XCM format and is version-sensitive. Messages are typically passed using the outer +/// XCM format, known as `VersionedXcm`. +#[derive(Derivative, Encode, Decode)] +#[derivative(Clone(bound = ""), Eq(bound = ""), PartialEq(bound = ""), Debug(bound = ""))] +#[codec(encode_bound())] +#[codec(decode_bound())] +pub enum Xcm<Call> { + /// Withdraw asset(s) (`assets`) from the ownership of `origin` and place them into `holding`. Execute the + /// orders (`effects`). + /// + /// - `assets`: The asset(s) to be withdrawn into holding. + /// - `effects`: The order(s) to execute on the holding account. + /// + /// Kind: *Instruction*. + /// + /// Errors: + #[codec(index = 0)] + WithdrawAsset { assets: Vec<MultiAsset>, effects: Vec<Order<Call>> }, + + /// Asset(s) (`assets`) have been received into the ownership of this system on the `origin` system. + /// + /// Some orders are given (`effects`) which should be executed once the corresponding derivative assets have + /// been placed into `holding`. + /// + /// - `assets`: The asset(s) that are minted into holding. + /// - `effects`: The order(s) to execute on the holding account. + /// + /// Safety: `origin` must be trusted to have received and be storing `assets` such that they may later be + /// withdrawn should this system send a corresponding message. + /// + /// Kind: *Trusted Indication*. + /// + /// Errors: + #[codec(index = 1)] + ReserveAssetDeposit { assets: Vec<MultiAsset>, effects: Vec<Order<Call>> }, + + /// Asset(s) (`assets`) have been destroyed on the `origin` system and equivalent assets should be + /// created on this system. + /// + /// Some orders are given (`effects`) which should be executed once the corresponding derivative assets have + /// been placed into `holding`. + /// + /// - `assets`: The asset(s) that are minted into holding. + /// - `effects`: The order(s) to execute on the holding account. + /// + /// Safety: `origin` must be trusted to have irrevocably destroyed the `assets` prior as a consequence of + /// sending this message. + /// + /// Kind: *Trusted Indication*. + /// + /// Errors: + #[codec(index = 2)] + TeleportAsset { assets: Vec<MultiAsset>, effects: Vec<Order<Call>> }, + + /// Indication of the contents of the holding account corresponding to the `QueryHolding` order of `query_id`. + /// + /// - `query_id`: The identifier of the query that resulted in this message being sent. + /// - `assets`: The message content. + /// + /// Safety: No concerns. + /// + /// Kind: *Information*. + /// + /// Errors: + #[codec(index = 3)] + QueryResponse { + #[codec(compact)] + query_id: u64, + response: Response, + }, + + /// Withdraw asset(s) (`assets`) from the ownership of `origin` and place equivalent assets under the + /// ownership of `dest` within this consensus system. + /// + /// - `assets`: The asset(s) to be withdrawn. + /// - `dest`: The new owner for the assets. + /// + /// Safety: No concerns. + /// + /// Kind: *Instruction*. + /// + /// Errors: + #[codec(index = 4)] + TransferAsset { assets: Vec<MultiAsset>, dest: MultiLocation }, + + /// Withdraw asset(s) (`assets`) from the ownership of `origin` and place equivalent assets under the + /// ownership of `dest` within this consensus system. + /// + /// Send an onward XCM message to `dest` of `ReserveAssetDeposit` with the given `effects`. + /// + /// - `assets`: The asset(s) to be withdrawn. + /// - `dest`: The new owner for the assets. + /// - `effects`: The orders that should be contained in the `ReserveAssetDeposit` which is sent onwards to + /// `dest`. + /// + /// Safety: No concerns. + /// + /// Kind: *Instruction*. + /// + /// Errors: + #[codec(index = 5)] + TransferReserveAsset { assets: Vec<MultiAsset>, dest: MultiLocation, effects: Vec<Order<()>> }, + + /// Apply the encoded transaction `call`, whose dispatch-origin should be `origin` as expressed by the kind + /// of origin `origin_type`. + /// + /// - `origin_type`: The means of expressing the message origin as a dispatch origin. + /// - `max_weight`: The weight of `call`; this should be at least the chain's calculated weight and will + /// be used in the weight determination arithmetic. + /// - `call`: The encoded transaction to be applied. + /// + /// Safety: No concerns. + /// + /// Kind: *Instruction*. + /// + /// Errors: + #[codec(index = 6)] + Transact { origin_type: OriginKind, require_weight_at_most: u64, call: DoubleEncoded<Call> }, + + /// A message to notify about a new incoming HRMP channel. This message is meant to be sent by the + /// relay-chain to a para. + /// + /// - `sender`: The sender in the to-be opened channel. Also, the initiator of the channel opening. + /// - `max_message_size`: The maximum size of a message proposed by the sender. + /// - `max_capacity`: The maximum number of messages that can be queued in the channel. + /// + /// Safety: The message should originate directly from the relay-chain. + /// + /// Kind: *System Notification* + #[codec(index = 7)] + HrmpNewChannelOpenRequest { + #[codec(compact)] + sender: u32, + #[codec(compact)] + max_message_size: u32, + #[codec(compact)] + max_capacity: u32, + }, + + /// A message to notify about that a previously sent open channel request has been accepted by + /// the recipient. That means that the channel will be opened during the next relay-chain session + /// change. This message is meant to be sent by the relay-chain to a para. + /// + /// Safety: The message should originate directly from the relay-chain. + /// + /// Kind: *System Notification* + /// + /// Errors: + #[codec(index = 8)] + HrmpChannelAccepted { + #[codec(compact)] + recipient: u32, + }, + + /// A message to notify that the other party in an open channel decided to close it. In particular, + /// `initiator` is going to close the channel opened from `sender` to the `recipient`. The close + /// will be enacted at the next relay-chain session change. This message is meant to be sent by + /// the relay-chain to a para. + /// + /// Safety: The message should originate directly from the relay-chain. + /// + /// Kind: *System Notification* + /// + /// Errors: + #[codec(index = 9)] + HrmpChannelClosing { + #[codec(compact)] + initiator: u32, + #[codec(compact)] + sender: u32, + #[codec(compact)] + recipient: u32, + }, + + /// A message to indicate that the embedded XCM is actually arriving on behalf of some consensus + /// location within the origin. + /// + /// Safety: `who` must be an interior location of the context. This basically means that no `Parent` + /// junctions are allowed in it. This should be verified at the time of XCM execution. + /// + /// Kind: *Instruction* + /// + /// Errors: + #[codec(index = 10)] + RelayedFrom { who: MultiLocation, message: alloc::boxed::Box<Xcm<Call>> }, +} + +impl<Call> From<Xcm<Call>> for VersionedXcm<Call> { + fn from(x: Xcm<Call>) -> Self { + VersionedXcm::V0(x) + } +} + +impl<Call> TryFrom<VersionedXcm<Call>> for Xcm<Call> { + type Error = (); + fn try_from(x: VersionedXcm<Call>) -> result::Result<Self, ()> { + match x { + VersionedXcm::V0(x) => Ok(x), + } + } +} + +impl<Call> Xcm<Call> { + pub fn into<C>(self) -> Xcm<C> { + Xcm::from(self) + } + pub fn from<C>(xcm: Xcm<C>) -> Self { + use Xcm::*; + match xcm { + WithdrawAsset { assets, effects } => + WithdrawAsset { assets, effects: effects.into_iter().map(Order::into).collect() }, + ReserveAssetDeposit { assets, effects } => ReserveAssetDeposit { + assets, + effects: effects.into_iter().map(Order::into).collect(), + }, + TeleportAsset { assets, effects } => + TeleportAsset { assets, effects: effects.into_iter().map(Order::into).collect() }, + QueryResponse { query_id: u64, response } => QueryResponse { query_id: u64, response }, + TransferAsset { assets, dest } => TransferAsset { assets, dest }, + TransferReserveAsset { assets, dest, effects } => + TransferReserveAsset { assets, dest, effects }, + HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } => + HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity }, + HrmpChannelAccepted { recipient } => HrmpChannelAccepted { recipient }, + HrmpChannelClosing { initiator, sender, recipient } => + HrmpChannelClosing { initiator, sender, recipient }, + Transact { origin_type, require_weight_at_most, call } => + Transact { origin_type, require_weight_at_most, call: call.into() }, + RelayedFrom { who, message } => + RelayedFrom { who, message: alloc::boxed::Box::new((*message).into()) }, + } + } +} + +pub mod opaque { + /// The basic concrete type of `generic::Xcm`, which doesn't make any assumptions about the format of a + /// call other than it is pre-encoded. + pub type Xcm = super::Xcm<()>; + + pub use super::order::opaque::*; +} diff --git a/xcm/src/v0/multi_asset.rs b/xcm/src/v0/multi_asset.rs new file mode 100644 index 000000000000..9a4b251ab312 --- /dev/null +++ b/xcm/src/v0/multi_asset.rs @@ -0,0 +1,380 @@ +// 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 <http://www.gnu.org/licenses/>. + +//! Cross-Consensus Message format data structures. + +use alloc::vec::Vec; +use core::{convert::TryFrom, result}; + +use super::MultiLocation; +use parity_scale_codec::{self, Decode, Encode}; + +/// A general identifier for an instance of a non-fungible asset class. +#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug)] +pub enum AssetInstance { + /// Undefined - used if the NFA class has only one instance. + Undefined, + + /// A compact index. Technically this could be greater than `u128`, but this implementation supports only + /// values up to `2**128 - 1`. + Index { + #[codec(compact)] + id: u128, + }, + + /// A 4-byte fixed-length datum. + Array4([u8; 4]), + + /// An 8-byte fixed-length datum. + Array8([u8; 8]), + + /// A 16-byte fixed-length datum. + Array16([u8; 16]), + + /// A 32-byte fixed-length datum. + Array32([u8; 32]), + + /// An arbitrary piece of data. Use only when necessary. + Blob(Vec<u8>), +} + +/// A single general identifier for an asset. +/// +/// Represents both fungible and non-fungible assets. May only be used to represent a single asset class. +/// +/// Wildcards may or may not be allowed by the interpreting context. +/// +/// Assets classes may be identified in one of two ways: either an abstract identifier or a concrete identifier. +/// Implementations may support only one of these. A single asset may be referenced from multiple asset identifiers, +/// though will tend to have only a single *preferred* identifier. +/// +/// ### Abstract identifiers +/// +/// Abstract identifiers are absolute identifiers that represent a notional asset which can exist within multiple +/// consensus systems. These tend to be simpler to deal with since their broad meaning is unchanged regardless stay of +/// the consensus system in which it is interpreted. +/// +/// However, in the attempt to provide uniformity across consensus systems, they may conflate different instantiations +/// of some notional asset (e.g. the reserve asset and a local reserve-backed derivative of it) under the same name, +/// leading to confusion. It also implies that one notional asset is accounted for locally in only one way. This may not +/// be the case, e.g. where there are multiple bridge instances each providing a bridged "BTC" token yet none being +/// fungible between the others. +/// +/// Since they are meant to be absolute and universal, a global registry is needed to ensure that name collisions do not +/// occur. +/// +/// An abstract identifier is represented as a simple variable-size byte string. As of writing, no global registry +/// exists and no proposals have been put forth for asset labeling. +/// +/// ### Concrete identifiers +/// +/// Concrete identifiers are *relative identifiers* that specifically identify a single asset through its location in a +/// consensus system relative to the context interpreting. Use of a `MultiLocation` ensures that similar but non +/// fungible variants of the same underlying asset can be properly distinguished, and obviates the need for any kind of +/// central registry. +/// +/// The limitation is that the asset identifier cannot be trivially copied between consensus systems and must instead be +/// "re-anchored" whenever being moved to a new consensus system, using the two systems' relative paths. +/// +/// Throughout XCM, messages are authored such that *when interpreted from the receiver's point of view* they will have +/// the desired meaning/effect. This means that relative paths should always by constructed to be read from the point of +/// view of the receiving system, *which may be have a completely different meaning in the authoring system*. +/// +/// Concrete identifiers are the preferred way of identifying an asset since they are entirely unambiguous. +/// +/// A concrete identifier is represented by a `MultiLocation`. If a system has an unambiguous primary asset (such as +/// Bitcoin with BTC or Ethereum with ETH), then it will conventionally be identified as the chain itself. Alternative +/// and more specific ways of referring to an asset within a system include: +/// +/// - `<chain>/PalletInstance(<id>)` for a Frame chain with a single-asset pallet instance (such as an instance of the +/// Balances pallet). +/// - `<chain>/PalletInstance(<id>)/GeneralIndex(<index>)` for a Frame chain with an indexed multi-asset pallet instance +/// (such as an instance of the Assets pallet). +/// - `<chain>/AccountId32` for an ERC-20-style single-asset smart-contract on a Frame-based contracts chain. +/// - `<chain>/AccountKey20` for an ERC-20-style single-asset smart-contract on an Ethereum-like chain. +/// +#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug)] +pub enum MultiAsset { + /// No assets. Rarely used. + None, + + /// All assets. Typically used for the subset of assets to be used for an `Order`, and in that context means + /// "all assets currently in holding". + All, + + /// All fungible assets. Typically used for the subset of assets to be used for an `Order`, and in that context + /// means "all fungible assets currently in holding". + AllFungible, + + /// All non-fungible assets. Typically used for the subset of assets to be used for an `Order`, and in that + /// context means "all non-fungible assets currently in holding". + AllNonFungible, + + /// All fungible assets of a given abstract asset `id`entifier. + AllAbstractFungible { id: Vec<u8> }, + + /// All non-fungible assets of a given abstract asset `class`. + AllAbstractNonFungible { class: Vec<u8> }, + + /// All fungible assets of a given concrete asset `id`entifier. + AllConcreteFungible { id: MultiLocation }, + + /// All non-fungible assets of a given concrete asset `class`. + AllConcreteNonFungible { class: MultiLocation }, + + /// Some specific `amount` of the fungible asset identified by an abstract `id`. + AbstractFungible { + id: Vec<u8>, + #[codec(compact)] + amount: u128, + }, + + /// Some specific `instance` of the non-fungible asset whose `class` is identified abstractly. + AbstractNonFungible { class: Vec<u8>, instance: AssetInstance }, + + /// Some specific `amount` of the fungible asset identified by an concrete `id`. + ConcreteFungible { + id: MultiLocation, + #[codec(compact)] + amount: u128, + }, + + /// Some specific `instance` of the non-fungible asset whose `class` is identified concretely. + ConcreteNonFungible { class: MultiLocation, instance: AssetInstance }, +} + +impl MultiAsset { + /// Returns `true` if the `MultiAsset` is a wildcard and can refer to classes of assets, instead of just one. + /// + /// Typically can also be inferred by the name starting with `All`. + pub fn is_wildcard(&self) -> bool { + match self { + MultiAsset::None | + MultiAsset::AbstractFungible { .. } | + MultiAsset::AbstractNonFungible { .. } | + MultiAsset::ConcreteFungible { .. } | + MultiAsset::ConcreteNonFungible { .. } => false, + + MultiAsset::All | + MultiAsset::AllFungible | + MultiAsset::AllNonFungible | + MultiAsset::AllAbstractFungible { .. } | + MultiAsset::AllConcreteFungible { .. } | + MultiAsset::AllAbstractNonFungible { .. } | + MultiAsset::AllConcreteNonFungible { .. } => true, + } + } + + fn is_none(&self) -> bool { + match self { + MultiAsset::None | + MultiAsset::AbstractFungible { amount: 0, .. } | + MultiAsset::ConcreteFungible { amount: 0, .. } => true, + + _ => false, + } + } + + fn is_fungible(&self) -> bool { + match self { + MultiAsset::All | + MultiAsset::AllFungible | + MultiAsset::AllAbstractFungible { .. } | + MultiAsset::AllConcreteFungible { .. } | + MultiAsset::AbstractFungible { .. } | + MultiAsset::ConcreteFungible { .. } => true, + + _ => false, + } + } + + fn is_non_fungible(&self) -> bool { + match self { + MultiAsset::All | + MultiAsset::AllNonFungible | + MultiAsset::AllAbstractNonFungible { .. } | + MultiAsset::AllConcreteNonFungible { .. } | + MultiAsset::AbstractNonFungible { .. } | + MultiAsset::ConcreteNonFungible { .. } => true, + + _ => false, + } + } + + fn is_concrete_fungible(&self, id: &MultiLocation) -> bool { + match self { + MultiAsset::AllFungible => true, + MultiAsset::AllConcreteFungible { id: i } | + MultiAsset::ConcreteFungible { id: i, .. } => i == id, + + _ => false, + } + } + + fn is_abstract_fungible(&self, id: &[u8]) -> bool { + match self { + MultiAsset::AllFungible => true, + MultiAsset::AllAbstractFungible { id: i } | + MultiAsset::AbstractFungible { id: i, .. } => i == id, + _ => false, + } + } + + fn is_concrete_non_fungible(&self, class: &MultiLocation) -> bool { + match self { + MultiAsset::AllNonFungible => true, + MultiAsset::AllConcreteNonFungible { class: i } | + MultiAsset::ConcreteNonFungible { class: i, .. } => i == class, + _ => false, + } + } + + fn is_abstract_non_fungible(&self, class: &[u8]) -> bool { + match self { + MultiAsset::AllNonFungible => true, + MultiAsset::AllAbstractNonFungible { class: i } | + MultiAsset::AbstractNonFungible { class: i, .. } => i == class, + _ => false, + } + } + + fn is_all(&self) -> bool { + matches!(self, MultiAsset::All) + } + + /// Returns true if `self` is a super-set of the given `inner`. + /// + /// Typically, any wildcard is never contained in anything else, and a wildcard can contain any other non-wildcard. + /// For more details, see the implementation and tests. + pub fn contains(&self, inner: &MultiAsset) -> bool { + use MultiAsset::*; + + // Inner cannot be wild + if inner.is_wildcard() { + return false + } + // Everything contains nothing. + if inner.is_none() { + return true + } + + // Everything contains anything. + if self.is_all() { + return true + } + // Nothing contains nothing. + if self.is_none() { + return false + } + + match self { + // Anything fungible contains "all fungibles" + AllFungible => inner.is_fungible(), + // Anything non-fungible contains "all non-fungibles" + AllNonFungible => inner.is_non_fungible(), + + AllConcreteFungible { id } => inner.is_concrete_fungible(id), + AllAbstractFungible { id } => inner.is_abstract_fungible(id), + AllConcreteNonFungible { class } => inner.is_concrete_non_fungible(class), + AllAbstractNonFungible { class } => inner.is_abstract_non_fungible(class), + + ConcreteFungible { id, amount } => matches!( + inner, + ConcreteFungible { id: inner_id , amount: inner_amount } if inner_id == id && amount >= inner_amount + ), + AbstractFungible { id, amount } => matches!( + inner, + AbstractFungible { id: inner_id , amount: inner_amount } if inner_id == id && amount >= inner_amount + ), + ConcreteNonFungible { .. } => self == inner, + AbstractNonFungible { .. } => self == inner, + _ => false, + } + } + + pub fn reanchor(&mut self, prepend: &MultiLocation) -> Result<(), ()> { + use MultiAsset::*; + match self { + AllConcreteFungible { ref mut id } | + AllConcreteNonFungible { class: ref mut id } | + ConcreteFungible { ref mut id, .. } | + ConcreteNonFungible { class: ref mut id, .. } => + id.prepend_with(prepend.clone()).map_err(|_| ()), + _ => Ok(()), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn contains_works() { + use alloc::vec; + use MultiAsset::*; + // trivial case: all contains any non-wildcard. + assert!(All.contains(&None)); + assert!(All.contains(&AbstractFungible { id: alloc::vec![99u8], amount: 1 })); + + // trivial case: none contains nothing, except itself. + assert!(None.contains(&None)); + assert!(!None.contains(&AllFungible)); + assert!(!None.contains(&All)); + + // A bit more sneaky: Nothing can contain wildcard, even All ir the thing itself. + assert!(!All.contains(&All)); + assert!(!All.contains(&AllFungible)); + assert!(!AllFungible.contains(&AllFungible)); + assert!(!AllNonFungible.contains(&AllNonFungible)); + + // For fungibles, containing is basically equality, or equal id with higher amount. + assert!(!AbstractFungible { id: vec![99u8], amount: 99 } + .contains(&AbstractFungible { id: vec![1u8], amount: 99 })); + assert!(AbstractFungible { id: vec![99u8], amount: 99 } + .contains(&AbstractFungible { id: vec![99u8], amount: 99 })); + assert!(AbstractFungible { id: vec![99u8], amount: 99 } + .contains(&AbstractFungible { id: vec![99u8], amount: 9 })); + assert!(!AbstractFungible { id: vec![99u8], amount: 99 } + .contains(&AbstractFungible { id: vec![99u8], amount: 100 })); + + // For non-fungibles, containing is equality. + assert!(!AbstractNonFungible { + class: vec![99u8], + instance: AssetInstance::Index { id: 9 } + } + .contains(&AbstractNonFungible { + class: vec![98u8], + instance: AssetInstance::Index { id: 9 } + })); + assert!(!AbstractNonFungible { + class: vec![99u8], + instance: AssetInstance::Index { id: 8 } + } + .contains(&AbstractNonFungible { + class: vec![99u8], + instance: AssetInstance::Index { id: 9 } + })); + assert!(AbstractNonFungible { + class: vec![99u8], + instance: AssetInstance::Index { id: 9 } + } + .contains(&AbstractNonFungible { + class: vec![99u8], + instance: AssetInstance::Index { id: 9 } + })); + } +} diff --git a/xcm/src/v0/multi_location.rs b/xcm/src/v0/multi_location.rs new file mode 100644 index 000000000000..e45df25a0ff6 --- /dev/null +++ b/xcm/src/v0/multi_location.rs @@ -0,0 +1,820 @@ +// Copyright 2020-2021 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 <http://www.gnu.org/licenses/>. + +//! Cross-Consensus Message format data structures. + +use core::{convert::TryFrom, mem, result}; + +use super::Junction; +use crate::VersionedMultiLocation; +use parity_scale_codec::{self, Decode, Encode}; + +/// A relative path between state-bearing consensus systems. +/// +/// A location in a consensus system is defined as an *isolatable state machine* held within global consensus. The +/// location in question need not have a sophisticated consensus algorithm of its own; a single account within +/// Ethereum, for example, could be considered a location. +/// +/// A very-much non-exhaustive list of types of location include: +/// - A (normal, layer-1) block chain, e.g. the Bitcoin mainnet or a parachain. +/// - A layer-0 super-chain, e.g. the Polkadot Relay chain. +/// - A layer-2 smart contract, e.g. an ERC-20 on Ethereum. +/// - A logical functional component of a chain, e.g. a single instance of a pallet on a Frame-based Substrate chain. +/// - An account. +/// +/// 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. +/// +/// This specific `MultiLocation` implementation uses a Rust `enum` in order to make pattern matching easier. +/// +/// The `MultiLocation` value of `Null` simply refers to the interpreting consensus system. +#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug)] +pub enum MultiLocation { + /// The interpreting consensus system. + Null, + /// 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), +} + +/// Maximum number of junctions a `MultiLocation` can contain. +pub const MAX_MULTILOCATION_LENGTH: usize = 8; + +impl From<Junction> for MultiLocation { + fn from(x: Junction) -> Self { + MultiLocation::X1(x) + } +} + +impl From<()> for MultiLocation { + fn from(_: ()) -> Self { + MultiLocation::Null + } +} +impl From<(Junction,)> for MultiLocation { + fn from(x: (Junction,)) -> Self { + MultiLocation::X1(x.0) + } +} +impl From<(Junction, Junction)> for MultiLocation { + fn from(x: (Junction, Junction)) -> Self { + MultiLocation::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) + } +} +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) + } +} +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) + } +} +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) + } +} +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) + } +} +impl From<(Junction, Junction, Junction, Junction, Junction, Junction, Junction, Junction)> + for MultiLocation +{ + 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) + } +} + +impl From<[Junction; 0]> for MultiLocation { + fn from(_: [Junction; 0]) -> Self { + MultiLocation::Null + } +} +impl From<[Junction; 1]> for MultiLocation { + fn from(x: [Junction; 1]) -> Self { + let [x0] = x; + MultiLocation::X1(x0) + } +} +impl From<[Junction; 2]> for MultiLocation { + fn from(x: [Junction; 2]) -> Self { + let [x0, x1] = x; + MultiLocation::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) + } +} +impl From<[Junction; 4]> for MultiLocation { + fn from(x: [Junction; 4]) -> Self { + let [x0, x1, x2, x3] = x; + MultiLocation::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) + } +} +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) + } +} +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) + } +} +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) + } +} + +pub struct MultiLocationIterator(MultiLocation); +impl Iterator for MultiLocationIterator { + type Item = Junction; + fn next(&mut self) -> Option<Junction> { + self.0.take_first() + } +} + +pub struct MultiLocationReverseIterator(MultiLocation); +impl Iterator for MultiLocationReverseIterator { + type Item = Junction; + fn next(&mut self) -> Option<Junction> { + self.0.take_last() + } +} + +pub struct MultiLocationRefIterator<'a>(&'a MultiLocation, usize); +impl<'a> Iterator for MultiLocationRefIterator<'a> { + type Item = &'a Junction; + fn next(&mut self) -> Option<&'a Junction> { + let result = self.0.at(self.1); + self.1 += 1; + result + } +} + +pub struct MultiLocationReverseRefIterator<'a>(&'a MultiLocation, usize); +impl<'a> Iterator for MultiLocationReverseRefIterator<'a> { + type Item = &'a Junction; + fn next(&mut self) -> Option<&'a Junction> { + self.1 += 1; + self.0.at(self.0.len().checked_sub(self.1)?) + } +} + +impl MultiLocation { + /// Returns first junction, or `None` if the location is empty. + pub fn first(&self) -> Option<&Junction> { + match &self { + MultiLocation::Null => 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), + } + } + + /// Returns last junction, or `None` if the location is empty. + pub fn last(&self) -> Option<&Junction> { + match &self { + MultiLocation::Null => 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), + } + } + + /// 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<Junction>) { + match self { + MultiLocation::Null => (MultiLocation::Null, None), + MultiLocation::X1(a) => (MultiLocation::Null, 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)), + } + } + + /// 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<Junction>) { + match self { + MultiLocation::Null => (MultiLocation::Null, None), + MultiLocation::X1(a) => (MultiLocation::Null, 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)), + } + } + + /// Removes the first element from `self`, returning it (or `None` if it was empty). + pub fn take_first(&mut self) -> Option<Junction> { + let mut d = MultiLocation::Null; + mem::swap(&mut *self, &mut d); + let (tail, head) = d.split_first(); + *self = tail; + head + } + + /// Removes the last element from `self`, returning it (or `None` if it was empty). + pub fn take_last(&mut self) -> Option<Junction> { + let mut d = MultiLocation::Null; + 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 + /// `self` in case of overflow. + pub fn pushed_with(self, new: Junction) -> result::Result<Self, Self> { + Ok(match self { + MultiLocation::Null => 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), + s => Err(s)?, + }) + } + + /// 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(self, new: Junction) -> result::Result<Self, Self> { + Ok(match self { + MultiLocation::Null => 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), + s => Err(s)?, + }) + } + + /// Returns the number of junctions in `self`. + pub fn len(&self) -> usize { + match &self { + MultiLocation::Null => 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, + } + } + + /// 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, + _ => return None, + }) + } + + /// Returns a mutable reference to the junction at index `i`, or `None` if the location doesn't contain that many + /// 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, + _ => return None, + }) + } + + /// Returns a reference iterator over the junctions. + pub fn iter(&self) -> MultiLocationRefIterator { + MultiLocationRefIterator(&self, 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) + } + + /// Consumes `self` and returns an iterator over the junctions in reverse. + pub fn into_iter_rev(self) -> MultiLocationReverseIterator { + MultiLocationReverseIterator(self) + } + + /// Ensures that self begins with `prefix` and that it has a single `Junction` item following. + /// If so, returns a reference to this `Junction` item. + /// + /// # Example + /// ```rust + /// # use xcm::v0::{MultiLocation::*, 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); + /// # } + /// ``` + pub fn match_and_split(&self, prefix: &MultiLocation) -> Option<&Junction> { + if prefix.len() + 1 != self.len() { + return None + } + for i in 0..prefix.len() { + if prefix.at(i) != self.at(i) { + return None + } + } + 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::Null; + 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::Null; + 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::Null; + 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::v0::{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::v0::{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"); + } + 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::v0::{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<MultiLocation> for VersionedMultiLocation { + fn from(x: MultiLocation) -> Self { + VersionedMultiLocation::V0(x) + } +} + +impl TryFrom<VersionedMultiLocation> for MultiLocation { + type Error = (); + fn try_from(x: VersionedMultiLocation) -> result::Result<Self, ()> { + match x { + VersionedMultiLocation::V0(x) => Ok(x), + } + } +} + +#[cfg(test)] +mod tests { + use super::MultiLocation::*; + use crate::opaque::v0::{Junction::*, NetworkId::Any}; + + #[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); + assert_eq!( + m.match_and_split(&X2(Parent, Parachain(42))), + Some(&AccountIndex64 { network: Any, index: 23 }) + ); + assert_eq!(m.match_and_split(&m), None); + } + + #[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())); + + // 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()); + 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, + ); + 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); + 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)); + } + + #[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, Null); + + 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, Null); + + let mut m = X4(Parent, Parent, Parachain(1), Parachain(2)); + m.canonicalize(); + assert_eq!(m, X4(Parent, Parent, Parachain(1), Parachain(2))); + } +} diff --git a/xcm/src/v0/order.rs b/xcm/src/v0/order.rs new file mode 100644 index 000000000000..c63df711758f --- /dev/null +++ b/xcm/src/v0/order.rs @@ -0,0 +1,154 @@ +// 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 <http://www.gnu.org/licenses/>. + +//! Version 0 of the Cross-Consensus Message format data structures. + +use super::{MultiAsset, MultiLocation, Xcm}; +use alloc::vec::Vec; +use derivative::Derivative; +use parity_scale_codec::{self, Decode, Encode}; + +/// An instruction to be executed on some or all of the assets in holding, used by asset-related XCM messages. +#[derive(Derivative, Encode, Decode)] +#[derivative(Clone(bound = ""), Eq(bound = ""), PartialEq(bound = ""), Debug(bound = ""))] +#[codec(encode_bound())] +#[codec(decode_bound())] +pub enum Order<Call> { + /// Do nothing. Not generally used. + #[codec(index = 0)] + Null, + + /// Remove the asset(s) (`assets`) from holding and place equivalent assets under the ownership of `dest` within + /// this consensus system. + /// + /// - `assets`: The asset(s) to remove from holding. + /// - `dest`: The new owner for the assets. + /// + /// Errors: + #[codec(index = 1)] + DepositAsset { assets: Vec<MultiAsset>, dest: MultiLocation }, + + /// Remove the asset(s) (`assets`) from holding and place equivalent assets under the ownership of `dest` within + /// this consensus system. + /// + /// Send an onward XCM message to `dest` of `ReserveAssetDeposit` with the given `effects`. + /// + /// - `assets`: The asset(s) to remove from holding. + /// - `dest`: The new owner for the assets. + /// - `effects`: The orders that should be contained in the `ReserveAssetDeposit` which is sent onwards to + /// `dest`. + /// + /// Errors: + #[codec(index = 2)] + DepositReserveAsset { assets: Vec<MultiAsset>, dest: MultiLocation, effects: Vec<Order<()>> }, + + /// Remove the asset(s) (`give`) from holding and replace them with alternative assets. + /// + /// The minimum amount of assets to be received into holding for the order not to fail may be stated. + /// + /// - `give`: The asset(s) to remove from holding. + /// - `receive`: The minimum amount of assets(s) which `give` should be exchanged for. The meaning of wildcards + /// is undefined and they should be not be used. + /// + /// Errors: + #[codec(index = 3)] + ExchangeAsset { give: Vec<MultiAsset>, receive: Vec<MultiAsset> }, + + /// Remove the asset(s) (`assets`) from holding and send a `WithdrawAsset` XCM message to a reserve location. + /// + /// - `assets`: The asset(s) to remove from holding. + /// - `reserve`: A valid location that acts as a reserve for all asset(s) in `assets`. The sovereign account + /// of this consensus system *on the reserve location* will have appropriate assets withdrawn and `effects` will + /// be executed on them. There will typically be only one valid location on any given asset/chain combination. + /// - `effects`: The orders to execute on the assets once withdrawn *on the reserve location*. + /// + /// Errors: + #[codec(index = 4)] + InitiateReserveWithdraw { + assets: Vec<MultiAsset>, + reserve: MultiLocation, + effects: Vec<Order<()>>, + }, + + /// Remove the asset(s) (`assets`) from holding and send a `TeleportAsset` XCM message to a destination location. + /// + /// - `assets`: The asset(s) to remove from holding. + /// - `destination`: A valid location that has a bi-lateral teleportation arrangement. + /// - `effects`: The orders to execute on the assets once arrived *on the destination location*. + /// + /// Errors: + #[codec(index = 5)] + InitiateTeleport { assets: Vec<MultiAsset>, dest: MultiLocation, effects: Vec<Order<()>> }, + + /// Send a `Balances` XCM message with the `assets` value equal to the holding contents, or a portion thereof. + /// + /// - `query_id`: An identifier that will be replicated into the returned XCM message. + /// - `dest`: A valid destination for the returned XCM message. This may be limited to the current origin. + /// - `assets`: A filter for the assets that should be reported back. The assets reported back will be, asset- + /// wise, *the lesser of this value and the holding account*. No wildcards will be used when reporting assets + /// back. + /// + /// Errors: + #[codec(index = 6)] + QueryHolding { + #[codec(compact)] + query_id: u64, + dest: MultiLocation, + assets: Vec<MultiAsset>, + }, + + /// Pay for the execution of some XCM with up to `weight` picoseconds of execution time, paying for this with + /// up to `fees` from the holding account. + /// + /// Errors: + #[codec(index = 7)] + BuyExecution { + fees: MultiAsset, + weight: u64, + debt: u64, + halt_on_error: bool, + xcm: Vec<Xcm<Call>>, + }, +} + +pub mod opaque { + pub type Order = super::Order<()>; +} + +impl<Call> Order<Call> { + pub fn into<C>(self) -> Order<C> { + Order::from(self) + } + pub fn from<C>(order: Order<C>) -> Self { + use Order::*; + match order { + Null => Null, + DepositAsset { assets, dest } => DepositAsset { assets, dest }, + DepositReserveAsset { assets, dest, effects } => + DepositReserveAsset { assets, dest, effects }, + ExchangeAsset { give, receive } => ExchangeAsset { give, receive }, + InitiateReserveWithdraw { assets, reserve, effects } => + InitiateReserveWithdraw { assets, reserve, effects }, + InitiateTeleport { assets, dest, effects } => + InitiateTeleport { assets, dest, effects }, + QueryHolding { query_id, dest, assets } => QueryHolding { query_id, dest, assets }, + BuyExecution { fees, weight, debt, halt_on_error, xcm } => { + let xcm = xcm.into_iter().map(Xcm::from).collect(); + BuyExecution { fees, weight, debt, halt_on_error, xcm } + }, + } + } +} diff --git a/xcm/src/v0/traits.rs b/xcm/src/v0/traits.rs new file mode 100644 index 000000000000..e1673fd5d990 --- /dev/null +++ b/xcm/src/v0/traits.rs @@ -0,0 +1,261 @@ +// 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 <http://www.gnu.org/licenses/>. + +//! Cross-Consensus Message format data structures. + +use core::result; +use parity_scale_codec::{Decode, Encode}; + +use super::{MultiLocation, Xcm}; + +#[derive(Clone, Encode, Decode, Eq, PartialEq, Debug)] +pub enum Error { + Undefined, + /// An arithmetic overflow happened. + Overflow, + /// The operation is intentionally unsupported. + Unimplemented, + UnhandledXcmVersion, + /// The implementation does not handle a given XCM. + UnhandledXcmMessage, + /// The implementation does not handle an effect present in an XCM. + UnhandledEffect, + EscalationOfPrivilege, + UntrustedReserveLocation, + UntrustedTeleportLocation, + DestinationBufferOverflow, + /// The message and destination was recognized as being reachable but the operation could not be completed. + /// A human-readable explanation of the specific issue is provided. + SendFailed(#[codec(skip)] &'static str), + /// The message and destination combination was not recognized as being reachable. + CannotReachDestination(MultiLocation, Xcm<()>), + MultiLocationFull, + FailedToDecode, + BadOrigin, + ExceedsMaxMessageSize, + /// An asset transaction (like withdraw or deposit) failed. + /// See implementers of the `TransactAsset` trait for sources. + /// Causes can include type conversion failures between id or balance types. + FailedToTransactAsset(#[codec(skip)] &'static str), + /// Execution of the XCM would potentially result in a greater weight used than the pre-specified + /// weight limit. The amount that is potentially required is the parameter. + WeightLimitReached(Weight), + /// An asset wildcard was passed where it was not expected (e.g. as the asset to withdraw in a + /// `WithdrawAsset` XCM). + Wildcard, + /// The case where an XCM message has specified a optional weight limit and the weight required for + /// processing is too great. + /// + /// Used by: + /// - `Transact` + TooMuchWeightRequired, + /// The fees specified by the XCM message were not found in the holding account. + /// + /// Used by: + /// - `BuyExecution` + NotHoldingFees, + /// The weight of an XCM message is not computable ahead of execution. This generally means at least part + /// of the message is invalid, which could be due to it containing overly nested structures or an invalid + /// nested data segment (e.g. for the call in `Transact`). + WeightNotComputable, + /// The XCM did not pass the barrier condition for execution. The barrier condition differs on different + /// chains and in different circumstances, but generally it means that the conditions surrounding the message + /// were not such that the chain considers the message worth spending time executing. Since most chains + /// lift the barrier to execution on appropriate payment, presentation of an NFT voucher, or based on the + /// message origin, it means that none of those were the case. + Barrier, + /// Indicates that it is not possible for a location to have an asset be withdrawn or transferred from its + /// ownership. This probably means it doesn't own (enough of) it, but may also indicate that it is under a + /// lock, hold, freeze or is otherwise unavailable. + NotWithdrawable, + /// Indicates that the consensus system cannot deposit an asset under the ownership of a particular location. + LocationCannotHold, + /// The assets given to purchase weight is are insufficient for the weight desired. + TooExpensive, + /// The given asset is not handled. + AssetNotFound, +} + +impl From<()> for Error { + fn from(_: ()) -> Self { + Self::Undefined + } +} + +pub type Result = result::Result<(), Error>; + +/// Local weight type; execution time in picoseconds. +pub type Weight = u64; + +/// Outcome of an XCM execution. +#[derive(Clone, Encode, Decode, Eq, PartialEq, Debug)] +pub enum Outcome { + /// Execution completed successfully; given weight was used. + Complete(Weight), + /// Execution started, but did not complete successfully due to the given error; given weight was used. + Incomplete(Weight, Error), + /// Execution did not start due to the given error. + Error(Error), +} + +impl Outcome { + pub fn ensure_complete(self) -> Result { + match self { + Outcome::Complete(_) => Ok(()), + Outcome::Incomplete(_, e) => Err(e), + Outcome::Error(e) => Err(e), + } + } + pub fn ensure_execution(self) -> result::Result<Weight, Error> { + match self { + Outcome::Complete(w) => Ok(w), + Outcome::Incomplete(w, _) => Ok(w), + Outcome::Error(e) => Err(e), + } + } + /// How much weight was used by the XCM execution attempt. + pub fn weight_used(&self) -> Weight { + match self { + Outcome::Complete(w) => *w, + Outcome::Incomplete(w, _) => *w, + Outcome::Error(_) => 0, + } + } +} + +/// Type of XCM message executor. +pub trait ExecuteXcm<Call> { + /// Execute some XCM `message` from `origin` using no more than `weight_limit` weight. The weight limit is + /// a basic hard-limit and the implementation may place further restrictions or requirements on weight and + /// other aspects. + fn execute_xcm(origin: MultiLocation, message: Xcm<Call>, weight_limit: Weight) -> Outcome { + log::debug!( + target: "xcm::execute_xcm", + "origin: {:?}, message: {:?}, weight_limit: {:?}", + origin, + message, + weight_limit, + ); + Self::execute_xcm_in_credit(origin, message, weight_limit, 0) + } + + /// Execute some XCM `message` from `origin` using no more than `weight_limit` weight. + /// + /// Some amount of `weight_credit` may be provided which, depending on the implementation, may allow + /// execution without associated payment. + fn execute_xcm_in_credit( + origin: MultiLocation, + message: Xcm<Call>, + weight_limit: Weight, + weight_credit: Weight, + ) -> Outcome; +} + +impl<C> ExecuteXcm<C> for () { + fn execute_xcm_in_credit( + _origin: MultiLocation, + _message: Xcm<C>, + _weight_limit: Weight, + _weight_credit: Weight, + ) -> Outcome { + Outcome::Error(Error::Unimplemented) + } +} + +/// Utility for sending an XCM message. +/// +/// These can be amalgamated in tuples to form sophisticated routing systems. In tuple format, each router might return +/// `CannotReachDestination` to pass the execution to the next sender item. Note that each `CannotReachDestination` +/// might alter the destination and the XCM message for to the next router. +/// +/// +/// # Example +/// ```rust +/// # use xcm::v0::{MultiLocation, Xcm, Junction, Error, OriginKind, SendXcm, Result}; +/// # use parity_scale_codec::Encode; +/// +/// /// A sender that only passes the message through and does nothing. +/// struct Sender1; +/// impl SendXcm for Sender1 { +/// fn send_xcm(destination: MultiLocation, message: Xcm<()>) -> Result { +/// return Err(Error::CannotReachDestination(destination, message)) +/// } +/// } +/// +/// /// A sender that accepts a message that has an X2 junction, otherwise stops the routing. +/// struct Sender2; +/// impl SendXcm for Sender2 { +/// fn send_xcm(destination: MultiLocation, message: Xcm<()>) -> Result { +/// if let MultiLocation::X2(j1, j2) = destination { +/// Ok(()) +/// } else { +/// Err(Error::Undefined) +/// } +/// } +/// } +/// +/// /// A sender that accepts a message from an X1 parent junction, passing through otherwise. +/// struct Sender3; +/// impl SendXcm for Sender3 { +/// fn send_xcm(destination: MultiLocation, message: Xcm<()>) -> Result { +/// match destination { +/// MultiLocation::X1(j) if j == Junction::Parent => Ok(()), +/// _ => Err(Error::CannotReachDestination(destination, message)), +/// } +/// } +/// } +/// +/// // A call to send via XCM. We don't really care about this. +/// # fn main() { +/// let call: Vec<u8> = ().encode(); +/// let message = Xcm::Transact { origin_type: OriginKind::Superuser, require_weight_at_most: 0, call: call.into() }; +/// let destination = MultiLocation::X1(Junction::Parent); +/// +/// assert!( +/// // Sender2 will block this. +/// <(Sender1, Sender2, Sender3) as SendXcm>::send_xcm(destination.clone(), message.clone()) +/// .is_err() +/// ); +/// +/// assert!( +/// // Sender3 will catch this. +/// <(Sender1, Sender3) as SendXcm>::send_xcm(destination.clone(), message.clone()) +/// .is_ok() +/// ); +/// # } +/// ``` +pub trait SendXcm { + /// Send an XCM `message` to a given `destination`. + /// + /// If it is not a destination which can be reached with this type but possibly could by others, then it *MUST* + /// return `CannotReachDestination`. Any other error will cause the tuple implementation to exit early without + /// trying other type fields. + fn send_xcm(destination: MultiLocation, message: Xcm<()>) -> Result; +} + +#[impl_trait_for_tuples::impl_for_tuples(30)] +impl SendXcm for Tuple { + fn send_xcm(destination: MultiLocation, message: Xcm<()>) -> Result { + for_tuples!( #( + // we shadow `destination` and `message` in each expansion for the next one. + let (destination, message) = match Tuple::send_xcm(destination, message) { + Err(Error::CannotReachDestination(d, m)) => (d, m), + o @ _ => return o, + }; + )* ); + Err(Error::CannotReachDestination(destination, message)) + } +} From 9f8606d7e6e2870f884989167bb061a7be705c07 Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Thu, 5 Aug 2021 11:30:39 +0200 Subject: [PATCH 090/166] Remove VersionedMultiLocation --- xcm/src/lib.rs | 24 +----------------------- xcm/src/v0/multi_location.rs | 16 ---------------- 2 files changed, 1 insertion(+), 39 deletions(-) diff --git a/xcm/src/lib.rs b/xcm/src/lib.rs index 0300e8f23c6d..d12d9e864a69 100644 --- a/xcm/src/lib.rs +++ b/xcm/src/lib.rs @@ -27,6 +27,7 @@ use core::{convert::TryFrom, result::Result}; use derivative::Derivative; use parity_scale_codec::{Decode, Encode, Error as CodecError, Input}; +pub mod v0; pub mod v1; pub mod latest { @@ -92,26 +93,3 @@ pub mod opaque { /// The basic `VersionedXcm` type which just uses the `Vec<u8>` as an encoded call. pub type VersionedXcm = super::VersionedXcm<()>; } - -/// A versioned multi-location, a relative location of a cross-consensus system identifier. -#[derive(Clone, Eq, PartialEq, Encode, Decode, Debug)] -pub enum VersionedMultiLocation { - V0(v0::MultiLocation), - V1(v1::MultiLocation), -} - -impl From<v1::MultiLocation> for VersionedMultiLocation { - fn from(x: v1::MultiLocation) -> Self { - VersionedMultiLocation::V1(x) - } -} - -impl TryFrom<VersionedMultiLocation> for v1::MultiLocation { - type Error = (); - fn try_from(x: VersionedMultiLocation) -> Result<Self, ()> { - match x { - VersionedMultiLocation::V0(x) => Ok(x), - VersionedMultiLocation::V1(x) => Ok(x), - } - } -} diff --git a/xcm/src/v0/multi_location.rs b/xcm/src/v0/multi_location.rs index e45df25a0ff6..a54610ea6509 100644 --- a/xcm/src/v0/multi_location.rs +++ b/xcm/src/v0/multi_location.rs @@ -19,7 +19,6 @@ use core::{convert::TryFrom, mem, result}; use super::Junction; -use crate::VersionedMultiLocation; use parity_scale_codec::{self, Decode, Encode}; /// A relative path between state-bearing consensus systems. @@ -697,21 +696,6 @@ impl MultiLocation { } } -impl From<MultiLocation> for VersionedMultiLocation { - fn from(x: MultiLocation) -> Self { - VersionedMultiLocation::V0(x) - } -} - -impl TryFrom<VersionedMultiLocation> for MultiLocation { - type Error = (); - fn try_from(x: VersionedMultiLocation) -> result::Result<Self, ()> { - match x { - VersionedMultiLocation::V0(x) => Ok(x), - } - } -} - #[cfg(test)] mod tests { use super::MultiLocation::*; From 1c4a89a6504b384fcf0ef1130c7840286ce9eac5 Mon Sep 17 00:00:00 2001 From: Gavin Wood <gavin@parity.io> Date: Thu, 5 Aug 2021 12:35:44 +0200 Subject: [PATCH 091/166] Update xcm/src/v1/order.rs Co-authored-by: Amar Singh <asinghchrony@protonmail.com> --- xcm/src/v1/order.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xcm/src/v1/order.rs b/xcm/src/v1/order.rs index 0c92e5c4ce8c..e588bdf40e25 100644 --- a/xcm/src/v1/order.rs +++ b/xcm/src/v1/order.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see <http://www.gnu.org/licenses/>. -//! Version 0 of the Cross-Consensus Message format data structures. +//! Version 1 of the Cross-Consensus Message format data structures. use super::{MultiAsset, MultiAssetFilter, MultiLocation, Xcm}; use alloc::vec::Vec; From d3fb09069eb505eb1903fc32b377b326e796237e Mon Sep 17 00:00:00 2001 From: Gavin Wood <gavin@parity.io> Date: Thu, 5 Aug 2021 12:35:49 +0200 Subject: [PATCH 092/166] Update xcm/src/v1/mod.rs Co-authored-by: Amar Singh <asinghchrony@protonmail.com> --- xcm/src/v1/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xcm/src/v1/mod.rs b/xcm/src/v1/mod.rs index c78506c5c042..535e8ad11333 100644 --- a/xcm/src/v1/mod.rs +++ b/xcm/src/v1/mod.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see <http://www.gnu.org/licenses/>. -//! Version 0 of the Cross-Consensus Message format data structures. +//! Version 1 of the Cross-Consensus Message format data structures. use crate::DoubleEncoded; use alloc::vec::Vec; From a5c2bde937926c2c8acfaa317c97b7e65d1d7be8 Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Thu, 5 Aug 2021 13:33:55 +0200 Subject: [PATCH 093/166] XCM v0 backwards compatibility --- xcm/src/lib.rs | 5 +- xcm/src/v0/junction.rs | 194 ----------------------------------- xcm/src/v0/mod.rs | 40 +------- xcm/src/v0/multi_asset.rs | 43 ++------ xcm/src/v0/multi_location.rs | 2 +- xcm/src/v1/junction.rs | 5 +- xcm/src/v1/mod.rs | 45 +++++++- xcm/src/v1/multiasset.rs | 93 ++++++++++++++++- xcm/src/v1/multilocation.rs | 18 ++++ xcm/src/v1/order.rs | 32 +++++- 10 files changed, 198 insertions(+), 279 deletions(-) delete mode 100644 xcm/src/v0/junction.rs diff --git a/xcm/src/lib.rs b/xcm/src/lib.rs index d12d9e864a69..5e39800da19c 100644 --- a/xcm/src/lib.rs +++ b/xcm/src/lib.rs @@ -23,7 +23,7 @@ #![no_std] extern crate alloc; -use core::{convert::TryFrom, result::Result}; +use core::{convert::{TryFrom, TryInto}, result::Result}; use derivative::Derivative; use parity_scale_codec::{Decode, Encode, Error as CodecError, Input}; @@ -66,8 +66,9 @@ impl<Call> TryFrom<VersionedXcm<Call>> for v1::Xcm<Call> { type Error = (); fn try_from(x: VersionedXcm<Call>) -> Result<Self, ()> { match x { + // v1-based chains can interpret v0 messages. + VersionedXcm::V0(x) => x.try_into(), VersionedXcm::V1(x) => Ok(x), - _ => Err(()), } } } diff --git a/xcm/src/v0/junction.rs b/xcm/src/v0/junction.rs deleted file mode 100644 index cf474f62851a..000000000000 --- a/xcm/src/v0/junction.rs +++ /dev/null @@ -1,194 +0,0 @@ -// 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 <http://www.gnu.org/licenses/>. - -//! Support data structures for `MultiLocation`, primarily the `Junction` datatype. - -use alloc::vec::Vec; -use parity_scale_codec::{self, Decode, Encode}; - -/// A global identifier of an account-bearing consensus system. -#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug)] -pub enum NetworkId { - /// Unidentified/any. - Any, - /// Some named network. - Named(Vec<u8>), - /// The Polkadot Relay chain - Polkadot, - /// Kusama. - Kusama, -} - -/// An identifier of a pluralistic body. -#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug)] -pub enum BodyId { - /// The only body in its context. - Unit, - /// A named body. - Named(Vec<u8>), - /// An indexed body. - // TODO: parity-scale-codec#262: Change to be a tuple. - Index { - #[codec(compact)] - id: u32, - }, - /// The unambiguous executive body (for Polkadot, this would be the Polkadot council). - Executive, - /// The unambiguous technical body (for Polkadot, this would be the Technical Committee). - Technical, - /// The unambiguous legislative body (for Polkadot, this could be considered the opinion of a majority of - /// lock-voters). - Legislative, - /// The unambiguous judicial body (this doesn't exist on Polkadot, but if it were to get a "grand oracle", it - /// may be considered as that). - Judicial, -} - -/// A part of a pluralistic body. -#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug)] -pub enum BodyPart { - /// The body's declaration, under whatever means it decides. - Voice, - /// A given number of members of the body. - Members { - #[codec(compact)] - count: u32, - }, - /// A given number of members of the body, out of some larger caucus. - Fraction { - #[codec(compact)] - nom: u32, - #[codec(compact)] - denom: u32, - }, - /// No less than the given proportion of members of the body. - AtLeastProportion { - #[codec(compact)] - nom: u32, - #[codec(compact)] - denom: u32, - }, - /// More than than the given proportion of members of the body. - MoreThanProportion { - #[codec(compact)] - nom: u32, - #[codec(compact)] - denom: u32, - }, -} - -impl BodyPart { - /// Returns `true` if the part represents a strict majority (> 50%) of the body in question. - pub fn is_majority(&self) -> bool { - match self { - BodyPart::Fraction { nom, denom } if *nom * 2 > *denom => true, - BodyPart::AtLeastProportion { nom, denom } if *nom * 2 > *denom => true, - BodyPart::MoreThanProportion { nom, denom } if *nom * 2 >= *denom => true, - _ => false, - } - } -} - -/// 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 { - /// The consensus system of which the context is a member and state-wise super-set. - /// - /// NOTE: This item is *not* a sub-consensus item: a consensus system may not identify itself trustlessly as - /// a location that includes this junction. - Parent, - /// 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)] - id: 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<u8>), - /// 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 Junction { - /// Returns true if this junction is a `Parent` item. - pub fn is_parent(&self) -> bool { - match self { - Junction::Parent => true, - _ => false, - } - } - - /// Returns true if this junction can be considered an interior part of its context. This is generally `true`, - /// except for the `Parent` item. - pub fn is_interior(&self) -> bool { - match self { - Junction::Parent => false, - - Junction::Parachain(..) | - Junction::AccountId32 { .. } | - Junction::AccountIndex64 { .. } | - Junction::AccountKey20 { .. } | - Junction::PalletInstance { .. } | - Junction::GeneralIndex { .. } | - Junction::GeneralKey(..) | - Junction::OnlyChild | - Junction::Plurality { .. } => true, - } - } -} diff --git a/xcm/src/v0/mod.rs b/xcm/src/v0/mod.rs index 6ebfe3a960a1..ffef612499c6 100644 --- a/xcm/src/v0/mod.rs +++ b/xcm/src/v0/mod.rs @@ -18,16 +18,14 @@ use crate::{DoubleEncoded, VersionedXcm}; use alloc::vec::Vec; -use core::{convert::TryFrom, fmt::Debug, result}; +use core::{convert::TryFrom, result}; use derivative::Derivative; use parity_scale_codec::{self, Decode, Encode}; -mod junction; mod multi_asset; mod multi_location; mod order; mod traits; -pub use junction::{BodyId, BodyPart, Junction, NetworkId}; pub use multi_asset::{AssetInstance, MultiAsset}; pub use multi_location::MultiLocation; pub use order::Order; @@ -36,7 +34,7 @@ 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, BodyPart, Junction::*, NetworkId}, + BodyId, BodyPart, Junction::*, NetworkId, multi_asset::{ AssetInstance::{self, *}, MultiAsset::{self, *}, @@ -49,38 +47,7 @@ pub mod prelude { }; } -// TODO: #2841 #XCMENCODE Efficient encodings for Vec<MultiAsset>, Vec<Order>, using initial byte values 128+ to encode -// the number of items in the vector. - -/// Basically just the XCM (more general) version of `ParachainDispatchOrigin`. -#[derive(Copy, Clone, Eq, PartialEq, Encode, Decode, Debug)] -pub enum OriginKind { - /// Origin should just be the native dispatch origin representation for the sender in the - /// local runtime framework. For Cumulus/Frame chains this is the `Parachain` or `Relay` origin - /// if coming from a chain, though there may be others if the `MultiLocation` XCM origin has a - /// primary/native dispatch origin form. - Native, - - /// Origin should just be the standard account-based origin with the sovereign account of - /// the sender. For Cumulus/Frame chains, this is the `Signed` origin. - SovereignAccount, - - /// Origin should be the super-user. For Cumulus/Frame chains, this is the `Root` origin. - /// This will not usually be an available option. - Superuser, - - /// Origin should be interpreted as an XCM native origin and the `MultiLocation` should be - /// encoded directly in the dispatch origin unchanged. For Cumulus/Frame chains, this will be - /// the `pallet_xcm::Origin::Xcm` type. - Xcm, -} - -/// Response data to a query. -#[derive(Clone, Eq, PartialEq, Encode, Decode, Debug)] -pub enum Response { - /// Some assets. - Assets(Vec<MultiAsset>), -} +pub use super::v1::{Response, OriginKind, BodyId, BodyPart, Junction, NetworkId}; /// Cross-Consensus Message: A message from one consensus system to another. /// @@ -286,6 +253,7 @@ impl<Call> TryFrom<VersionedXcm<Call>> for Xcm<Call> { fn try_from(x: VersionedXcm<Call>) -> result::Result<Self, ()> { match x { VersionedXcm::V0(x) => Ok(x), + VersionedXcm::V1(_) => Err(()), // v0-based chains cannot interpret v1 messages. } } } diff --git a/xcm/src/v0/multi_asset.rs b/xcm/src/v0/multi_asset.rs index 9a4b251ab312..d89d13dd4e0c 100644 --- a/xcm/src/v0/multi_asset.rs +++ b/xcm/src/v0/multi_asset.rs @@ -17,39 +17,10 @@ //! Cross-Consensus Message format data structures. use alloc::vec::Vec; -use core::{convert::TryFrom, result}; - use super::MultiLocation; use parity_scale_codec::{self, Decode, Encode}; -/// A general identifier for an instance of a non-fungible asset class. -#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug)] -pub enum AssetInstance { - /// Undefined - used if the NFA class has only one instance. - Undefined, - - /// A compact index. Technically this could be greater than `u128`, but this implementation supports only - /// values up to `2**128 - 1`. - Index { - #[codec(compact)] - id: u128, - }, - - /// A 4-byte fixed-length datum. - Array4([u8; 4]), - - /// An 8-byte fixed-length datum. - Array8([u8; 8]), - - /// A 16-byte fixed-length datum. - Array16([u8; 16]), - - /// A 32-byte fixed-length datum. - Array32([u8; 32]), - - /// An arbitrary piece of data. Use only when necessary. - Blob(Vec<u8>), -} +pub use super::super::v1::AssetInstance; /// A single general identifier for an asset. /// @@ -354,27 +325,27 @@ mod tests { // For non-fungibles, containing is equality. assert!(!AbstractNonFungible { class: vec![99u8], - instance: AssetInstance::Index { id: 9 } + instance: AssetInstance::Index(9) } .contains(&AbstractNonFungible { class: vec![98u8], - instance: AssetInstance::Index { id: 9 } + instance: AssetInstance::Index(9) })); assert!(!AbstractNonFungible { class: vec![99u8], - instance: AssetInstance::Index { id: 8 } + instance: AssetInstance::Index(8) } .contains(&AbstractNonFungible { class: vec![99u8], - instance: AssetInstance::Index { id: 9 } + instance: AssetInstance::Index(9) })); assert!(AbstractNonFungible { class: vec![99u8], - instance: AssetInstance::Index { id: 9 } + instance: AssetInstance::Index(9) } .contains(&AbstractNonFungible { class: vec![99u8], - instance: AssetInstance::Index { id: 9 } + instance: AssetInstance::Index(9) })); } } diff --git a/xcm/src/v0/multi_location.rs b/xcm/src/v0/multi_location.rs index a54610ea6509..41ef20dfffd9 100644 --- a/xcm/src/v0/multi_location.rs +++ b/xcm/src/v0/multi_location.rs @@ -16,7 +16,7 @@ //! Cross-Consensus Message format data structures. -use core::{convert::TryFrom, mem, result}; +use core::{mem, result}; use super::Junction; use parity_scale_codec::{self, Decode, Encode}; diff --git a/xcm/src/v1/junction.rs b/xcm/src/v1/junction.rs index cf474f62851a..981756f5536b 100644 --- a/xcm/src/v1/junction.rs +++ b/xcm/src/v1/junction.rs @@ -41,10 +41,7 @@ pub enum BodyId { Named(Vec<u8>), /// An indexed body. // TODO: parity-scale-codec#262: Change to be a tuple. - Index { - #[codec(compact)] - id: u32, - }, + Index(#[codec(compact)] u32), /// The unambiguous executive body (for Polkadot, this would be the Polkadot council). Executive, /// The unambiguous technical body (for Polkadot, this would be the Technical Committee). diff --git a/xcm/src/v1/mod.rs b/xcm/src/v1/mod.rs index c78506c5c042..41d909074651 100644 --- a/xcm/src/v1/mod.rs +++ b/xcm/src/v1/mod.rs @@ -18,7 +18,8 @@ use crate::DoubleEncoded; use alloc::vec::Vec; -use core::fmt::Debug; +use core::{fmt::Debug, convert::{TryFrom, TryInto}, result}; +use super::v0::{Xcm as Xcm0, MultiLocation as MultiLocation0}; use derivative::Derivative; use parity_scale_codec::{self, Decode, Encode}; @@ -37,6 +38,7 @@ pub use multilocation::MultiLocation; 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::{ @@ -332,3 +334,44 @@ pub mod opaque { pub use super::order::opaque::*; } + +impl<Call> TryFrom<Xcm0<Call>> for Xcm<Call> { + type Error = (); + fn try_from(old: Xcm0<Call>) -> result::Result<Xcm<Call>, ()> { + use Xcm::*; + Ok(match old { + Xcm0::WithdrawAsset { assets, effects } => + WithdrawAsset { + assets: assets.try_into()?, + effects: effects.into_iter() + .map(Order::try_from) + .collect::<result::Result<_, _>>()?, + }, + Xcm0::ReserveAssetDeposit { assets, effects } => ReserveAssetDeposited { + assets: assets.try_into()?, + effects: effects.into_iter().map(Order::try_from).collect::<result::Result<_, _>>()?, + }, + Xcm0::TeleportAsset { assets, effects } => ReceiveTeleportedAsset { + assets: assets.try_into()?, + effects: effects.into_iter().map(Order::try_from).collect::<result::Result<_, _>>()?, + }, + Xcm0::QueryResponse { query_id: u64, response } => QueryResponse { query_id: u64, response }, + Xcm0::TransferAsset { assets, dest } => TransferAsset { assets: assets.try_into()?, beneficiary: dest.into() }, + Xcm0::TransferReserveAsset { assets, dest, effects } => + TransferReserveAsset { + assets: assets.try_into()?, + dest: dest.into(), + effects: effects.into_iter().map(Order::try_from).collect::<result::Result<_, _>>()?, + }, + Xcm0::HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } => + HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity }, + Xcm0::HrmpChannelAccepted { recipient } => HrmpChannelAccepted { recipient }, + Xcm0::HrmpChannelClosing { initiator, sender, recipient } => + HrmpChannelClosing { initiator, sender, recipient }, + 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(), message: alloc::boxed::Box::new((*message).try_into()?) }, + }) + } +} diff --git a/xcm/src/v1/multiasset.rs b/xcm/src/v1/multiasset.rs index a52725a58c1a..1b9f693ce054 100644 --- a/xcm/src/v1/multiasset.rs +++ b/xcm/src/v1/multiasset.rs @@ -28,7 +28,7 @@ use super::{ MultiLocation::{self, X1}, }; use alloc::{vec, vec::Vec}; -use core::cmp::Ordering; +use core::{cmp::Ordering, convert::{TryFrom, TryInto}, result}; use parity_scale_codec::{self as codec, Decode, Encode}; /// A general identifier for an instance of a non-fungible asset class. @@ -231,6 +231,44 @@ impl MultiAsset { } } +impl TryFrom<super::super::v0::MultiAsset> for MultiAsset { + type Error = (); + fn try_from(old: super::super::v0::MultiAsset) -> result::Result<MultiAsset, ()> { + use super::super::v0::MultiAsset as V0; + use Fungibility::*; + use AssetId::*; + let (id, fun) = match old { + V0::ConcreteFungible { id, amount } => (Concrete(id.into()), Fungible(amount)), + V0::ConcreteNonFungible { class, instance } => (Concrete(class.into()), NonFungible(instance)), + V0::AbstractFungible { id, amount } => (Abstract(id), Fungible(amount)), + V0::AbstractNonFungible { class, instance } => (Abstract(class), NonFungible(instance)), + _ => return Err(()), + }; + Ok(MultiAsset { id, fun }) + } +} + +impl TryFrom<super::super::v0::MultiAsset> for Option<MultiAsset> { + type Error = (); + fn try_from(old: super::super::v0::MultiAsset) -> result::Result<Option<MultiAsset>, ()> { + match old { + super::super::v0::MultiAsset::None => return Ok(None), + x => return Ok(Some(x.try_into()?)), + } + } +} + +impl TryFrom<Vec<super::super::v0::MultiAsset>> for MultiAsset { + type Error = (); + fn try_from(mut old: Vec<super::super::v0::MultiAsset>) -> result::Result<MultiAsset, ()> { + if old.len() == 1 { + old.remove(0).try_into() + } else { + Err(()) + } + } +} + /// A `Vec` of `MultiAsset`s. There may be no duplicate fungible items in here and when decoding, they must be sorted. #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode)] pub struct MultiAssets(Vec<MultiAsset>); @@ -242,6 +280,17 @@ impl Decode for MultiAssets { } } +impl TryFrom<Vec<super::super::v0::MultiAsset>> for MultiAssets { + type Error = (); + fn try_from(old: Vec<super::super::v0::MultiAsset>) -> result::Result<MultiAssets, ()> { + let v = old.into_iter() + .map(Option::<MultiAsset>::try_from) + .filter_map(|x| x.transpose()) + .collect::<result::Result<Vec<MultiAsset>, ()>>()?; + Ok(v.into()) + } +} + impl From<Vec<MultiAsset>> for MultiAssets { fn from(mut assets: Vec<MultiAsset>) -> Self { let mut res = Vec::with_capacity(assets.len()); @@ -390,7 +439,36 @@ pub enum WildMultiAsset { All, /// All assets in the holding register of a given fungibility and ID. If operating on non-fungibles, then a limit /// is provided for the maximum amount of matching instances. - AllOf { fun: WildFungibility, id: AssetId }, + AllOf { id: AssetId, fun: WildFungibility }, +} + +impl TryFrom<super::super::v0::MultiAsset> for WildMultiAsset { + type Error = (); + fn try_from(old: super::super::v0::MultiAsset) -> result::Result<WildMultiAsset, ()> { + use super::super::v0::MultiAsset as V0; + use WildFungibility::*; + use AssetId::*; + 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::AllAbstractFungible { id } => (Abstract(id), Fungible), + V0::AllAbstractNonFungible { class } => (Abstract(class), NonFungible), + _ => return Err(()), + }; + Ok(WildMultiAsset::AllOf { id, fun }) + } +} + +impl TryFrom<Vec<super::super::v0::MultiAsset>> for WildMultiAsset { + type Error = (); + fn try_from(mut old: Vec<super::super::v0::MultiAsset>) -> result::Result<WildMultiAsset, ()> { + if old.len() == 1 { + old.remove(0).try_into() + } else { + Err(()) + } + } } impl WildMultiAsset { @@ -476,3 +554,14 @@ impl MultiAssetFilter { } } } + +impl TryFrom<Vec<super::super::v0::MultiAsset>> for MultiAssetFilter { + type Error = (); + fn try_from(mut old: Vec<super::super::v0::MultiAsset>) -> result::Result<MultiAssetFilter, ()> { + if old.len() == 1 && old[0].is_wildcard() { + Ok(MultiAssetFilter::Wild(old.remove(0).try_into()?)) + } else { + Ok(MultiAssetFilter::Definite(old.try_into()?)) + } + } +} diff --git a/xcm/src/v1/multilocation.rs b/xcm/src/v1/multilocation.rs index e44d5f76a289..1181cdea9ef5 100644 --- a/xcm/src/v1/multilocation.rs +++ b/xcm/src/v1/multilocation.rs @@ -696,6 +696,24 @@ impl MultiLocation { } } +impl From<super::MultiLocation0> for MultiLocation { + fn from(old: super::MultiLocation0) -> Self { + use MultiLocation::*; + use super::MultiLocation0; + 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), + } + } +} + #[cfg(test)] mod tests { use super::MultiLocation::*; diff --git a/xcm/src/v1/order.rs b/xcm/src/v1/order.rs index 0c92e5c4ce8c..e6abaa81e696 100644 --- a/xcm/src/v1/order.rs +++ b/xcm/src/v1/order.rs @@ -16,8 +16,9 @@ //! Version 0 of the Cross-Consensus Message format data structures. -use super::{MultiAsset, MultiAssetFilter, MultiLocation, Xcm}; -use alloc::vec::Vec; +use core::{convert::{TryFrom, TryInto}, result}; +use alloc::{vec, vec::Vec}; +use super::{MultiAsset, MultiAssets, MultiAssetFilter, MultiLocation, Xcm}; use derivative::Derivative; use parity_scale_codec::{self, Decode, Encode}; @@ -76,7 +77,7 @@ pub enum Order<Call> { /// /// Errors: #[codec(index = 3)] - ExchangeAsset { give: MultiAssetFilter, receive: Vec<MultiAsset> }, + ExchangeAsset { give: MultiAssetFilter, receive: MultiAssets }, /// Remove the asset(s) (`assets`) from holding and send a `WithdrawAsset` XCM message to a reserve location. /// @@ -181,3 +182,28 @@ impl<Call> Order<Call> { } } } + +impl<Call> TryFrom<super::super::v0::Order<Call>> for Order<Call> { + type Error = (); + fn try_from(old: super::super::v0::Order<Call>) -> result::Result<Order<Call>, ()> { + use Order::*; + use super::super::v0::Order as Order0; + Ok(match old { + Order0::Null => Noop, + Order0::DepositAsset { assets, dest } => + DepositAsset { assets: assets.try_into()?, max_assets: 1, beneficiary: dest.into() }, + Order0::DepositReserveAsset { assets, dest, effects } => + DepositReserveAsset { assets: assets.try_into()?, max_assets: 1, dest: dest.into(), effects: effects.into_iter().map(Order::<()>::try_from).collect::<result::Result<_, _>>()? }, + Order0::ExchangeAsset { give, receive } => ExchangeAsset { give: give.try_into()?, receive: receive.try_into()? }, + Order0::InitiateReserveWithdraw { assets, reserve, effects } => + InitiateReserveWithdraw { assets: assets.try_into()?, reserve: reserve.into(), effects: effects.into_iter().map(Order::<()>::try_from).collect::<result::Result<_, _>>()? }, + Order0::InitiateTeleport { assets, dest, effects } => + InitiateTeleport { assets: assets.try_into()?, dest: dest.into(), effects: effects.into_iter().map(Order::<()>::try_from).collect::<result::Result<_, _>>()? }, + Order0::QueryHolding { query_id, dest, assets } => QueryHolding { query_id, dest: dest.into(), assets: assets.try_into()? }, + Order0::BuyExecution { fees, weight, debt, halt_on_error, xcm } => { + let instructions = xcm.into_iter().map(Xcm::<Call>::try_from).collect::<result::Result<_, _>>()?; + BuyExecution { fees: fees.try_into()?, weight, debt, halt_on_error, orders: vec![], instructions } + }, + }) + } +} From 7130ed71671649ee0e44ca8817944398e29410d4 Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Thu, 5 Aug 2021 15:01:58 +0200 Subject: [PATCH 094/166] Full compatibility --- runtime/common/src/xcm_sender.rs | 17 +++++----- runtime/kusama/src/lib.rs | 2 +- runtime/rococo/src/lib.rs | 2 +- runtime/westend/src/lib.rs | 2 +- xcm/src/v0/mod.rs | 44 +++++++++++++++++++++++++- xcm/src/v0/multi_asset.rs | 53 ++++++++++++++++++++++++++++++-- xcm/src/v0/multi_location.rs | 19 +++++++++++- xcm/src/v0/order.rs | 29 +++++++++++++++++ xcm/src/v1/mod.rs | 6 ++-- xcm/src/v1/multilocation.rs | 8 ++--- xcm/src/v1/order.rs | 6 ++-- xcm/src/v1/traits.rs | 25 +++++++++++++-- 12 files changed, 185 insertions(+), 28 deletions(-) diff --git a/runtime/common/src/xcm_sender.rs b/runtime/common/src/xcm_sender.rs index 819f9b0b0617..247c345873ac 100644 --- a/runtime/common/src/xcm_sender.rs +++ b/runtime/common/src/xcm_sender.rs @@ -20,28 +20,29 @@ 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}, - VersionedXcm, + v1::{Error, Junction, MultiLocation, Result, SendXcm, Xcm, WrapVersion}, }; +use xcm::v1::prelude::XcmError; /// XCM sender for relay chain. It only sends downward message. -pub struct ChildParachainRouter<T>(PhantomData<T>); +pub struct ChildParachainRouter<T, W>(PhantomData<(T, W)>); -impl<T: configuration::Config + dmp::Config> SendXcm for ChildParachainRouter<T> { +impl<T: configuration::Config + dmp::Config, W: WrapVersion> SendXcm for ChildParachainRouter<T, W> { fn send_xcm(dest: MultiLocation, msg: Xcm) -> Result { - match dest { + match &dest { MultiLocation::X1(Junction::Parachain(id)) => { // Downward message passing. + let versioned_xcm = W::wrap_version(&dest, msg).map_err(|()| Error::DestinationUnsupported)?; let config = <configuration::Pallet<T>>::config(); <dmp::Pallet<T>>::queue_downward_message( &config, - id.into(), - VersionedXcm::from(msg).encode(), + (*id).into(), + versioned_xcm.encode(), ) .map_err(Into::<Error>::into)?; Ok(()) }, - d => Err(Error::CannotReachDestination(d, msg)), + d => Err(Error::CannotReachDestination(dest, msg)), } } } diff --git a/runtime/kusama/src/lib.rs b/runtime/kusama/src/lib.rs index 32a5455b8d13..dc00d4d7a7ea 100644 --- a/runtime/kusama/src/lib.rs +++ b/runtime/kusama/src/lib.rs @@ -1258,7 +1258,7 @@ parameter_types! { /// individual routers. pub type XcmRouter = ( // Only one router so far - use DMP to communicate with child parachains. - xcm_sender::ChildParachainRouter<Runtime>, + xcm_sender::ChildParachainRouter<Runtime, ForceV0>, ); parameter_types! { diff --git a/runtime/rococo/src/lib.rs b/runtime/rococo/src/lib.rs index c82e777f7f02..a195289f15ba 100644 --- a/runtime/rococo/src/lib.rs +++ b/runtime/rococo/src/lib.rs @@ -620,7 +620,7 @@ parameter_types! { /// individual routers. pub type XcmRouter = ( // Only one router so far - use DMP to communicate with child parachains. - xcm_sender::ChildParachainRouter<Runtime>, + xcm_sender::ChildParachainRouter<Runtime, ForceV0>, ); parameter_types! { diff --git a/runtime/westend/src/lib.rs b/runtime/westend/src/lib.rs index 9944efa1f5f4..d7b00dd550db 100644 --- a/runtime/westend/src/lib.rs +++ b/runtime/westend/src/lib.rs @@ -903,7 +903,7 @@ parameter_types! { /// individual routers. pub type XcmRouter = ( // Only one router so far - use DMP to communicate with child parachains. - xcm_sender::ChildParachainRouter<Runtime>, + xcm_sender::ChildParachainRouter<Runtime, ForceV0>, ); parameter_types! { diff --git a/xcm/src/v0/mod.rs b/xcm/src/v0/mod.rs index ffef612499c6..f54732c56ffa 100644 --- a/xcm/src/v0/mod.rs +++ b/xcm/src/v0/mod.rs @@ -18,7 +18,7 @@ use crate::{DoubleEncoded, VersionedXcm}; 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}; @@ -30,6 +30,7 @@ pub use multi_asset::{AssetInstance, MultiAsset}; pub use multi_location::MultiLocation; pub use order::Order; pub use traits::{Error, ExecuteXcm, Outcome, Result, SendXcm}; +use super::v1::Xcm as Xcm1; /// A prelude for importing all types typically used when interacting with XCM messages. pub mod prelude { @@ -297,3 +298,44 @@ pub mod opaque { pub use super::order::opaque::*; } + +impl<Call> TryFrom<Xcm1<Call>> for Xcm<Call> { + type Error = (); + fn try_from(x: Xcm1<Call>) -> result::Result<Xcm<Call>, ()> { + use Xcm::*; + Ok(match x { + Xcm1::WithdrawAsset { assets, effects } => + WithdrawAsset { + assets: assets.into(), + effects: effects.into_iter() + .map(Order::try_from) + .collect::<result::Result<_, _>>()?, + }, + Xcm1::ReserveAssetDeposited { assets, effects } => ReserveAssetDeposit { + assets: assets.into(), + effects: effects.into_iter().map(Order::try_from).collect::<result::Result<_, _>>()?, + }, + Xcm1::ReceiveTeleportedAsset { assets, effects } => TeleportAsset { + assets: assets.into(), + effects: effects.into_iter().map(Order::try_from).collect::<result::Result<_, _>>()?, + }, + Xcm1::QueryResponse { query_id: u64, response } => QueryResponse { query_id: u64, response }, + Xcm1::TransferAsset { assets, beneficiary } => TransferAsset { assets: assets.into(), dest: beneficiary.into() }, + Xcm1::TransferReserveAsset { assets, dest, effects } => + TransferReserveAsset { + assets: assets.into(), + dest: dest.into(), + effects: effects.into_iter().map(Order::try_from).collect::<result::Result<_, _>>()?, + }, + Xcm1::HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } => + HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity }, + Xcm1::HrmpChannelAccepted { recipient } => HrmpChannelAccepted { recipient }, + Xcm1::HrmpChannelClosing { initiator, sender, recipient } => + HrmpChannelClosing { initiator, sender, recipient }, + 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(), 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 d89d13dd4e0c..696576453b65 100644 --- a/xcm/src/v0/multi_asset.rs +++ b/xcm/src/v0/multi_asset.rs @@ -16,11 +16,12 @@ //! Cross-Consensus Message format data structures. -use alloc::vec::Vec; +use alloc::{vec, vec::Vec}; use super::MultiLocation; use parity_scale_codec::{self, Decode, Encode}; +use crate::v1::{MultiAsset as MultiAsset1, WildMultiAsset, MultiAssetFilter, MultiAssets}; -pub use super::super::v1::AssetInstance; +pub use crate::v1::AssetInstance; /// A single general identifier for an asset. /// @@ -289,6 +290,54 @@ impl MultiAsset { } } +impl From<MultiAsset1> for MultiAsset { + fn from(a: MultiAsset1) -> MultiAsset { + use MultiAsset::*; + use crate::v1::{Fungibility::*, AssetId::*}; + match (a.id, a.fun) { + (Concrete(id), Fungible(amount)) => ConcreteFungible { id: id.into(), amount }, + (Concrete(class), NonFungible(instance)) => ConcreteNonFungible { class: class.into(), instance }, + (Abstract(id), Fungible(amount)) => AbstractFungible { id, amount }, + (Abstract(class), NonFungible(instance)) => AbstractNonFungible { class, instance }, + } + } +} + +impl From<MultiAssets> for Vec<MultiAsset> { + fn from(a: MultiAssets) -> Vec<MultiAsset> { + a.drain().into_iter().map(MultiAsset::from).collect() + } +} + +impl From<WildMultiAsset> for MultiAsset { + fn from(a: WildMultiAsset) -> MultiAsset { + use MultiAsset::*; + use crate::v1::{WildFungibility::*, AssetId::*}; + match a { + WildMultiAsset::All => All, + WildMultiAsset::AllOf { id, fun } => match (id, fun) { + (Concrete(id), Fungible) => AllConcreteFungible { id: id.into()}, + (Concrete(class), NonFungible) => AllConcreteNonFungible { class: class.into()}, + (Abstract(id), Fungible) => AllAbstractFungible { id}, + (Abstract(class), NonFungible) => AllAbstractNonFungible { class}, + } + } + } +} + +impl From<WildMultiAsset> for Vec<MultiAsset> { + fn from(a: WildMultiAsset) -> Vec<MultiAsset> { vec![a.into()] } +} + +impl From<MultiAssetFilter> for Vec<MultiAsset> { + fn from(a: MultiAssetFilter) -> Vec<MultiAsset> { + match a { + MultiAssetFilter::Definite(assets) => assets.into(), + MultiAssetFilter::Wild(wildcard) => wildcard.into(), + } + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/xcm/src/v0/multi_location.rs b/xcm/src/v0/multi_location.rs index 41ef20dfffd9..311ec67c190c 100644 --- a/xcm/src/v0/multi_location.rs +++ b/xcm/src/v0/multi_location.rs @@ -18,7 +18,7 @@ use core::{mem, result}; -use super::Junction; +use super::{Junction, super::v1::MultiLocation as MultiLocation1}; use parity_scale_codec::{self, Decode, Encode}; /// A relative path between state-bearing consensus systems. @@ -696,6 +696,23 @@ impl MultiLocation { } } +impl From<MultiLocation1> 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), + } + } +} + #[cfg(test)] mod tests { use super::MultiLocation::*; diff --git a/xcm/src/v0/order.rs b/xcm/src/v0/order.rs index c63df711758f..de4059558cc9 100644 --- a/xcm/src/v0/order.rs +++ b/xcm/src/v0/order.rs @@ -18,8 +18,10 @@ use super::{MultiAsset, MultiLocation, Xcm}; use alloc::vec::Vec; +use core::{result, convert::TryFrom}; use derivative::Derivative; use parity_scale_codec::{self, Decode, Encode}; +use super::super::v1::Order as Order1; /// An instruction to be executed on some or all of the assets in holding, used by asset-related XCM messages. #[derive(Derivative, Encode, Decode)] @@ -152,3 +154,30 @@ impl<Call> Order<Call> { } } } + +impl<Call> TryFrom<Order1<Call>> for Order<Call> { + type Error = (); + fn try_from(old: Order1<Call>) -> result::Result<Order<Call>, ()> { + use Order::*; + Ok(match old { + Order1::Noop => Null, + Order1::DepositAsset { assets, beneficiary, .. } => + DepositAsset { assets: assets.into(), dest: beneficiary.into() }, + Order1::DepositReserveAsset { assets, dest, effects, .. } => + DepositReserveAsset { assets: assets.into(), dest: dest.into(), effects: effects.into_iter().map(Order::<()>::try_from).collect::<result::Result<_, _>>()? }, + Order1::ExchangeAsset { give, receive } => ExchangeAsset { give: give.into(), receive: receive.into() }, + Order1::InitiateReserveWithdraw { assets, reserve, effects } => + InitiateReserveWithdraw { assets: assets.into(), reserve: reserve.into(), effects: effects.into_iter().map(Order::<()>::try_from).collect::<result::Result<_, _>>()? }, + Order1::InitiateTeleport { assets, dest, effects } => + InitiateTeleport { assets: assets.into(), dest: dest.into(), effects: effects.into_iter().map(Order::<()>::try_from).collect::<result::Result<_, _>>()? }, + Order1::QueryHolding { query_id, dest, assets } => QueryHolding { query_id, dest: dest.into(), assets: assets.into() }, + Order1::BuyExecution { fees, weight, debt, halt_on_error, instructions, orders } => { + if !orders.is_empty() { + return Err(()) + } + let xcm = instructions.into_iter().map(Xcm::<Call>::try_from).collect::<result::Result<_, _>>()?; + BuyExecution { fees: fees.into(), weight, debt, halt_on_error, xcm } + }, + }) + } +} diff --git a/xcm/src/v1/mod.rs b/xcm/src/v1/mod.rs index c3e5f1d63b09..1a24e48c9bcc 100644 --- a/xcm/src/v1/mod.rs +++ b/xcm/src/v1/mod.rs @@ -19,7 +19,7 @@ use crate::DoubleEncoded; use alloc::vec::Vec; use core::{fmt::Debug, convert::{TryFrom, TryInto}, result}; -use super::v0::{Xcm as Xcm0, MultiLocation as MultiLocation0}; +use super::v0::Xcm as Xcm0; use derivative::Derivative; use parity_scale_codec::{self, Decode, Encode}; @@ -36,7 +36,7 @@ pub use multiasset::{ }; pub use multilocation::MultiLocation; pub use order::Order; -pub use traits::{Error, ExecuteXcm, Outcome, Result, SendXcm}; +pub use traits::{Error, ExecuteXcm, Outcome, Result, SendXcm, WrapVersion}; /// A prelude for importing all types typically used when interacting with XCM messages. @@ -60,7 +60,7 @@ pub mod prelude { multilocation::MultiLocation::{self, *}, opaque, order::Order::{self, *}, - traits::{Error as XcmError, ExecuteXcm, Outcome, Result as XcmResult, SendXcm}, + traits::{Error as XcmError, ExecuteXcm, Outcome, Result as XcmResult, SendXcm, ForceV0}, OriginKind, Response, Xcm::{self, *}, }; diff --git a/xcm/src/v1/multilocation.rs b/xcm/src/v1/multilocation.rs index 1181cdea9ef5..4a9866c90eb1 100644 --- a/xcm/src/v1/multilocation.rs +++ b/xcm/src/v1/multilocation.rs @@ -17,8 +17,7 @@ //! Cross-Consensus Message format data structures. use core::{mem, result}; - -use super::Junction; +use super::{Junction, super::v0::MultiLocation as MultiLocation0}; use parity_scale_codec::{self, Decode, Encode}; /// A relative path between state-bearing consensus systems. @@ -696,10 +695,9 @@ impl MultiLocation { } } -impl From<super::MultiLocation0> for MultiLocation { - fn from(old: super::MultiLocation0) -> Self { +impl From<MultiLocation0> for MultiLocation { + fn from(old: MultiLocation0) -> Self { use MultiLocation::*; - use super::MultiLocation0; match old { MultiLocation0::Null => Here, MultiLocation0::X1(j0) => X1(j0), diff --git a/xcm/src/v1/order.rs b/xcm/src/v1/order.rs index 93dc82b13a39..7010b1f580e3 100644 --- a/xcm/src/v1/order.rs +++ b/xcm/src/v1/order.rs @@ -21,6 +21,7 @@ use alloc::{vec, vec::Vec}; use super::{MultiAsset, MultiAssets, MultiAssetFilter, MultiLocation, Xcm}; use derivative::Derivative; use parity_scale_codec::{self, Decode, Encode}; +use super::super::v0::Order as Order0; /// An instruction to be executed on some or all of the assets in holding, used by asset-related XCM messages. #[derive(Derivative, Encode, Decode)] @@ -183,11 +184,10 @@ impl<Call> Order<Call> { } } -impl<Call> TryFrom<super::super::v0::Order<Call>> for Order<Call> { +impl<Call> TryFrom<Order0<Call>> for Order<Call> { type Error = (); - fn try_from(old: super::super::v0::Order<Call>) -> result::Result<Order<Call>, ()> { + fn try_from(old: Order0<Call>) -> result::Result<Order<Call>, ()> { use Order::*; - use super::super::v0::Order as Order0; Ok(match old { Order0::Null => Noop, Order0::DepositAsset { assets, dest } => diff --git a/xcm/src/v1/traits.rs b/xcm/src/v1/traits.rs index fc1c3ce88b57..e05759b59e16 100644 --- a/xcm/src/v1/traits.rs +++ b/xcm/src/v1/traits.rs @@ -16,10 +16,10 @@ //! Cross-Consensus Message format data structures. -use core::result; +use core::{result, convert::TryInto}; use parity_scale_codec::{Decode, Encode}; -use super::{MultiLocation, Xcm}; +use super::{MultiLocation, Xcm, super::VersionedXcm}; #[derive(Clone, Encode, Decode, Eq, PartialEq, Debug)] pub enum Error { @@ -87,6 +87,8 @@ pub enum Error { TooExpensive, /// The given asset is not handled. AssetNotFound, + /// The given message cannot be translated into a format that the destination can be expected to interpret. + DestinationUnsupported, } impl From<()> for Error { @@ -259,3 +261,22 @@ impl SendXcm for Tuple { Err(Error::CannotReachDestination(destination, message)) } } + +/// Convert an `Xcm` datum into a `VersionedXcm`, based on a destination `MultiLocation` which will interpret it. +pub trait WrapVersion { + fn wrap_version<Call>(dest: &MultiLocation, xcm: Xcm<Call>) -> result::Result<VersionedXcm<Call>, ()>; +} + +impl WrapVersion for () { + fn wrap_version<Call>(_: &MultiLocation, xcm: Xcm<Call>) -> result::Result<VersionedXcm<Call>, ()> { + Ok(VersionedXcm::<Call>::from(xcm)) + } +} + +/// `WrapVersion` implementation which attempts to always convert the XCM to version 0 before wrapping it. +pub struct ForceV0; +impl WrapVersion for ForceV0 { + fn wrap_version<Call>(_: &MultiLocation, xcm: Xcm<Call>) -> result::Result<VersionedXcm<Call>, ()> { + Ok(VersionedXcm::<Call>::V0(xcm.try_into()?)) + } +} From efa012dbc31eebf5089309c8bdc944b27fa1ee02 Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Thu, 5 Aug 2021 15:51:00 +0200 Subject: [PATCH 095/166] fmt --- runtime/common/src/xcm_sender.rs | 14 +++---- xcm/src/lib.rs | 5 ++- xcm/src/v0/mod.rs | 66 ++++++++++++++++++++------------ xcm/src/v0/multi_asset.rs | 64 ++++++++++++++----------------- xcm/src/v0/multi_location.rs | 5 ++- xcm/src/v0/order.rs | 45 ++++++++++++++++------ xcm/src/v1/mod.rs | 61 ++++++++++++++++++----------- xcm/src/v1/multiasset.rs | 20 +++++++--- xcm/src/v1/multilocation.rs | 5 ++- xcm/src/v1/order.rs | 58 ++++++++++++++++++++++------ xcm/src/v1/traits.rs | 19 ++++++--- 11 files changed, 233 insertions(+), 129 deletions(-) diff --git a/runtime/common/src/xcm_sender.rs b/runtime/common/src/xcm_sender.rs index 247c345873ac..4c2575a3face 100644 --- a/runtime/common/src/xcm_sender.rs +++ b/runtime/common/src/xcm_sender.rs @@ -19,20 +19,20 @@ 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, WrapVersion}, -}; -use xcm::v1::prelude::XcmError; +use xcm::opaque::v1::{Error, Junction, MultiLocation, Result, SendXcm, WrapVersion, Xcm}; /// XCM sender for relay chain. It only sends downward message. pub struct ChildParachainRouter<T, W>(PhantomData<(T, W)>); -impl<T: configuration::Config + dmp::Config, W: WrapVersion> SendXcm for ChildParachainRouter<T, W> { +impl<T: configuration::Config + dmp::Config, W: WrapVersion> SendXcm + for ChildParachainRouter<T, W> +{ fn send_xcm(dest: MultiLocation, msg: Xcm) -> Result { match &dest { MultiLocation::X1(Junction::Parachain(id)) => { // Downward message passing. - let versioned_xcm = W::wrap_version(&dest, msg).map_err(|()| Error::DestinationUnsupported)?; + let versioned_xcm = + W::wrap_version(&dest, msg).map_err(|()| Error::DestinationUnsupported)?; let config = <configuration::Pallet<T>>::config(); <dmp::Pallet<T>>::queue_downward_message( &config, @@ -42,7 +42,7 @@ impl<T: configuration::Config + dmp::Config, W: WrapVersion> SendXcm for ChildPa .map_err(Into::<Error>::into)?; Ok(()) }, - d => Err(Error::CannotReachDestination(dest, msg)), + _ => Err(Error::CannotReachDestination(dest, msg)), } } } diff --git a/xcm/src/lib.rs b/xcm/src/lib.rs index 5e39800da19c..4bce0086eca8 100644 --- a/xcm/src/lib.rs +++ b/xcm/src/lib.rs @@ -23,7 +23,10 @@ #![no_std] extern crate alloc; -use core::{convert::{TryFrom, TryInto}, result::Result}; +use core::{ + convert::{TryFrom, TryInto}, + result::Result, +}; use derivative::Derivative; use parity_scale_codec::{Decode, Encode, Error as CodecError, Input}; diff --git a/xcm/src/v0/mod.rs b/xcm/src/v0/mod.rs index f54732c56ffa..54b1a0e25267 100644 --- a/xcm/src/v0/mod.rs +++ b/xcm/src/v0/mod.rs @@ -18,7 +18,10 @@ use crate::{DoubleEncoded, VersionedXcm}; use alloc::vec::Vec; -use core::{convert::{TryFrom, TryInto}, result}; +use core::{ + convert::{TryFrom, TryInto}, + result, +}; use derivative::Derivative; use parity_scale_codec::{self, Decode, Encode}; @@ -26,16 +29,15 @@ mod multi_asset; mod multi_location; mod order; mod traits; +use super::v1::Xcm as Xcm1; pub use multi_asset::{AssetInstance, MultiAsset}; pub use multi_location::MultiLocation; pub use order::Order; pub use traits::{Error, ExecuteXcm, Outcome, Result, SendXcm}; -use super::v1::Xcm as Xcm1; /// A prelude for importing all types typically used when interacting with XCM messages. pub mod prelude { pub use super::{ - BodyId, BodyPart, Junction::*, NetworkId, multi_asset::{ AssetInstance::{self, *}, MultiAsset::{self, *}, @@ -43,12 +45,14 @@ pub mod prelude { multi_location::MultiLocation::{self, *}, order::Order::{self, *}, traits::{Error as XcmError, ExecuteXcm, Outcome, Result as XcmResult, SendXcm}, - OriginKind, + BodyId, BodyPart, + Junction::*, + NetworkId, OriginKind, Xcm::{self, *}, }; } -pub use super::v1::{Response, OriginKind, BodyId, BodyPart, Junction, NetworkId}; +pub use super::v1::{BodyId, BodyPart, Junction, NetworkId, OriginKind, Response}; /// Cross-Consensus Message: A message from one consensus system to another. /// @@ -254,7 +258,7 @@ impl<Call> TryFrom<VersionedXcm<Call>> for Xcm<Call> { fn try_from(x: VersionedXcm<Call>) -> result::Result<Self, ()> { match x { VersionedXcm::V0(x) => Ok(x), - VersionedXcm::V1(_) => Err(()), // v0-based chains cannot interpret v1 messages. + VersionedXcm::V1(_) => Err(()), // v0-based chains cannot interpret v1 messages. } } } @@ -304,29 +308,39 @@ impl<Call> TryFrom<Xcm1<Call>> for Xcm<Call> { fn try_from(x: Xcm1<Call>) -> result::Result<Xcm<Call>, ()> { use Xcm::*; Ok(match x { - Xcm1::WithdrawAsset { assets, effects } => - WithdrawAsset { - assets: assets.into(), - effects: effects.into_iter() - .map(Order::try_from) - .collect::<result::Result<_, _>>()?, - }, + Xcm1::WithdrawAsset { assets, effects } => WithdrawAsset { + assets: assets.into(), + effects: effects + .into_iter() + .map(Order::try_from) + .collect::<result::Result<_, _>>()?, + }, Xcm1::ReserveAssetDeposited { assets, effects } => ReserveAssetDeposit { assets: assets.into(), - effects: effects.into_iter().map(Order::try_from).collect::<result::Result<_, _>>()?, + effects: effects + .into_iter() + .map(Order::try_from) + .collect::<result::Result<_, _>>()?, }, Xcm1::ReceiveTeleportedAsset { assets, effects } => TeleportAsset { assets: assets.into(), - effects: effects.into_iter().map(Order::try_from).collect::<result::Result<_, _>>()?, + effects: effects + .into_iter() + .map(Order::try_from) + .collect::<result::Result<_, _>>()?, + }, + Xcm1::QueryResponse { query_id: u64, response } => + QueryResponse { query_id: u64, response }, + Xcm1::TransferAsset { assets, beneficiary } => + TransferAsset { assets: assets.into(), dest: beneficiary.into() }, + Xcm1::TransferReserveAsset { assets, dest, effects } => TransferReserveAsset { + assets: assets.into(), + dest: dest.into(), + effects: effects + .into_iter() + .map(Order::try_from) + .collect::<result::Result<_, _>>()?, }, - Xcm1::QueryResponse { query_id: u64, response } => QueryResponse { query_id: u64, response }, - Xcm1::TransferAsset { assets, beneficiary } => TransferAsset { assets: assets.into(), dest: beneficiary.into() }, - Xcm1::TransferReserveAsset { assets, dest, effects } => - TransferReserveAsset { - assets: assets.into(), - dest: dest.into(), - effects: effects.into_iter().map(Order::try_from).collect::<result::Result<_, _>>()?, - }, Xcm1::HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } => HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity }, Xcm1::HrmpChannelAccepted { recipient } => HrmpChannelAccepted { recipient }, @@ -334,8 +348,10 @@ impl<Call> TryFrom<Xcm1<Call>> for Xcm<Call> { HrmpChannelClosing { initiator, sender, recipient }, 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(), message: alloc::boxed::Box::new((*message).try_into()?) }, + Xcm1::RelayedFrom { who, message } => RelayedFrom { + who: who.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 696576453b65..3225e38a213a 100644 --- a/xcm/src/v0/multi_asset.rs +++ b/xcm/src/v0/multi_asset.rs @@ -16,10 +16,10 @@ //! Cross-Consensus Message format data structures. -use alloc::{vec, vec::Vec}; use super::MultiLocation; +use crate::v1::{MultiAsset as MultiAsset1, MultiAssetFilter, MultiAssets, WildMultiAsset}; +use alloc::{vec, vec::Vec}; use parity_scale_codec::{self, Decode, Encode}; -use crate::v1::{MultiAsset as MultiAsset1, WildMultiAsset, MultiAssetFilter, MultiAssets}; pub use crate::v1::AssetInstance; @@ -292,11 +292,12 @@ impl MultiAsset { impl From<MultiAsset1> for MultiAsset { fn from(a: MultiAsset1) -> MultiAsset { + use crate::v1::{AssetId::*, Fungibility::*}; use MultiAsset::*; - use crate::v1::{Fungibility::*, AssetId::*}; match (a.id, a.fun) { (Concrete(id), Fungible(amount)) => ConcreteFungible { id: id.into(), amount }, - (Concrete(class), NonFungible(instance)) => ConcreteNonFungible { class: class.into(), instance }, + (Concrete(class), NonFungible(instance)) => + ConcreteNonFungible { class: class.into(), instance }, (Abstract(id), Fungible(amount)) => AbstractFungible { id, amount }, (Abstract(class), NonFungible(instance)) => AbstractNonFungible { class, instance }, } @@ -311,22 +312,24 @@ impl From<MultiAssets> for Vec<MultiAsset> { impl From<WildMultiAsset> for MultiAsset { fn from(a: WildMultiAsset) -> MultiAsset { + use crate::v1::{AssetId::*, WildFungibility::*}; use MultiAsset::*; - use crate::v1::{WildFungibility::*, AssetId::*}; match a { WildMultiAsset::All => All, WildMultiAsset::AllOf { id, fun } => match (id, fun) { - (Concrete(id), Fungible) => AllConcreteFungible { id: id.into()}, - (Concrete(class), NonFungible) => AllConcreteNonFungible { class: class.into()}, - (Abstract(id), Fungible) => AllAbstractFungible { id}, - (Abstract(class), NonFungible) => AllAbstractNonFungible { class}, - } + (Concrete(id), Fungible) => AllConcreteFungible { id: id.into() }, + (Concrete(class), NonFungible) => AllConcreteNonFungible { class: class.into() }, + (Abstract(id), Fungible) => AllAbstractFungible { id }, + (Abstract(class), NonFungible) => AllAbstractNonFungible { class }, + }, } } } impl From<WildMultiAsset> for Vec<MultiAsset> { - fn from(a: WildMultiAsset) -> Vec<MultiAsset> { vec![a.into()] } + fn from(a: WildMultiAsset) -> Vec<MultiAsset> { + vec![a.into()] + } } impl From<MultiAssetFilter> for Vec<MultiAsset> { @@ -372,29 +375,20 @@ mod tests { .contains(&AbstractFungible { id: vec![99u8], amount: 100 })); // For non-fungibles, containing is equality. - assert!(!AbstractNonFungible { - class: vec![99u8], - instance: AssetInstance::Index(9) - } - .contains(&AbstractNonFungible { - class: vec![98u8], - instance: AssetInstance::Index(9) - })); - assert!(!AbstractNonFungible { - class: vec![99u8], - instance: AssetInstance::Index(8) - } - .contains(&AbstractNonFungible { - class: vec![99u8], - instance: AssetInstance::Index(9) - })); - assert!(AbstractNonFungible { - class: vec![99u8], - instance: AssetInstance::Index(9) - } - .contains(&AbstractNonFungible { - class: vec![99u8], - instance: AssetInstance::Index(9) - })); + assert!(!AbstractNonFungible { class: vec![99u8], instance: AssetInstance::Index(9) } + .contains(&AbstractNonFungible { + class: vec![98u8], + instance: AssetInstance::Index(9) + })); + assert!(!AbstractNonFungible { class: vec![99u8], instance: AssetInstance::Index(8) } + .contains(&AbstractNonFungible { + class: vec![99u8], + instance: AssetInstance::Index(9) + })); + assert!(AbstractNonFungible { class: vec![99u8], instance: AssetInstance::Index(9) } + .contains(&AbstractNonFungible { + class: vec![99u8], + instance: AssetInstance::Index(9) + })); } } diff --git a/xcm/src/v0/multi_location.rs b/xcm/src/v0/multi_location.rs index 311ec67c190c..1426529f2fdb 100644 --- a/xcm/src/v0/multi_location.rs +++ b/xcm/src/v0/multi_location.rs @@ -18,7 +18,7 @@ use core::{mem, result}; -use super::{Junction, super::v1::MultiLocation as MultiLocation1}; +use super::{super::v1::MultiLocation as MultiLocation1, Junction}; use parity_scale_codec::{self, Decode, Encode}; /// A relative path between state-bearing consensus systems. @@ -708,7 +708,8 @@ impl From<MultiLocation1> for MultiLocation { 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), + MultiLocation1::X8(j0, j1, j2, j3, j4, j5, j6, j7) => + X8(j0, j1, j2, j3, j4, j5, j6, j7), } } } diff --git a/xcm/src/v0/order.rs b/xcm/src/v0/order.rs index de4059558cc9..3ce20d22bdd8 100644 --- a/xcm/src/v0/order.rs +++ b/xcm/src/v0/order.rs @@ -16,12 +16,11 @@ //! Version 0 of the Cross-Consensus Message format data structures. -use super::{MultiAsset, MultiLocation, Xcm}; +use super::{super::v1::Order as Order1, MultiAsset, MultiLocation, Xcm}; use alloc::vec::Vec; -use core::{result, convert::TryFrom}; +use core::{convert::TryFrom, result}; use derivative::Derivative; use parity_scale_codec::{self, Decode, Encode}; -use super::super::v1::Order as Order1; /// An instruction to be executed on some or all of the assets in holding, used by asset-related XCM messages. #[derive(Derivative, Encode, Decode)] @@ -163,19 +162,43 @@ impl<Call> TryFrom<Order1<Call>> for Order<Call> { Order1::Noop => Null, Order1::DepositAsset { assets, beneficiary, .. } => DepositAsset { assets: assets.into(), dest: beneficiary.into() }, - Order1::DepositReserveAsset { assets, dest, effects, .. } => - DepositReserveAsset { assets: assets.into(), dest: dest.into(), effects: effects.into_iter().map(Order::<()>::try_from).collect::<result::Result<_, _>>()? }, - Order1::ExchangeAsset { give, receive } => ExchangeAsset { give: give.into(), receive: receive.into() }, + Order1::DepositReserveAsset { assets, dest, effects, .. } => DepositReserveAsset { + assets: assets.into(), + dest: dest.into(), + effects: effects + .into_iter() + .map(Order::<()>::try_from) + .collect::<result::Result<_, _>>()?, + }, + Order1::ExchangeAsset { give, receive } => + ExchangeAsset { give: give.into(), receive: receive.into() }, Order1::InitiateReserveWithdraw { assets, reserve, effects } => - InitiateReserveWithdraw { assets: assets.into(), reserve: reserve.into(), effects: effects.into_iter().map(Order::<()>::try_from).collect::<result::Result<_, _>>()? }, - Order1::InitiateTeleport { assets, dest, effects } => - InitiateTeleport { assets: assets.into(), dest: dest.into(), effects: effects.into_iter().map(Order::<()>::try_from).collect::<result::Result<_, _>>()? }, - Order1::QueryHolding { query_id, dest, assets } => QueryHolding { query_id, dest: dest.into(), assets: assets.into() }, + InitiateReserveWithdraw { + assets: assets.into(), + reserve: reserve.into(), + effects: effects + .into_iter() + .map(Order::<()>::try_from) + .collect::<result::Result<_, _>>()?, + }, + Order1::InitiateTeleport { assets, dest, effects } => InitiateTeleport { + assets: assets.into(), + dest: dest.into(), + effects: effects + .into_iter() + .map(Order::<()>::try_from) + .collect::<result::Result<_, _>>()?, + }, + Order1::QueryHolding { query_id, dest, assets } => + QueryHolding { query_id, dest: dest.into(), assets: assets.into() }, Order1::BuyExecution { fees, weight, debt, halt_on_error, instructions, orders } => { if !orders.is_empty() { return Err(()) } - let xcm = instructions.into_iter().map(Xcm::<Call>::try_from).collect::<result::Result<_, _>>()?; + let xcm = instructions + .into_iter() + .map(Xcm::<Call>::try_from) + .collect::<result::Result<_, _>>()?; BuyExecution { fees: fees.into(), weight, debt, halt_on_error, xcm } }, }) diff --git a/xcm/src/v1/mod.rs b/xcm/src/v1/mod.rs index 1a24e48c9bcc..99ba9be3b0bb 100644 --- a/xcm/src/v1/mod.rs +++ b/xcm/src/v1/mod.rs @@ -16,10 +16,14 @@ //! Version 1 of the Cross-Consensus Message format data structures. +use super::v0::Xcm as Xcm0; use crate::DoubleEncoded; use alloc::vec::Vec; -use core::{fmt::Debug, convert::{TryFrom, TryInto}, result}; -use super::v0::Xcm as Xcm0; +use core::{ + convert::{TryFrom, TryInto}, + fmt::Debug, + result, +}; use derivative::Derivative; use parity_scale_codec::{self, Decode, Encode}; @@ -38,7 +42,6 @@ pub use multilocation::MultiLocation; pub use order::Order; pub use traits::{Error, ExecuteXcm, Outcome, Result, SendXcm, WrapVersion}; - /// A prelude for importing all types typically used when interacting with XCM messages. pub mod prelude { pub use super::{ @@ -60,7 +63,7 @@ pub mod prelude { multilocation::MultiLocation::{self, *}, opaque, order::Order::{self, *}, - traits::{Error as XcmError, ExecuteXcm, Outcome, Result as XcmResult, SendXcm, ForceV0}, + traits::{Error as XcmError, ExecuteXcm, ForceV0, Outcome, Result as XcmResult, SendXcm}, OriginKind, Response, Xcm::{self, *}, }; @@ -340,29 +343,39 @@ impl<Call> TryFrom<Xcm0<Call>> for Xcm<Call> { fn try_from(old: Xcm0<Call>) -> result::Result<Xcm<Call>, ()> { use Xcm::*; Ok(match old { - Xcm0::WithdrawAsset { assets, effects } => - WithdrawAsset { - assets: assets.try_into()?, - effects: effects.into_iter() - .map(Order::try_from) - .collect::<result::Result<_, _>>()?, - }, + Xcm0::WithdrawAsset { assets, effects } => WithdrawAsset { + assets: assets.try_into()?, + effects: effects + .into_iter() + .map(Order::try_from) + .collect::<result::Result<_, _>>()?, + }, Xcm0::ReserveAssetDeposit { assets, effects } => ReserveAssetDeposited { assets: assets.try_into()?, - effects: effects.into_iter().map(Order::try_from).collect::<result::Result<_, _>>()?, + effects: effects + .into_iter() + .map(Order::try_from) + .collect::<result::Result<_, _>>()?, }, Xcm0::TeleportAsset { assets, effects } => ReceiveTeleportedAsset { assets: assets.try_into()?, - effects: effects.into_iter().map(Order::try_from).collect::<result::Result<_, _>>()?, + effects: effects + .into_iter() + .map(Order::try_from) + .collect::<result::Result<_, _>>()?, + }, + Xcm0::QueryResponse { query_id: u64, response } => + QueryResponse { query_id: u64, response }, + Xcm0::TransferAsset { assets, dest } => + TransferAsset { assets: assets.try_into()?, beneficiary: dest.into() }, + Xcm0::TransferReserveAsset { assets, dest, effects } => TransferReserveAsset { + assets: assets.try_into()?, + dest: dest.into(), + effects: effects + .into_iter() + .map(Order::try_from) + .collect::<result::Result<_, _>>()?, }, - Xcm0::QueryResponse { query_id: u64, response } => QueryResponse { query_id: u64, response }, - Xcm0::TransferAsset { assets, dest } => TransferAsset { assets: assets.try_into()?, beneficiary: dest.into() }, - Xcm0::TransferReserveAsset { assets, dest, effects } => - TransferReserveAsset { - assets: assets.try_into()?, - dest: dest.into(), - effects: effects.into_iter().map(Order::try_from).collect::<result::Result<_, _>>()?, - }, Xcm0::HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity } => HrmpNewChannelOpenRequest { sender, max_message_size, max_capacity }, Xcm0::HrmpChannelAccepted { recipient } => HrmpChannelAccepted { recipient }, @@ -370,8 +383,10 @@ impl<Call> TryFrom<Xcm0<Call>> for Xcm<Call> { HrmpChannelClosing { initiator, sender, recipient }, 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(), message: alloc::boxed::Box::new((*message).try_into()?) }, + Xcm0::RelayedFrom { who, message } => RelayedFrom { + who: who.into(), + message: alloc::boxed::Box::new((*message).try_into()?), + }, }) } } diff --git a/xcm/src/v1/multiasset.rs b/xcm/src/v1/multiasset.rs index 1b9f693ce054..5f14d8f2f01a 100644 --- a/xcm/src/v1/multiasset.rs +++ b/xcm/src/v1/multiasset.rs @@ -28,7 +28,11 @@ use super::{ MultiLocation::{self, X1}, }; use alloc::{vec, vec::Vec}; -use core::{cmp::Ordering, convert::{TryFrom, TryInto}, result}; +use core::{ + cmp::Ordering, + convert::{TryFrom, TryInto}, + result, +}; use parity_scale_codec::{self as codec, Decode, Encode}; /// A general identifier for an instance of a non-fungible asset class. @@ -235,11 +239,12 @@ impl TryFrom<super::super::v0::MultiAsset> for MultiAsset { type Error = (); fn try_from(old: super::super::v0::MultiAsset) -> result::Result<MultiAsset, ()> { use super::super::v0::MultiAsset as V0; - use Fungibility::*; use AssetId::*; + use Fungibility::*; let (id, fun) = match old { V0::ConcreteFungible { id, amount } => (Concrete(id.into()), Fungible(amount)), - V0::ConcreteNonFungible { class, instance } => (Concrete(class.into()), NonFungible(instance)), + V0::ConcreteNonFungible { class, instance } => + (Concrete(class.into()), NonFungible(instance)), V0::AbstractFungible { id, amount } => (Abstract(id), Fungible(amount)), V0::AbstractNonFungible { class, instance } => (Abstract(class), NonFungible(instance)), _ => return Err(()), @@ -283,7 +288,8 @@ impl Decode for MultiAssets { impl TryFrom<Vec<super::super::v0::MultiAsset>> for MultiAssets { type Error = (); fn try_from(old: Vec<super::super::v0::MultiAsset>) -> result::Result<MultiAssets, ()> { - let v = old.into_iter() + let v = old + .into_iter() .map(Option::<MultiAsset>::try_from) .filter_map(|x| x.transpose()) .collect::<result::Result<Vec<MultiAsset>, ()>>()?; @@ -446,8 +452,8 @@ impl TryFrom<super::super::v0::MultiAsset> for WildMultiAsset { type Error = (); fn try_from(old: super::super::v0::MultiAsset) -> result::Result<WildMultiAsset, ()> { use super::super::v0::MultiAsset as V0; - use WildFungibility::*; use AssetId::*; + use WildFungibility::*; let (id, fun) = match old { V0::All => return Ok(WildMultiAsset::All), V0::AllConcreteFungible { id } => (Concrete(id.into()), Fungible), @@ -557,7 +563,9 @@ impl MultiAssetFilter { impl TryFrom<Vec<super::super::v0::MultiAsset>> for MultiAssetFilter { type Error = (); - fn try_from(mut old: Vec<super::super::v0::MultiAsset>) -> result::Result<MultiAssetFilter, ()> { + fn try_from( + mut old: Vec<super::super::v0::MultiAsset>, + ) -> result::Result<MultiAssetFilter, ()> { if old.len() == 1 && old[0].is_wildcard() { Ok(MultiAssetFilter::Wild(old.remove(0).try_into()?)) } else { diff --git a/xcm/src/v1/multilocation.rs b/xcm/src/v1/multilocation.rs index 4a9866c90eb1..bd1548fd6f59 100644 --- a/xcm/src/v1/multilocation.rs +++ b/xcm/src/v1/multilocation.rs @@ -16,8 +16,8 @@ //! Cross-Consensus Message format data structures. +use super::{super::v0::MultiLocation as MultiLocation0, Junction}; use core::{mem, result}; -use super::{Junction, super::v0::MultiLocation as MultiLocation0}; use parity_scale_codec::{self, Decode, Encode}; /// A relative path between state-bearing consensus systems. @@ -707,7 +707,8 @@ impl From<MultiLocation0> for MultiLocation { 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::X8(j0, j1, j2, j3, j4, j5, j6, j7) => + X8(j0, j1, j2, j3, j4, j5, j6, j7), } } } diff --git a/xcm/src/v1/order.rs b/xcm/src/v1/order.rs index 7010b1f580e3..06363c39ce83 100644 --- a/xcm/src/v1/order.rs +++ b/xcm/src/v1/order.rs @@ -16,12 +16,16 @@ //! Version 1 of the Cross-Consensus Message format data structures. -use core::{convert::{TryFrom, TryInto}, result}; +use super::{ + super::v0::Order as Order0, MultiAsset, MultiAssetFilter, MultiAssets, MultiLocation, Xcm, +}; use alloc::{vec, vec::Vec}; -use super::{MultiAsset, MultiAssets, MultiAssetFilter, MultiLocation, Xcm}; +use core::{ + convert::{TryFrom, TryInto}, + result, +}; use derivative::Derivative; use parity_scale_codec::{self, Decode, Encode}; -use super::super::v0::Order as Order0; /// An instruction to be executed on some or all of the assets in holding, used by asset-related XCM messages. #[derive(Derivative, Encode, Decode)] @@ -192,17 +196,47 @@ impl<Call> TryFrom<Order0<Call>> for Order<Call> { Order0::Null => Noop, Order0::DepositAsset { assets, dest } => DepositAsset { assets: assets.try_into()?, max_assets: 1, beneficiary: dest.into() }, - Order0::DepositReserveAsset { assets, dest, effects } => - DepositReserveAsset { assets: assets.try_into()?, max_assets: 1, dest: dest.into(), effects: effects.into_iter().map(Order::<()>::try_from).collect::<result::Result<_, _>>()? }, - Order0::ExchangeAsset { give, receive } => ExchangeAsset { give: give.try_into()?, receive: receive.try_into()? }, + Order0::DepositReserveAsset { assets, dest, effects } => DepositReserveAsset { + assets: assets.try_into()?, + max_assets: 1, + dest: dest.into(), + effects: effects + .into_iter() + .map(Order::<()>::try_from) + .collect::<result::Result<_, _>>()?, + }, + Order0::ExchangeAsset { give, receive } => + ExchangeAsset { give: give.try_into()?, receive: receive.try_into()? }, Order0::InitiateReserveWithdraw { assets, reserve, effects } => - InitiateReserveWithdraw { assets: assets.try_into()?, reserve: reserve.into(), effects: effects.into_iter().map(Order::<()>::try_from).collect::<result::Result<_, _>>()? }, - Order0::InitiateTeleport { assets, dest, effects } => - InitiateTeleport { assets: assets.try_into()?, dest: dest.into(), effects: effects.into_iter().map(Order::<()>::try_from).collect::<result::Result<_, _>>()? }, - Order0::QueryHolding { query_id, dest, assets } => QueryHolding { query_id, dest: dest.into(), assets: assets.try_into()? }, + InitiateReserveWithdraw { + assets: assets.try_into()?, + reserve: reserve.into(), + effects: effects + .into_iter() + .map(Order::<()>::try_from) + .collect::<result::Result<_, _>>()?, + }, + Order0::InitiateTeleport { assets, dest, effects } => InitiateTeleport { + assets: assets.try_into()?, + dest: dest.into(), + effects: effects + .into_iter() + .map(Order::<()>::try_from) + .collect::<result::Result<_, _>>()?, + }, + Order0::QueryHolding { query_id, dest, assets } => + QueryHolding { query_id, dest: dest.into(), assets: assets.try_into()? }, Order0::BuyExecution { fees, weight, debt, halt_on_error, xcm } => { - let instructions = xcm.into_iter().map(Xcm::<Call>::try_from).collect::<result::Result<_, _>>()?; - BuyExecution { fees: fees.try_into()?, weight, debt, halt_on_error, orders: vec![], instructions } + let instructions = + xcm.into_iter().map(Xcm::<Call>::try_from).collect::<result::Result<_, _>>()?; + BuyExecution { + fees: fees.try_into()?, + weight, + debt, + halt_on_error, + orders: vec![], + instructions, + } }, }) } diff --git a/xcm/src/v1/traits.rs b/xcm/src/v1/traits.rs index e05759b59e16..54a40796de66 100644 --- a/xcm/src/v1/traits.rs +++ b/xcm/src/v1/traits.rs @@ -16,10 +16,10 @@ //! Cross-Consensus Message format data structures. -use core::{result, convert::TryInto}; +use core::{convert::TryInto, result}; use parity_scale_codec::{Decode, Encode}; -use super::{MultiLocation, Xcm, super::VersionedXcm}; +use super::{super::VersionedXcm, MultiLocation, Xcm}; #[derive(Clone, Encode, Decode, Eq, PartialEq, Debug)] pub enum Error { @@ -264,11 +264,17 @@ impl SendXcm for Tuple { /// Convert an `Xcm` datum into a `VersionedXcm`, based on a destination `MultiLocation` which will interpret it. pub trait WrapVersion { - fn wrap_version<Call>(dest: &MultiLocation, xcm: Xcm<Call>) -> result::Result<VersionedXcm<Call>, ()>; + fn wrap_version<Call>( + dest: &MultiLocation, + xcm: Xcm<Call>, + ) -> result::Result<VersionedXcm<Call>, ()>; } impl WrapVersion for () { - fn wrap_version<Call>(_: &MultiLocation, xcm: Xcm<Call>) -> result::Result<VersionedXcm<Call>, ()> { + fn wrap_version<Call>( + _: &MultiLocation, + xcm: Xcm<Call>, + ) -> result::Result<VersionedXcm<Call>, ()> { Ok(VersionedXcm::<Call>::from(xcm)) } } @@ -276,7 +282,10 @@ impl WrapVersion for () { /// `WrapVersion` implementation which attempts to always convert the XCM to version 0 before wrapping it. pub struct ForceV0; impl WrapVersion for ForceV0 { - fn wrap_version<Call>(_: &MultiLocation, xcm: Xcm<Call>) -> result::Result<VersionedXcm<Call>, ()> { + fn wrap_version<Call>( + _: &MultiLocation, + xcm: Xcm<Call>, + ) -> result::Result<VersionedXcm<Call>, ()> { Ok(VersionedXcm::<Call>::V0(xcm.try_into()?)) } } From e33710b6f515e6067d300046ee586da558ef18fe Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi <shawntabrizi@gmail.com> Date: Thu, 5 Aug 2021 19:06:14 +0200 Subject: [PATCH 096/166] Update xcm/pallet-xcm/src/lib.rs --- xcm/pallet-xcm/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/xcm/pallet-xcm/src/lib.rs b/xcm/pallet-xcm/src/lib.rs index 4e22576ca50f..e95cb31188eb 100644 --- a/xcm/pallet-xcm/src/lib.rs +++ b/xcm/pallet-xcm/src/lib.rs @@ -235,7 +235,6 @@ pub mod pallet { .reanchored(&inv_dest) .map_err(|_| Error::<T>::CannotReanchor)?; let max_assets = assets.len() as u32; - assets.sort(); let assets = assets.into(); let mut message = Xcm::TransferReserveAsset { assets, From fe598863d5eb79d9692c134d13e873fff731f9eb Mon Sep 17 00:00:00 2001 From: Gavin Wood <gavin@parity.io> Date: Thu, 5 Aug 2021 23:55:08 +0200 Subject: [PATCH 097/166] Update xcm/src/v0/order.rs Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com> --- xcm/src/v0/order.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xcm/src/v0/order.rs b/xcm/src/v0/order.rs index 3ce20d22bdd8..4674046e2628 100644 --- a/xcm/src/v0/order.rs +++ b/xcm/src/v0/order.rs @@ -191,7 +191,7 @@ impl<Call> TryFrom<Order1<Call>> for Order<Call> { }, Order1::QueryHolding { query_id, dest, assets } => QueryHolding { query_id, dest: dest.into(), assets: assets.into() }, - Order1::BuyExecution { fees, weight, debt, halt_on_error, instructions, orders } => { + Order1::BuyExecution { fees, weight, debt, halt_on_error, orders, instructions } => { if !orders.is_empty() { return Err(()) } From d2bd1e004e89065ee71681c633499e831f23f7c5 Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Fri, 6 Aug 2021 13:59:21 +0200 Subject: [PATCH 098/166] Tweaks to versioning system --- runtime/kusama/src/lib.rs | 4 +- runtime/parachains/src/dmp.rs | 2 +- runtime/parachains/src/ump.rs | 6 +- runtime/rococo/src/lib.rs | 4 +- runtime/westend/src/lib.rs | 4 +- xcm/pallet-xcm/src/lib.rs | 4 +- xcm/pallet-xcm/src/mock.rs | 8 +-- xcm/src/lib.rs | 63 ++++++++++++++++++- xcm/src/v0/mod.rs | 18 +----- xcm/src/v1/mod.rs | 4 +- xcm/src/v1/multilocation.rs | 8 +-- xcm/src/v1/traits.rs | 32 +--------- xcm/xcm-builder/src/barriers.rs | 2 +- xcm/xcm-builder/src/currency_adapter.rs | 4 +- xcm/xcm-builder/src/filter_asset_location.rs | 2 +- xcm/xcm-builder/src/fungibles_adapter.rs | 2 +- xcm/xcm-builder/src/location_conversion.rs | 6 +- xcm/xcm-builder/src/matches_fungible.rs | 6 +- xcm/xcm-builder/src/mock.rs | 6 +- xcm/xcm-builder/src/origin_conversion.rs | 2 +- xcm/xcm-builder/src/tests.rs | 2 +- xcm/xcm-builder/src/weight.rs | 2 +- xcm/xcm-executor/src/assets.rs | 6 +- xcm/xcm-executor/src/config.rs | 2 +- xcm/xcm-executor/src/lib.rs | 2 +- xcm/xcm-executor/src/traits/conversion.rs | 4 +- .../src/traits/filter_asset_location.rs | 2 +- .../src/traits/matches_fungible.rs | 2 +- .../src/traits/matches_fungibles.rs | 2 +- xcm/xcm-executor/src/traits/on_response.rs | 2 +- xcm/xcm-executor/src/traits/should_execute.rs | 2 +- xcm/xcm-executor/src/traits/transact_asset.rs | 2 +- xcm/xcm-executor/src/traits/weight.rs | 2 +- xcm/xcm-simulator/example/src/lib.rs | 2 +- xcm/xcm-simulator/example/src/parachain.rs | 2 +- xcm/xcm-simulator/example/src/relay_chain.rs | 2 +- xcm/xcm-simulator/src/lib.rs | 2 +- 37 files changed, 122 insertions(+), 105 deletions(-) diff --git a/runtime/kusama/src/lib.rs b/runtime/kusama/src/lib.rs index dc00d4d7a7ea..2a83120b41ed 100644 --- a/runtime/kusama/src/lib.rs +++ b/runtime/kusama/src/lib.rs @@ -75,7 +75,7 @@ use sp_staking::SessionIndex; use sp_version::NativeVersion; use sp_version::RuntimeVersion; use static_assertions::const_assert; -use xcm::v1::prelude::*; +use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, BackingToPlurality, ChildParachainAsNative, ChildParachainConvertsVia, @@ -1258,7 +1258,7 @@ parameter_types! { /// individual routers. pub type XcmRouter = ( // Only one router so far - use DMP to communicate with child parachains. - xcm_sender::ChildParachainRouter<Runtime, ForceV0>, + xcm_sender::ChildParachainRouter<Runtime, xcm::AlwaysRelease>, ); parameter_types! { diff --git a/runtime/parachains/src/dmp.rs b/runtime/parachains/src/dmp.rs index 1ff8fed4528d..6ca7f09fc773 100644 --- a/runtime/parachains/src/dmp.rs +++ b/runtime/parachains/src/dmp.rs @@ -22,7 +22,7 @@ use frame_support::pallet_prelude::*; use primitives::v1::{DownwardMessage, Hash, Id as ParaId, InboundDownwardMessage}; use sp_runtime::traits::{BlakeTwo256, Hash as HashT, SaturatedConversion}; use sp_std::{fmt, prelude::*}; -use xcm::v1::Error as XcmError; +use xcm::latest::Error as XcmError; pub use pallet::*; diff --git a/runtime/parachains/src/ump.rs b/runtime/parachains/src/ump.rs index b1a39405a468..31a72875407a 100644 --- a/runtime/parachains/src/ump.rs +++ b/runtime/parachains/src/ump.rs @@ -27,7 +27,7 @@ use sp_std::{ marker::PhantomData, prelude::*, }; -use xcm::v1::Outcome; +use xcm::latest::Outcome; pub use pallet::*; @@ -78,14 +78,14 @@ pub type MessageId = [u8; 32]; /// and will be forwarded to the XCM Executor. pub struct XcmSink<XcmExecutor, Config>(PhantomData<(XcmExecutor, Config)>); -impl<XcmExecutor: xcm::v1::ExecuteXcm<C::Call>, C: Config> UmpSink for XcmSink<XcmExecutor, C> { +impl<XcmExecutor: xcm::latest::ExecuteXcm<C::Call>, C: Config> UmpSink for XcmSink<XcmExecutor, C> { fn process_upward_message( origin: ParaId, data: &[u8], max_weight: Weight, ) -> Result<Weight, (MessageId, Weight)> { use xcm::{ - v1::{Error as XcmError, Junction, MultiLocation, Xcm}, + latest::{Error as XcmError, Junction, MultiLocation, Xcm}, VersionedXcm, }; diff --git a/runtime/rococo/src/lib.rs b/runtime/rococo/src/lib.rs index a195289f15ba..e4b5f737cd22 100644 --- a/runtime/rococo/src/lib.rs +++ b/runtime/rococo/src/lib.rs @@ -80,7 +80,7 @@ use polkadot_parachain::primitives::Id as ParaId; use constants::{currency::*, fee::*, time::*}; use frame_support::traits::InstanceFilter; -use xcm::v1::prelude::*; +use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, BackingToPlurality, ChildParachainAsNative, ChildParachainConvertsVia, ChildSystemParachainAsSuperuser, CurrencyAdapter as XcmCurrencyAdapter, FixedWeightBounds, @@ -620,7 +620,7 @@ parameter_types! { /// individual routers. pub type XcmRouter = ( // Only one router so far - use DMP to communicate with child parachains. - xcm_sender::ChildParachainRouter<Runtime, ForceV0>, + xcm_sender::ChildParachainRouter<Runtime, xcm::AlwaysRelease>, ); parameter_types! { diff --git a/runtime/westend/src/lib.rs b/runtime/westend/src/lib.rs index d7b00dd550db..4d4efab21f2c 100644 --- a/runtime/westend/src/lib.rs +++ b/runtime/westend/src/lib.rs @@ -44,7 +44,7 @@ use runtime_parachains::{ session_info as parachains_session_info, shared as parachains_shared, ump as parachains_ump, }; -use xcm::v1::prelude::*; +use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, ChildParachainAsNative, ChildParachainConvertsVia, ChildSystemParachainAsSuperuser, @@ -903,7 +903,7 @@ parameter_types! { /// individual routers. pub type XcmRouter = ( // Only one router so far - use DMP to communicate with child parachains. - xcm_sender::ChildParachainRouter<Runtime, ForceV0>, + xcm_sender::ChildParachainRouter<Runtime, xcm::AlwaysRelease>, ); parameter_types! { diff --git a/xcm/pallet-xcm/src/lib.rs b/xcm/pallet-xcm/src/lib.rs index 4e22576ca50f..4c0854625d81 100644 --- a/xcm/pallet-xcm/src/lib.rs +++ b/xcm/pallet-xcm/src/lib.rs @@ -27,7 +27,7 @@ use codec::{Decode, Encode}; use frame_support::traits::{Contains, EnsureOrigin, Filter, Get, OriginTrait}; use sp_runtime::{traits::BadOrigin, RuntimeDebug}; use sp_std::{boxed::Box, convert::TryInto, marker::PhantomData, prelude::*, vec}; -use xcm::v1::prelude::*; +use xcm::latest::prelude::*; use xcm_executor::traits::ConvertOrigin; use frame_support::PalletId; @@ -85,7 +85,7 @@ pub mod pallet { #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event<T: Config> { - Attempted(xcm::v1::Outcome), + Attempted(xcm::latest::Outcome), Sent(MultiLocation, MultiLocation, Xcm<()>), } diff --git a/xcm/pallet-xcm/src/mock.rs b/xcm/pallet-xcm/src/mock.rs index ca143ce11db0..f7468cb3455d 100644 --- a/xcm/pallet-xcm/src/mock.rs +++ b/xcm/pallet-xcm/src/mock.rs @@ -25,8 +25,8 @@ use sp_core::H256; use sp_runtime::{testing::Header, traits::IdentityLookup, AccountId32}; pub use sp_std::{cell::RefCell, fmt::Debug, marker::PhantomData}; use xcm::{ - opaque::v1::{Error as XcmError, MultiAsset, Result as XcmResult, SendXcm, Xcm}, - v1::prelude::*, + opaque::latest::{Error as XcmError, MultiAsset, Result as XcmResult, SendXcm, Xcm}, + latest::prelude::*, }; use xcm_builder::{ AccountId32Aliases, AllowTopLevelPaidExecutionFrom, ChildParachainAsNative, @@ -181,7 +181,7 @@ impl pallet_xcm::Config for Test { type SendXcmOrigin = xcm_builder::EnsureXcmOrigin<Origin, LocalOriginToLocation>; type XcmRouter = (TestSendXcmErrX8, TestSendXcm); type ExecuteXcmOrigin = xcm_builder::EnsureXcmOrigin<Origin, LocalOriginToLocation>; - type XcmExecuteFilter = All<(MultiLocation, xcm::v1::Xcm<Call>)>; + type XcmExecuteFilter = All<(MultiLocation, xcm::latest::Xcm<Call>)>; type XcmExecutor = XcmExecutor<XcmConfig>; type XcmTeleportFilter = All<(MultiLocation, Vec<MultiAsset>)>; type XcmReserveTransferFilter = All<(MultiLocation, Vec<MultiAsset>)>; @@ -196,7 +196,7 @@ pub(crate) fn last_event() -> Event { } pub(crate) fn buy_execution<C>(fees: impl Into<MultiAsset>, debt: Weight) -> Order<C> { - use xcm::opaque::v1::prelude::*; + use xcm::opaque::latest::prelude::*; Order::BuyExecution { fees: fees.into(), weight: 0, diff --git a/xcm/src/lib.rs b/xcm/src/lib.rs index 4bce0086eca8..05443fc76b1c 100644 --- a/xcm/src/lib.rs +++ b/xcm/src/lib.rs @@ -59,23 +59,84 @@ pub enum VersionedXcm<Call> { V1(v1::Xcm<Call>), } +impl<Call> From<v0::Xcm<Call>> for VersionedXcm<Call> { + fn from(x: v0::Xcm<Call>) -> Self { + VersionedXcm::V0(x) + } +} + impl<Call> From<v1::Xcm<Call>> for VersionedXcm<Call> { fn from(x: v1::Xcm<Call>) -> Self { VersionedXcm::V1(x) } } +impl<Call> TryFrom<VersionedXcm<Call>> for v0::Xcm<Call> { + type Error = (); + fn try_from(x: VersionedXcm<Call>) -> Result<Self, ()> { + match x { + VersionedXcm::V0(x) => Ok(x), + VersionedXcm::V1(x) => x.try_into(), + } + } +} + impl<Call> TryFrom<VersionedXcm<Call>> for v1::Xcm<Call> { type Error = (); fn try_from(x: VersionedXcm<Call>) -> Result<Self, ()> { match x { - // v1-based chains can interpret v0 messages. VersionedXcm::V0(x) => x.try_into(), VersionedXcm::V1(x) => Ok(x), } } } +/// Convert an `Xcm` datum into a `VersionedXcm`, based on a destination `MultiLocation` which will interpret it. +pub trait WrapVersion { + fn wrap_version<Call>( + dest: &latest::MultiLocation, + xcm: impl Into<VersionedXcm<Call>>, + ) -> Result<VersionedXcm<Call>, ()>; +} + +/// `()` implementation does nothing with the XCM, just sending with whatever version it was authored as. +impl WrapVersion for () { + fn wrap_version<Call>( + _: &latest::MultiLocation, + xcm: impl Into<VersionedXcm<Call>>, + ) -> Result<VersionedXcm<Call>, ()> { + Ok(xcm.into()) + } +} + +/// `WrapVersion` implementation which attempts to always convert the XCM to version 0 before wrapping it. +pub struct AlwaysV0; +impl WrapVersion for AlwaysV0 { + fn wrap_version<Call>( + _: &latest::MultiLocation, + xcm: impl Into<VersionedXcm<Call>>, + ) -> Result<VersionedXcm<Call>, ()> { + Ok(VersionedXcm::<Call>::V0(xcm.into().try_into()?)) + } +} + +/// `WrapVersion` implementation which attempts to always convert the XCM to version 1 before wrapping it. +pub struct AlwaysV1; +impl WrapVersion for AlwaysV1 { + fn wrap_version<Call>( + _: &latest::MultiLocation, + xcm: impl Into<VersionedXcm<Call>>, + ) -> Result<VersionedXcm<Call>, ()> { + Ok(VersionedXcm::<Call>::V1(xcm.into().try_into()?)) + } +} + +/// `WrapVersion` implementation which attempts to always convert the XCM to the latest version before wrapping it. +pub type AlwaysLatest = AlwaysV1; + +/// `WrapVersion` implementation which attempts to always convert the XCM to the release version before wrapping it. +pub type AlwaysRelease = AlwaysV0; + pub mod opaque { pub mod v0 { // Everything from v0 diff --git a/xcm/src/v0/mod.rs b/xcm/src/v0/mod.rs index 54b1a0e25267..ad2f70e31cf5 100644 --- a/xcm/src/v0/mod.rs +++ b/xcm/src/v0/mod.rs @@ -16,7 +16,7 @@ //! Version 0 of the Cross-Consensus Message format data structures. -use crate::{DoubleEncoded, VersionedXcm}; +use crate::DoubleEncoded; use alloc::vec::Vec; use core::{ convert::{TryFrom, TryInto}, @@ -247,22 +247,6 @@ pub enum Xcm<Call> { RelayedFrom { who: MultiLocation, message: alloc::boxed::Box<Xcm<Call>> }, } -impl<Call> From<Xcm<Call>> for VersionedXcm<Call> { - fn from(x: Xcm<Call>) -> Self { - VersionedXcm::V0(x) - } -} - -impl<Call> TryFrom<VersionedXcm<Call>> for Xcm<Call> { - type Error = (); - fn try_from(x: VersionedXcm<Call>) -> result::Result<Self, ()> { - match x { - VersionedXcm::V0(x) => Ok(x), - VersionedXcm::V1(_) => Err(()), // v0-based chains cannot interpret v1 messages. - } - } -} - impl<Call> Xcm<Call> { pub fn into<C>(self) -> Xcm<C> { Xcm::from(self) diff --git a/xcm/src/v1/mod.rs b/xcm/src/v1/mod.rs index 99ba9be3b0bb..6b7b4d4f2aea 100644 --- a/xcm/src/v1/mod.rs +++ b/xcm/src/v1/mod.rs @@ -40,7 +40,7 @@ pub use multiasset::{ }; pub use multilocation::MultiLocation; pub use order::Order; -pub use traits::{Error, ExecuteXcm, Outcome, Result, SendXcm, WrapVersion}; +pub use traits::{Error, ExecuteXcm, Outcome, Result, SendXcm}; /// A prelude for importing all types typically used when interacting with XCM messages. pub mod prelude { @@ -63,7 +63,7 @@ pub mod prelude { multilocation::MultiLocation::{self, *}, opaque, order::Order::{self, *}, - traits::{Error as XcmError, ExecuteXcm, ForceV0, Outcome, Result as XcmResult, SendXcm}, + traits::{Error as XcmError, ExecuteXcm, Outcome, Result as XcmResult, SendXcm}, OriginKind, Response, Xcm::{self, *}, }; diff --git a/xcm/src/v1/multilocation.rs b/xcm/src/v1/multilocation.rs index bd1548fd6f59..57cdda4209d4 100644 --- a/xcm/src/v1/multilocation.rs +++ b/xcm/src/v1/multilocation.rs @@ -458,7 +458,7 @@ impl MultiLocation { /// /// # Example /// ```rust - /// # use xcm::v1::{MultiLocation::*, Junction::*}; + /// # use xcm::latest::{MultiLocation::*, Junction::*}; /// # fn main() { /// let mut m = X3(Parent, PalletInstance(3), OnlyChild); /// assert_eq!(m.match_and_split(&X2(Parent, PalletInstance(3))), Some(&OnlyChild)); @@ -598,7 +598,7 @@ impl MultiLocation { /// /// # Example /// ```rust - /// # use xcm::v1::{MultiLocation::*, Junction::*}; + /// # 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(())); @@ -625,7 +625,7 @@ impl MultiLocation { /// /// # Example /// ```rust - /// # use xcm::v1::{MultiLocation::*, Junction::*, NetworkId::Any}; + /// # 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(())); @@ -682,7 +682,7 @@ impl MultiLocation { /// /// # Example /// ```rust - /// # use xcm::v1::{MultiLocation::*, Junction::*, NetworkId::Any}; + /// # use xcm::latest::{MultiLocation::*, Junction::*, NetworkId::Any}; /// # fn main() { /// let parent = X1(Parent); /// assert_eq!(parent.is_interior(), false); diff --git a/xcm/src/v1/traits.rs b/xcm/src/v1/traits.rs index 54a40796de66..94fd4449f21d 100644 --- a/xcm/src/v1/traits.rs +++ b/xcm/src/v1/traits.rs @@ -16,10 +16,10 @@ //! Cross-Consensus Message format data structures. -use core::{convert::TryInto, result}; +use core::result; use parity_scale_codec::{Decode, Encode}; -use super::{super::VersionedXcm, MultiLocation, Xcm}; +use super::{MultiLocation, Xcm}; #[derive(Clone, Encode, Decode, Eq, PartialEq, Debug)] pub enum Error { @@ -261,31 +261,3 @@ impl SendXcm for Tuple { Err(Error::CannotReachDestination(destination, message)) } } - -/// Convert an `Xcm` datum into a `VersionedXcm`, based on a destination `MultiLocation` which will interpret it. -pub trait WrapVersion { - fn wrap_version<Call>( - dest: &MultiLocation, - xcm: Xcm<Call>, - ) -> result::Result<VersionedXcm<Call>, ()>; -} - -impl WrapVersion for () { - fn wrap_version<Call>( - _: &MultiLocation, - xcm: Xcm<Call>, - ) -> result::Result<VersionedXcm<Call>, ()> { - Ok(VersionedXcm::<Call>::from(xcm)) - } -} - -/// `WrapVersion` implementation which attempts to always convert the XCM to version 0 before wrapping it. -pub struct ForceV0; -impl WrapVersion for ForceV0 { - fn wrap_version<Call>( - _: &MultiLocation, - xcm: Xcm<Call>, - ) -> result::Result<VersionedXcm<Call>, ()> { - Ok(VersionedXcm::<Call>::V0(xcm.try_into()?)) - } -} diff --git a/xcm/xcm-builder/src/barriers.rs b/xcm/xcm-builder/src/barriers.rs index ec1b5d0c7f63..3e412af629da 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::v1::{Junction, MultiLocation, Order, Xcm}; +use xcm::latest::{Junction, MultiLocation, Order, Xcm}; use xcm_executor::traits::{OnResponse, ShouldExecute}; /// Execution barrier that just takes `shallow_weight` from `weight_credit`. diff --git a/xcm/xcm-builder/src/currency_adapter.rs b/xcm/xcm-builder/src/currency_adapter.rs index ebbdf794209f..9742d035c78a 100644 --- a/xcm/xcm-builder/src/currency_adapter.rs +++ b/xcm/xcm-builder/src/currency_adapter.rs @@ -19,7 +19,7 @@ use frame_support::traits::{ExistenceRequirement::AllowDeath, Get, WithdrawReasons}; use sp_runtime::traits::{CheckedSub, SaturatedConversion}; use sp_std::{convert::TryInto, marker::PhantomData, result}; -use xcm::v1::{Error as XcmError, MultiAsset, MultiLocation, Result}; +use xcm::latest::{Error as XcmError, MultiAsset, MultiLocation, Result}; use xcm_executor::{ traits::{Convert, MatchesFungible, TransactAsset}, Assets, @@ -53,7 +53,7 @@ impl From<Error> for XcmError { /// # Example /// ``` /// use frame_support::parameter_types; -/// use xcm::v1::{MultiLocation, Junction}; +/// use xcm::latest::{MultiLocation, Junction}; /// use xcm_builder::{ParentIsDefault, CurrencyAdapter, IsConcrete}; /// /// /// Our chain's account id. diff --git a/xcm/xcm-builder/src/filter_asset_location.rs b/xcm/xcm-builder/src/filter_asset_location.rs index 99a0e5e8f7f6..9794c2f44f5b 100644 --- a/xcm/xcm-builder/src/filter_asset_location.rs +++ b/xcm/xcm-builder/src/filter_asset_location.rs @@ -18,7 +18,7 @@ use frame_support::traits::Get; use sp_std::marker::PhantomData; -use xcm::v1::{AssetId::Concrete, MultiAsset, MultiAssetFilter, MultiLocation}; +use xcm::latest::{AssetId::Concrete, MultiAsset, MultiAssetFilter, MultiLocation}; use xcm_executor::traits::FilterAssetLocation; /// Accepts an asset iff it is a native asset. diff --git a/xcm/xcm-builder/src/fungibles_adapter.rs b/xcm/xcm-builder/src/fungibles_adapter.rs index 048f3d8d3a52..d9f1e026ee0b 100644 --- a/xcm/xcm-builder/src/fungibles_adapter.rs +++ b/xcm/xcm-builder/src/fungibles_adapter.rs @@ -18,7 +18,7 @@ use frame_support::traits::{tokens::fungibles, Contains, Get}; use sp_std::{borrow::Borrow, marker::PhantomData, prelude::*, result}; -use xcm::v1::{ +use xcm::latest::{ AssetId::{Abstract, Concrete}, Error as XcmError, Fungibility::Fungible, diff --git a/xcm/xcm-builder/src/location_conversion.rs b/xcm/xcm-builder/src/location_conversion.rs index cbaf0b93063e..5daaf11d4b81 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::v1::{Junction, MultiLocation, NetworkId}; +use xcm::latest::{Junction, MultiLocation, NetworkId}; use xcm_executor::traits::{Convert, InvertLocation}; pub struct Account32Hash<Network, AccountId>(PhantomData<(Network, AccountId)>); @@ -155,7 +155,7 @@ impl<Network: Get<NetworkId>, AccountId: From<[u8; 20]> + Into<[u8; 20]> + Clone /// ``` /// ```rust /// # use frame_support::parameter_types; -/// # use xcm::v1::{MultiLocation::{self, *}, Junction::*, NetworkId::Any}; +/// # use xcm::latest::{MultiLocation::{self, *}, Junction::*, NetworkId::Any}; /// # use xcm_builder::LocationInverter; /// # use xcm_executor::traits::InvertLocation; /// # fn main() { @@ -200,7 +200,7 @@ mod tests { use super::*; use frame_support::parameter_types; - use xcm::v1::{Junction::*, MultiLocation::*, NetworkId::Any}; + use xcm::latest::{Junction::*, MultiLocation::*, NetworkId::Any}; fn account20() -> Junction { AccountKey20 { network: Any, key: Default::default() } diff --git a/xcm/xcm-builder/src/matches_fungible.rs b/xcm/xcm-builder/src/matches_fungible.rs index 8e61bd2f8439..f1e619c97068 100644 --- a/xcm/xcm-builder/src/matches_fungible.rs +++ b/xcm/xcm-builder/src/matches_fungible.rs @@ -19,7 +19,7 @@ use frame_support::traits::Get; use sp_runtime::traits::CheckedConversion; use sp_std::{convert::TryFrom, marker::PhantomData}; -use xcm::v1::{ +use xcm::latest::{ AssetId::{Abstract, Concrete}, Fungibility::Fungible, MultiAsset, MultiLocation, @@ -32,7 +32,7 @@ use xcm_executor::traits::MatchesFungible; /// # Example /// /// ``` -/// use xcm::v1::prelude::*; +/// use xcm::latest::prelude::*; /// use xcm_builder::IsConcrete; /// use xcm_executor::traits::MatchesFungible; /// @@ -62,7 +62,7 @@ impl<T: Get<MultiLocation>, B: TryFrom<u128>> MatchesFungible<B> for IsConcrete< /// # Example /// /// ``` -/// use xcm::v1::prelude::*; +/// use xcm::latest::prelude::*; /// use xcm_builder::IsAbstract; /// use xcm_executor::traits::MatchesFungible; /// diff --git a/xcm/xcm-builder/src/mock.rs b/xcm/xcm-builder/src/mock.rs index af568a5fc8de..adedd965a4ba 100644 --- a/xcm/xcm-builder/src/mock.rs +++ b/xcm/xcm-builder/src/mock.rs @@ -34,7 +34,7 @@ pub use sp_std::{ fmt::Debug, marker::PhantomData, }; -pub use xcm::v1::prelude::*; +pub use xcm::latest::prelude::*; pub use xcm_executor::{ traits::{ConvertOrigin, FilterAssetLocation, InvertLocation, OnResponse, TransactAsset}, Assets, Config, @@ -203,7 +203,7 @@ impl FilterAssetLocation for TestIsTeleporter { } } -use xcm::v1::Response; +use xcm::latest::Response; pub enum ResponseSlot { Expecting(MultiLocation), Received(Response), @@ -219,7 +219,7 @@ impl OnResponse for TestResponseHandler { _ => false, }) } - fn on_response(_origin: MultiLocation, query_id: u64, response: xcm::v1::Response) -> Weight { + fn on_response(_origin: MultiLocation, query_id: u64, response: xcm::latest::Response) -> Weight { QUERIES.with(|q| { q.borrow_mut().entry(query_id).and_modify(|v| { if matches!(*v, ResponseSlot::Expecting(..)) { diff --git a/xcm/xcm-builder/src/origin_conversion.rs b/xcm/xcm-builder/src/origin_conversion.rs index 1432738263cd..08a6de91c648 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::v1::{BodyId, BodyPart, Junction, MultiLocation, NetworkId, OriginKind}; +use xcm::latest::{BodyId, BodyPart, Junction, 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`. diff --git a/xcm/xcm-builder/src/tests.rs b/xcm/xcm-builder/src/tests.rs index 8f95687f29cf..31f141ab68be 100644 --- a/xcm/xcm-builder/src/tests.rs +++ b/xcm/xcm-builder/src/tests.rs @@ -15,7 +15,7 @@ // along with Polkadot. If not, see <http://www.gnu.org/licenses/>. use super::{mock::*, *}; -use xcm::v1::prelude::*; +use xcm::latest::prelude::*; use xcm_executor::{traits::*, Config, XcmExecutor}; #[test] diff --git a/xcm/xcm-builder/src/weight.rs b/xcm/xcm-builder/src/weight.rs index 679aa0928216..12ec9ff173d8 100644 --- a/xcm/xcm-builder/src/weight.rs +++ b/xcm/xcm-builder/src/weight.rs @@ -21,7 +21,7 @@ use frame_support::{ use parity_scale_codec::Decode; use sp_runtime::traits::{SaturatedConversion, Saturating, Zero}; use sp_std::{convert::TryInto, marker::PhantomData, result::Result}; -use xcm::v1::{AssetId, AssetId::Concrete, Error, MultiAsset, MultiLocation, Order, Xcm}; +use xcm::latest::{AssetId, AssetId::Concrete, Error, MultiAsset, MultiLocation, Order, Xcm}; use xcm_executor::{ traits::{WeightBounds, WeightTrader}, Assets, diff --git a/xcm/xcm-executor/src/assets.rs b/xcm/xcm-executor/src/assets.rs index f04483f1a6fa..006bea157015 100644 --- a/xcm/xcm-executor/src/assets.rs +++ b/xcm/xcm-executor/src/assets.rs @@ -20,7 +20,7 @@ use sp_std::{ mem, prelude::*, }; -use xcm::v1::{ +use xcm::latest::{ AssetId, AssetInstance, Fungibility::{Fungible, NonFungible}, MultiAsset, MultiAssetFilter, MultiAssets, MultiLocation, @@ -376,7 +376,7 @@ impl Assets { /// /// ``` /// use xcm_executor::Assets; - /// use xcm::v1::prelude::*; + /// use xcm::latest::prelude::*; /// let assets_i_have: Assets = vec![ (Here, 100).into(), (vec![0], 100).into() ].into(); /// let assets_they_want: MultiAssetFilter = vec![ (Here, 200).into(), (vec![0], 50).into() ].into(); /// @@ -425,7 +425,7 @@ impl Assets { #[cfg(test)] mod tests { use super::*; - use xcm::v1::prelude::*; + use xcm::latest::prelude::*; use MultiLocation::Here; #[allow(non_snake_case)] /// Abstract fungible constructor diff --git a/xcm/xcm-executor/src/config.rs b/xcm/xcm-executor/src/config.rs index 1a38fb44ea50..7f4bf08f5fa0 100644 --- a/xcm/xcm-executor/src/config.rs +++ b/xcm/xcm-executor/src/config.rs @@ -22,7 +22,7 @@ use frame_support::{ dispatch::{Dispatchable, Parameter}, weights::{GetDispatchInfo, PostDispatchInfo}, }; -use xcm::v1::SendXcm; +use xcm::latest::SendXcm; /// The trait to parameterize the `XcmExecutor`. pub trait Config { diff --git a/xcm/xcm-executor/src/lib.rs b/xcm/xcm-executor/src/lib.rs index c30c5d3f9a77..102f241fbc4e 100644 --- a/xcm/xcm-executor/src/lib.rs +++ b/xcm/xcm-executor/src/lib.rs @@ -22,7 +22,7 @@ use frame_support::{ weights::GetDispatchInfo, }; use sp_std::{marker::PhantomData, prelude::*}; -use xcm::v1::{ +use xcm::latest::{ Error as XcmError, ExecuteXcm, MultiAssets, MultiLocation, Order, Outcome, Response, SendXcm, Xcm, }; diff --git a/xcm/xcm-executor/src/traits/conversion.rs b/xcm/xcm-executor/src/traits/conversion.rs index df99a05d0064..4342fc5002e5 100644 --- a/xcm/xcm-executor/src/traits/conversion.rs +++ b/xcm/xcm-executor/src/traits/conversion.rs @@ -16,7 +16,7 @@ use parity_scale_codec::{Decode, Encode}; use sp_std::{borrow::Borrow, convert::TryFrom, prelude::*, result::Result}; -use xcm::v1::{MultiLocation, OriginKind}; +use xcm::latest::{MultiLocation, OriginKind}; /// Generic third-party conversion trait. Use this when you don't want to force the user to use default /// implementations of `From` and `Into` for the types you wish to convert between. @@ -139,7 +139,7 @@ impl<T: Clone + Encode + Decode> Convert<Vec<u8>, T> for Decoded { /// which is passed to the next convert item. /// /// ```rust -/// # use xcm::v1::{MultiLocation, Junction, OriginKind}; +/// # use xcm::latest::{MultiLocation, Junction, OriginKind}; /// # use xcm_executor::traits::ConvertOrigin; /// // A convertor that will bump the para id and pass it to the next one. /// struct BumpParaId; diff --git a/xcm/xcm-executor/src/traits/filter_asset_location.rs b/xcm/xcm-executor/src/traits/filter_asset_location.rs index a63af84e167c..31b9c47a828c 100644 --- a/xcm/xcm-executor/src/traits/filter_asset_location.rs +++ b/xcm/xcm-executor/src/traits/filter_asset_location.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see <http://www.gnu.org/licenses/>. -use xcm::v1::{MultiAsset, MultiLocation}; +use xcm::latest::{MultiAsset, MultiLocation}; /// Filters assets/location pairs. /// diff --git a/xcm/xcm-executor/src/traits/matches_fungible.rs b/xcm/xcm-executor/src/traits/matches_fungible.rs index ff466af5b21c..4989f263a63d 100644 --- a/xcm/xcm-executor/src/traits/matches_fungible.rs +++ b/xcm/xcm-executor/src/traits/matches_fungible.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see <http://www.gnu.org/licenses/>. -use xcm::v1::MultiAsset; +use xcm::latest::MultiAsset; pub trait MatchesFungible<Balance> { fn matches_fungible(a: &MultiAsset) -> Option<Balance>; diff --git a/xcm/xcm-executor/src/traits/matches_fungibles.rs b/xcm/xcm-executor/src/traits/matches_fungibles.rs index 2499eae27531..f5baafdcd97a 100644 --- a/xcm/xcm-executor/src/traits/matches_fungibles.rs +++ b/xcm/xcm-executor/src/traits/matches_fungibles.rs @@ -15,7 +15,7 @@ // along with Polkadot. If not, see <http://www.gnu.org/licenses/>. use sp_std::result; -use xcm::v1::{Error as XcmError, MultiAsset}; +use xcm::latest::{Error as XcmError, MultiAsset}; /// Errors associated with [`MatchesFungibles`] operation. pub enum Error { diff --git a/xcm/xcm-executor/src/traits/on_response.rs b/xcm/xcm-executor/src/traits/on_response.rs index 801aa016d478..8af238e7cef2 100644 --- a/xcm/xcm-executor/src/traits/on_response.rs +++ b/xcm/xcm-executor/src/traits/on_response.rs @@ -15,7 +15,7 @@ // along with Polkadot. If not, see <http://www.gnu.org/licenses/>. use frame_support::weights::Weight; -use xcm::v1::{MultiLocation, Response}; +use xcm::latest::{MultiLocation, Response}; /// Define what needs to be done upon receiving a query response. pub trait OnResponse { diff --git a/xcm/xcm-executor/src/traits/should_execute.rs b/xcm/xcm-executor/src/traits/should_execute.rs index a8d9ad1ca79a..a6f7c0207b1a 100644 --- a/xcm/xcm-executor/src/traits/should_execute.rs +++ b/xcm/xcm-executor/src/traits/should_execute.rs @@ -16,7 +16,7 @@ use frame_support::weights::Weight; use sp_std::result::Result; -use xcm::v1::{MultiLocation, Xcm}; +use xcm::latest::{MultiLocation, Xcm}; /// Trait to determine whether the execution engine should actually execute a given XCM. /// diff --git a/xcm/xcm-executor/src/traits/transact_asset.rs b/xcm/xcm-executor/src/traits/transact_asset.rs index a810ce173ca3..e261d9c9c963 100644 --- a/xcm/xcm-executor/src/traits/transact_asset.rs +++ b/xcm/xcm-executor/src/traits/transact_asset.rs @@ -16,7 +16,7 @@ use crate::Assets; use sp_std::result::Result; -use xcm::v1::{Error as XcmError, MultiAsset, MultiLocation, Result as XcmResult}; +use xcm::latest::{Error as XcmError, MultiAsset, MultiLocation, Result as XcmResult}; /// Facility for asset transacting. /// diff --git a/xcm/xcm-executor/src/traits/weight.rs b/xcm/xcm-executor/src/traits/weight.rs index c32ec682857c..8c9e6ec6366d 100644 --- a/xcm/xcm-executor/src/traits/weight.rs +++ b/xcm/xcm-executor/src/traits/weight.rs @@ -17,7 +17,7 @@ use crate::Assets; use frame_support::weights::Weight; use sp_std::result::Result; -use xcm::v1::{Error, MultiAsset, MultiLocation, Xcm}; +use xcm::latest::{Error, MultiAsset, MultiLocation, Xcm}; /// Determine the weight of an XCM message. pub trait WeightBounds<Call> { diff --git a/xcm/xcm-simulator/example/src/lib.rs b/xcm/xcm-simulator/example/src/lib.rs index a02aeaaff456..2426b83819bb 100644 --- a/xcm/xcm-simulator/example/src/lib.rs +++ b/xcm/xcm-simulator/example/src/lib.rs @@ -99,7 +99,7 @@ mod tests { use codec::Encode; use frame_support::assert_ok; - use xcm::v1::prelude::*; + use xcm::latest::prelude::*; use xcm_simulator::TestExt; #[test] diff --git a/xcm/xcm-simulator/example/src/parachain.rs b/xcm/xcm-simulator/example/src/parachain.rs index 3e7212c48fa4..bf2eff15c27c 100644 --- a/xcm/xcm-simulator/example/src/parachain.rs +++ b/xcm/xcm-simulator/example/src/parachain.rs @@ -35,7 +35,7 @@ use polkadot_core_primitives::BlockNumber as RelayBlockNumber; use polkadot_parachain::primitives::{ DmpMessageHandler, Id as ParaId, Sibling, XcmpMessageFormat, XcmpMessageHandler, }; -use xcm::{v1::prelude::*, VersionedXcm}; +use xcm::{latest::prelude::*, VersionedXcm}; use xcm_builder::{ AccountId32Aliases, AllowUnpaidExecutionFrom, CurrencyAdapter as XcmCurrencyAdapter, EnsureXcmOrigin, FixedRateOfFungible, FixedWeightBounds, IsConcrete, LocationInverter, diff --git a/xcm/xcm-simulator/example/src/relay_chain.rs b/xcm/xcm-simulator/example/src/relay_chain.rs index adbf0b965f41..b89bc2abca01 100644 --- a/xcm/xcm-simulator/example/src/relay_chain.rs +++ b/xcm/xcm-simulator/example/src/relay_chain.rs @@ -26,7 +26,7 @@ use sp_runtime::{testing::Header, traits::IdentityLookup, AccountId32}; use polkadot_parachain::primitives::Id as ParaId; use polkadot_runtime_parachains::{configuration, origin, shared, ump}; -use xcm::v1::prelude::*; +use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowUnpaidExecutionFrom, ChildParachainAsNative, ChildParachainConvertsVia, ChildSystemParachainAsSuperuser, diff --git a/xcm/xcm-simulator/src/lib.rs b/xcm/xcm-simulator/src/lib.rs index f075c7e3d9fb..7a3ad25d1555 100644 --- a/xcm/xcm-simulator/src/lib.rs +++ b/xcm/xcm-simulator/src/lib.rs @@ -32,7 +32,7 @@ pub use polkadot_runtime_parachains::{ dmp, ump::{self, MessageId, UmpSink, XcmSink}, }; -pub use xcm::{v1::prelude::*, VersionedXcm}; +pub use xcm::{latest::prelude::*, VersionedXcm}; pub use xcm_executor::XcmExecutor; pub trait TestExt { From d9ff88c24983e694e6c6778474c8e8e6dfe754b9 Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Fri, 6 Aug 2021 14:04:21 +0200 Subject: [PATCH 099/166] Fixes --- runtime/common/src/xcm_sender.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/runtime/common/src/xcm_sender.rs b/runtime/common/src/xcm_sender.rs index 4c2575a3face..c386fc5252d4 100644 --- a/runtime/common/src/xcm_sender.rs +++ b/runtime/common/src/xcm_sender.rs @@ -19,12 +19,12 @@ use parity_scale_codec::Encode; use runtime_parachains::{configuration, dmp}; use sp_std::marker::PhantomData; -use xcm::opaque::v1::{Error, Junction, MultiLocation, Result, SendXcm, WrapVersion, Xcm}; +use xcm::opaque::v1::{Error, Junction, MultiLocation, Result, SendXcm, Xcm}; /// XCM sender for relay chain. It only sends downward message. pub struct ChildParachainRouter<T, W>(PhantomData<(T, W)>); -impl<T: configuration::Config + dmp::Config, W: WrapVersion> SendXcm +impl<T: configuration::Config + dmp::Config, W: xcm::WrapVersion> SendXcm for ChildParachainRouter<T, W> { fn send_xcm(dest: MultiLocation, msg: Xcm) -> Result { From b40668efb3522ca8c670ddac6842a3781bbc8f73 Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Fri, 6 Aug 2021 14:57:10 +0200 Subject: [PATCH 100/166] fmt --- xcm/pallet-xcm/src/mock.rs | 2 +- xcm/xcm-builder/src/mock.rs | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/xcm/pallet-xcm/src/mock.rs b/xcm/pallet-xcm/src/mock.rs index f7468cb3455d..7929534126b2 100644 --- a/xcm/pallet-xcm/src/mock.rs +++ b/xcm/pallet-xcm/src/mock.rs @@ -25,8 +25,8 @@ use sp_core::H256; use sp_runtime::{testing::Header, traits::IdentityLookup, AccountId32}; pub use sp_std::{cell::RefCell, fmt::Debug, marker::PhantomData}; use xcm::{ - opaque::latest::{Error as XcmError, MultiAsset, Result as XcmResult, SendXcm, Xcm}, latest::prelude::*, + opaque::latest::{Error as XcmError, MultiAsset, Result as XcmResult, SendXcm, Xcm}, }; use xcm_builder::{ AccountId32Aliases, AllowTopLevelPaidExecutionFrom, ChildParachainAsNative, diff --git a/xcm/xcm-builder/src/mock.rs b/xcm/xcm-builder/src/mock.rs index adedd965a4ba..21835dd39b1e 100644 --- a/xcm/xcm-builder/src/mock.rs +++ b/xcm/xcm-builder/src/mock.rs @@ -219,7 +219,11 @@ impl OnResponse for TestResponseHandler { _ => false, }) } - fn on_response(_origin: MultiLocation, query_id: u64, response: xcm::latest::Response) -> Weight { + fn on_response( + _origin: MultiLocation, + query_id: u64, + response: xcm::latest::Response, + ) -> Weight { QUERIES.with(|q| { q.borrow_mut().entry(query_id).and_modify(|v| { if matches!(*v, ResponseSlot::Expecting(..)) { From a123f94d64399c63f608d0079906c03c1bca5506 Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Fri, 6 Aug 2021 08:05:14 -0700 Subject: [PATCH 101/166] Fix pallet-xcm tests --- xcm/pallet-xcm/src/mock.rs | 6 +++--- xcm/pallet-xcm/src/tests.rs | 38 ++++++++++++++++--------------------- 2 files changed, 19 insertions(+), 25 deletions(-) diff --git a/xcm/pallet-xcm/src/mock.rs b/xcm/pallet-xcm/src/mock.rs index 7929534126b2..845ced90b58e 100644 --- a/xcm/pallet-xcm/src/mock.rs +++ b/xcm/pallet-xcm/src/mock.rs @@ -75,7 +75,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))); @@ -133,9 +133,9 @@ impl pallet_balances::Config for Test { } parameter_types! { - pub const RelayLocation: MultiLocation = MultiLocation::Here; + pub const RelayLocation: MultiLocation = MultiLocation::here(); pub const AnyNetwork: NetworkId = NetworkId::Any; - pub Ancestry: MultiLocation = MultiLocation::Here; + pub Ancestry: MultiLocation = MultiLocation::here(); pub UnitWeightCost: Weight = 1_000; } diff --git a/xcm/pallet-xcm/src/tests.rs b/xcm/pallet-xcm/src/tests.rs index f10e0490484d..764eeaff98c4 100644 --- a/xcm/pallet-xcm/src/tests.rs +++ b/xcm/pallet-xcm/src/tests.rs @@ -40,9 +40,9 @@ 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: (MultiLocation::with_parents(1).unwrap(), SEND_AMOUNT).into(), effects: vec![ - buy_execution((Parent, SEND_AMOUNT), weight), + buy_execution((MultiLocation::with_parents(1).unwrap(), SEND_AMOUNT), weight), DepositAsset { assets: All.into(), max_assets: 1, beneficiary: sender.clone() }, ], }; @@ -50,7 +50,7 @@ fn send_works() { assert_eq!( sent_xcm(), vec![( - MultiLocation::Here, + MultiLocation::here(), RelayedFrom { who: sender.clone(), message: Box::new(message.clone()) } )] ); @@ -74,25 +74,16 @@ fn send_fails_when_xcm_router_blocks() { let sender: MultiLocation = Junction::AccountId32 { network: AnyNetwork::get(), id: ALICE.into() }.into(); let message = Xcm::ReserveAssetDeposited { - assets: (Parent, SEND_AMOUNT).into(), + assets: (MultiLocation::with_parents(1).unwrap(), SEND_AMOUNT).into(), effects: vec![ - buy_execution((Parent, SEND_AMOUNT), weight), + buy_execution((MultiLocation::with_parents(1).unwrap(), SEND_AMOUNT), weight), DepositAsset { assets: All.into(), max_assets: 1, beneficiary: sender.clone() }, ], }; assert_noop!( XcmPallet::send( Origin::signed(ALICE), - X8( - Junction::Parent, - Junction::Parent, - Junction::Parent, - Junction::Parent, - Junction::Parent, - Junction::Parent, - Junction::Parent, - Junction::Parent - ), + MultiLocation::with_parents(8).unwrap(), message.clone() ), crate::Error::<Test>::SendFailure @@ -114,8 +105,8 @@ fn teleport_assets_works() { assert_ok!(XcmPallet::teleport_assets( Origin::signed(ALICE), RelayLocation::get(), - X1(AccountId32 { network: Any, id: BOB.into() }), - (Here, SEND_AMOUNT).into(), + X1(AccountId32 { network: Any, id: BOB.into() }).into(), + (MultiLocation::here(), SEND_AMOUNT).into(), 0, weight, )); @@ -144,7 +135,7 @@ fn reserve_transfer_assets_works() { Origin::signed(ALICE), Parachain(PARA_ID).into(), dest.clone(), - (Here, SEND_AMOUNT).into(), + (MultiLocation::here(), SEND_AMOUNT).into(), 0, weight )); @@ -158,9 +149,12 @@ fn reserve_transfer_assets_works() { vec![( Parachain(PARA_ID).into(), Xcm::ReserveAssetDeposited { - assets: (X1(Parent), SEND_AMOUNT).into(), + assets: (MultiLocation::with_parents(1).unwrap(), SEND_AMOUNT).into(), effects: vec![ - buy_execution((Parent, SEND_AMOUNT), weight), + buy_execution( + (MultiLocation::with_parents(1).unwrap(), SEND_AMOUNT), + weight + ), DepositAsset { assets: All.into(), max_assets: 1, beneficiary: dest }, ] } @@ -189,9 +183,9 @@ fn execute_withdraw_to_deposit_works() { assert_ok!(XcmPallet::execute( Origin::signed(ALICE), Box::new(Xcm::WithdrawAsset { - assets: (Here, SEND_AMOUNT).into(), + assets: (MultiLocation::here(), SEND_AMOUNT).into(), effects: vec![ - buy_execution((Here, SEND_AMOUNT), weight), + buy_execution((MultiLocation::here(), SEND_AMOUNT), weight), DepositAsset { assets: All.into(), max_assets: 1, beneficiary: dest } ], }), From 5c330ad07ee39e9d71bb65fea8d0e58498e86ffe Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Fri, 6 Aug 2021 10:47:14 -0700 Subject: [PATCH 102/166] fix --- xcm/xcm-executor/src/traits/transact_asset.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/xcm/xcm-executor/src/traits/transact_asset.rs b/xcm/xcm-executor/src/traits/transact_asset.rs index dd155a60bf98..608498fd2dd9 100644 --- a/xcm/xcm-executor/src/traits/transact_asset.rs +++ b/xcm/xcm-executor/src/traits/transact_asset.rs @@ -193,7 +193,6 @@ impl TransactAsset for Tuple { #[cfg(test)] mod tests { use super::*; - use MultiLocation::Here; pub struct UnimplementedTransactor; impl TransactAsset for UnimplementedTransactor {} From 0edc39fcacc08a12ea0e411a384a3a527fef6daa Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Fri, 6 Aug 2021 12:38:34 -0700 Subject: [PATCH 103/166] Substitute with_parent with with_parents_const --- Cargo.lock | 1 + xcm/Cargo.toml | 1 + xcm/pallet-xcm/src/tests.rs | 14 ++-- xcm/src/v1/multilocation.rs | 32 ++++----- xcm/src/v1/traits.rs | 2 +- xcm/xcm-builder/src/currency_adapter.rs | 2 +- xcm/xcm-builder/src/matches_fungible.rs | 4 +- xcm/xcm-builder/src/tests.rs | 84 +++++++++++----------- xcm/xcm-simulator/example/src/lib.rs | 2 +- xcm/xcm-simulator/example/src/parachain.rs | 6 +- 10 files changed, 71 insertions(+), 77 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cd449c18b316..5514cf38ac8c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12282,6 +12282,7 @@ dependencies = [ "impl-trait-for-tuples", "log", "parity-scale-codec", + "static_assertions", ] [[package]] diff --git a/xcm/Cargo.toml b/xcm/Cargo.toml index a1bfa76130a7..67865f32f929 100644 --- a/xcm/Cargo.toml +++ b/xcm/Cargo.toml @@ -10,6 +10,7 @@ impl-trait-for-tuples = "0.2.0" parity-scale-codec = { version = "2.0.0", default-features = false, features = [ "derive" ] } derivative = {version = "2.2.0", default-features = false, features = [ "use_core" ] } log = { version = "0.4.14", default-features = false } +static_assertions = "1.1.0" [features] default = ["std"] diff --git a/xcm/pallet-xcm/src/tests.rs b/xcm/pallet-xcm/src/tests.rs index 764eeaff98c4..b0785493f059 100644 --- a/xcm/pallet-xcm/src/tests.rs +++ b/xcm/pallet-xcm/src/tests.rs @@ -40,9 +40,9 @@ fn send_works() { let sender: MultiLocation = AccountId32 { network: AnyNetwork::get(), id: ALICE.into() }.into(); let message = Xcm::ReserveAssetDeposited { - assets: (MultiLocation::with_parents(1).unwrap(), SEND_AMOUNT).into(), + assets: (MultiLocation::with_parents::<1>(), SEND_AMOUNT).into(), effects: vec![ - buy_execution((MultiLocation::with_parents(1).unwrap(), SEND_AMOUNT), weight), + buy_execution((MultiLocation::with_parents::<1>(), SEND_AMOUNT), weight), DepositAsset { assets: All.into(), max_assets: 1, beneficiary: sender.clone() }, ], }; @@ -74,16 +74,16 @@ fn send_fails_when_xcm_router_blocks() { let sender: MultiLocation = Junction::AccountId32 { network: AnyNetwork::get(), id: ALICE.into() }.into(); let message = Xcm::ReserveAssetDeposited { - assets: (MultiLocation::with_parents(1).unwrap(), SEND_AMOUNT).into(), + assets: (MultiLocation::with_parents::<1>(), SEND_AMOUNT).into(), effects: vec![ - buy_execution((MultiLocation::with_parents(1).unwrap(), SEND_AMOUNT), weight), + buy_execution((MultiLocation::with_parents::<1>(), SEND_AMOUNT), weight), DepositAsset { assets: All.into(), max_assets: 1, beneficiary: sender.clone() }, ], }; assert_noop!( XcmPallet::send( Origin::signed(ALICE), - MultiLocation::with_parents(8).unwrap(), + MultiLocation::with_parents::<8>(), message.clone() ), crate::Error::<Test>::SendFailure @@ -149,10 +149,10 @@ fn reserve_transfer_assets_works() { vec![( Parachain(PARA_ID).into(), Xcm::ReserveAssetDeposited { - assets: (MultiLocation::with_parents(1).unwrap(), SEND_AMOUNT).into(), + assets: (MultiLocation::with_parents::<1>(), SEND_AMOUNT).into(), effects: vec![ buy_execution( - (MultiLocation::with_parents(1).unwrap(), SEND_AMOUNT), + (MultiLocation::with_parents::<1>(), SEND_AMOUNT), weight ), DepositAsset { assets: All.into(), max_assets: 1, beneficiary: dest }, diff --git a/xcm/src/v1/multilocation.rs b/xcm/src/v1/multilocation.rs index b4ef955a4732..2cd8d6b81a81 100644 --- a/xcm/src/v1/multilocation.rs +++ b/xcm/src/v1/multilocation.rs @@ -22,6 +22,7 @@ use core::{ mem, result, }; use parity_scale_codec::{self, Decode, Encode}; +use static_assertions::const_assert; /// A relative path between state-bearing consensus systems. /// @@ -81,21 +82,12 @@ impl MultiLocation { /// Creates a new `MultiLocation` with the specified number of parents in the `P` const generic /// parameter and a `Null` interior. - // #FIXME: Use a where clause to evaluate P for well-formedness once const eval of const - // generics is possible. - pub const fn with_parents_const<const P: u8>() -> MultiLocation { + pub const fn with_parents<const P: u8>() -> MultiLocation { + // If this condition does not hold, then P may overflow MAX_MULTILOCATION_LENGTH. + const_assert!(MAX_MULTILOCATION_LENGTH >= 255); MultiLocation { parents: P, interior: Junctions::Null } } - /// Creates a new `MultiLocation` with the specified number of parents and a `Null` interior. - /// Returns an error if `parents` is greater than `MAX_MULTILOCATION_LENGTH`. - pub const fn with_parents(parents: u8) -> result::Result<MultiLocation, ()> { - if parents as usize > MAX_MULTILOCATION_LENGTH { - return Err(()) - } - Ok(MultiLocation { parents, interior: Junctions::Null }) - } - /// Creates a new `MultiLocation` with no parents and a single `Parachain` interior junction /// specified by `para_id`. /// @@ -837,16 +829,16 @@ impl TryFrom<MultiLocation0> for MultiLocation { use Junctions::*; match old { MultiLocation0::Null => Ok(MultiLocation::here()), - MultiLocation0::X1(j0) if j0.is_parent() => MultiLocation::with_parents(1), + MultiLocation0::X1(j0) if j0.is_parent() => Ok(MultiLocation::with_parents::<1>()), MultiLocation0::X1(j0) => Ok(X1(j0.try_into()?).into()), MultiLocation0::X2(j0, j1) if j0.is_parent() && j1.is_parent() => - MultiLocation::with_parents(2), + Ok(MultiLocation::with_parents::<2>()), 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() => - MultiLocation::with_parents(3), + Ok(MultiLocation::with_parents::<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() => @@ -855,7 +847,7 @@ impl TryFrom<MultiLocation0> for MultiLocation { 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() => - MultiLocation::with_parents(4), + Ok(MultiLocation::with_parents::<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()?) }), @@ -871,7 +863,7 @@ impl TryFrom<MultiLocation0> for MultiLocation { if j0.is_parent() && j1.is_parent() && j2.is_parent() && j3.is_parent() && j4.is_parent() => - MultiLocation::with_parents(5), + Ok(MultiLocation::with_parents::<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()?) }), @@ -900,7 +892,7 @@ impl TryFrom<MultiLocation0> for MultiLocation { j1.is_parent() && j2.is_parent() && j3.is_parent() && j4.is_parent() && j5.is_parent() => - MultiLocation::with_parents(6), + Ok(MultiLocation::with_parents::<6>()), MultiLocation0::X6(j0, j1, j2, j3, j4, j5) if j0.is_parent() && j1.is_parent() && j2.is_parent() && @@ -944,7 +936,7 @@ impl TryFrom<MultiLocation0> for MultiLocation { j1.is_parent() && j2.is_parent() && j3.is_parent() && j4.is_parent() && j5.is_parent() && j6.is_parent() => - MultiLocation::with_parents(7), + Ok(MultiLocation::with_parents::<7>()), MultiLocation0::X7(j0, j1, j2, j3, j4, j5, j6) if j0.is_parent() && j1.is_parent() && j2.is_parent() && @@ -1006,7 +998,7 @@ impl TryFrom<MultiLocation0> for MultiLocation { j3.is_parent() && j4.is_parent() && j5.is_parent() && j6.is_parent() && j7.is_parent() => - MultiLocation::with_parents(8), + Ok(MultiLocation::with_parents::<8>()), MultiLocation0::X8(j0, j1, j2, j3, j4, j5, j6, j7) if j0.is_parent() && j1.is_parent() && j2.is_parent() && diff --git a/xcm/src/v1/traits.rs b/xcm/src/v1/traits.rs index 78f3eb692b0c..2410223f8b3e 100644 --- a/xcm/src/v1/traits.rs +++ b/xcm/src/v1/traits.rs @@ -229,7 +229,7 @@ impl<C> ExecuteXcm<C> for () { /// # fn main() { /// let call: Vec<u8> = ().encode(); /// let message = Xcm::Transact { origin_type: OriginKind::Superuser, require_weight_at_most: 0, call: call.into() }; -/// let destination = MultiLocation::with_parents(1).unwrap(); +/// let destination = MultiLocation::with_parents::<1>(); /// /// assert!( /// // Sender2 will block this. diff --git a/xcm/xcm-builder/src/currency_adapter.rs b/xcm/xcm-builder/src/currency_adapter.rs index eef790de1a18..097010d2c889 100644 --- a/xcm/xcm-builder/src/currency_adapter.rs +++ b/xcm/xcm-builder/src/currency_adapter.rs @@ -61,7 +61,7 @@ impl From<Error> for XcmError { /// /// /// Our relay chain's location. /// parameter_types! { -/// RelayChain: MultiLocation = MultiLocation::with_parents(1).unwrap(); +/// RelayChain: MultiLocation = MultiLocation::with_parents::<1>(); /// CheckingAccount: AccountId = Default::default(); /// } /// diff --git a/xcm/xcm-builder/src/matches_fungible.rs b/xcm/xcm-builder/src/matches_fungible.rs index 1c95a7fa269c..579b2eba3f78 100644 --- a/xcm/xcm-builder/src/matches_fungible.rs +++ b/xcm/xcm-builder/src/matches_fungible.rs @@ -37,11 +37,11 @@ use xcm_executor::traits::MatchesFungible; /// use xcm_executor::traits::MatchesFungible; /// /// frame_support::parameter_types! { -/// pub TargetLocation: MultiLocation = MultiLocation::with_parents(1).unwrap(); +/// pub TargetLocation: MultiLocation = MultiLocation::with_parents::<1>(); /// } /// /// # fn main() { -/// let asset = (MultiLocation::with_parents(1).unwrap(), 999).into(); +/// let asset = (MultiLocation::with_parents::<1>(), 999).into(); /// // match `asset` if it is a concrete asset in `TargetLocation`. /// assert_eq!(<IsConcrete<TargetLocation> as MatchesFungible<u128>>::matches_fungible(&asset), Some(999)); /// # } diff --git a/xcm/xcm-builder/src/tests.rs b/xcm/xcm-builder/src/tests.rs index 118d65147ee9..0d6ddb4d5331 100644 --- a/xcm/xcm-builder/src/tests.rs +++ b/xcm/xcm-builder/src/tests.rs @@ -21,12 +21,12 @@ use xcm_executor::{traits::*, Config, XcmExecutor}; #[test] fn basic_setup_works() { add_reserve( - MultiLocation::with_parents(1).unwrap(), - Wild((MultiLocation::with_parents(1).unwrap(), WildFungible).into()), + MultiLocation::with_parents::<1>(), + Wild((MultiLocation::with_parents::<1>(), WildFungible).into()), ); assert!(<TestConfig as Config>::IsReserve::filter_asset_location( - &(MultiLocation::with_parents(1).unwrap(), 100).into(), - &MultiLocation::with_parents(1).unwrap(), + &(MultiLocation::with_parents::<1>(), 100).into(), + &MultiLocation::with_parents::<1>(), )); assert_eq!(to_account(MultiLocation::with_parachain_interior(1)), Ok(1001)); @@ -47,10 +47,10 @@ fn basic_setup_works() { #[test] fn weigher_should_work() { let mut message = opaque::Xcm::ReserveAssetDeposited { - assets: (MultiLocation::with_parents(1).unwrap(), 100).into(), + assets: (MultiLocation::with_parents::<1>(), 100).into(), effects: vec![ Order::BuyExecution { - fees: (MultiLocation::with_parents(1).unwrap(), 1).into(), + fees: (MultiLocation::with_parents::<1>(), 1).into(), weight: 0, debt: 30, halt_on_error: true, @@ -71,13 +71,13 @@ fn weigher_should_work() { #[test] fn take_weight_credit_barrier_should_work() { let mut message = opaque::Xcm::TransferAsset { - assets: (MultiLocation::with_parents(1).unwrap(), 100).into(), + assets: (MultiLocation::with_parents::<1>(), 100).into(), beneficiary: MultiLocation::here(), }; let mut weight_credit = 10; let r = TakeWeightCredit::should_execute( - &MultiLocation::new(1, Null).unwrap(), + &MultiLocation::with_parents::<1>(), true, &mut message, 10, @@ -87,7 +87,7 @@ fn take_weight_credit_barrier_should_work() { assert_eq!(weight_credit, 0); let r = TakeWeightCredit::should_execute( - &MultiLocation::new(1, Null).unwrap(), + &MultiLocation::with_parents::<1>(), true, &mut message, 10, @@ -100,11 +100,11 @@ fn take_weight_credit_barrier_should_work() { #[test] fn allow_unpaid_should_work() { let mut message = opaque::Xcm::TransferAsset { - assets: (MultiLocation::with_parents(1).unwrap(), 100).into(), + assets: (MultiLocation::with_parents::<1>(), 100).into(), beneficiary: MultiLocation::here(), }; - AllowUnpaidFrom::set(vec![MultiLocation::new(1, Null).unwrap()]); + AllowUnpaidFrom::set(vec![MultiLocation::with_parents::<1>()]); let r = AllowUnpaidExecutionFrom::<IsInVec<AllowUnpaidFrom>>::should_execute( &X1(Parachain(1)).into(), @@ -116,7 +116,7 @@ fn allow_unpaid_should_work() { assert_eq!(r, Err(())); let r = AllowUnpaidExecutionFrom::<IsInVec<AllowUnpaidFrom>>::should_execute( - &MultiLocation::new(1, Null).unwrap(), + &MultiLocation::with_parents::<1>(), true, &mut message, 10, @@ -127,10 +127,10 @@ fn allow_unpaid_should_work() { #[test] fn allow_paid_should_work() { - AllowPaidFrom::set(vec![MultiLocation::new(1, Null).unwrap()]); + AllowPaidFrom::set(vec![MultiLocation::with_parents::<1>()]); let mut message = opaque::Xcm::TransferAsset { - assets: (MultiLocation::with_parents(1).unwrap(), 100).into(), + assets: (MultiLocation::with_parents::<1>(), 100).into(), beneficiary: MultiLocation::here(), }; @@ -143,9 +143,9 @@ fn allow_paid_should_work() { ); assert_eq!(r, Err(())); - let fees = (MultiLocation::with_parents(1).unwrap(), 1).into(); + let fees = (MultiLocation::with_parents::<1>(), 1).into(); let mut underpaying_message = opaque::Xcm::ReserveAssetDeposited { - assets: (MultiLocation::with_parents(1).unwrap(), 100).into(), + assets: (MultiLocation::with_parents::<1>(), 100).into(), effects: vec![ Order::BuyExecution { fees, @@ -164,7 +164,7 @@ fn allow_paid_should_work() { }; let r = AllowTopLevelPaidExecutionFrom::<IsInVec<AllowPaidFrom>>::should_execute( - &MultiLocation::new(1, Null).unwrap(), + &MultiLocation::with_parents::<1>(), true, &mut underpaying_message, 30, @@ -172,9 +172,9 @@ fn allow_paid_should_work() { ); assert_eq!(r, Err(())); - let fees = (MultiLocation::with_parents(1).unwrap(), 1).into(); + let fees = (MultiLocation::with_parents::<1>(), 1).into(); let mut paying_message = opaque::Xcm::ReserveAssetDeposited { - assets: (MultiLocation::with_parents(1).unwrap(), 100).into(), + assets: (MultiLocation::with_parents::<1>(), 100).into(), effects: vec![ Order::BuyExecution { fees, @@ -202,7 +202,7 @@ fn allow_paid_should_work() { assert_eq!(r, Err(())); let r = AllowTopLevelPaidExecutionFrom::<IsInVec<AllowPaidFrom>>::should_execute( - &MultiLocation::new(1, Null).unwrap(), + &MultiLocation::with_parents::<1>(), true, &mut paying_message, 30, @@ -213,17 +213,17 @@ fn allow_paid_should_work() { #[test] fn paying_reserve_deposit_should_work() { - AllowPaidFrom::set(vec![MultiLocation::with_parents(1).unwrap()]); + AllowPaidFrom::set(vec![MultiLocation::with_parents::<1>()]); add_reserve( - MultiLocation::with_parents(1).unwrap(), - (MultiLocation::with_parents(1).unwrap(), WildFungible).into(), + MultiLocation::with_parents::<1>(), + (MultiLocation::with_parents::<1>(), WildFungible).into(), ); - WeightPrice::set((MultiLocation::with_parents(1).unwrap().into(), 1_000_000_000_000)); + WeightPrice::set((MultiLocation::with_parents::<1>().into(), 1_000_000_000_000)); - let origin = MultiLocation::with_parents(1).unwrap(); - let fees = (MultiLocation::with_parents(1).unwrap(), 30).into(); + let origin = MultiLocation::with_parents::<1>(); + let fees = (MultiLocation::with_parents::<1>(), 30).into(); let message = Xcm::<TestCall>::ReserveAssetDeposited { - assets: (MultiLocation::with_parents(1).unwrap(), 100).into(), + assets: (MultiLocation::with_parents::<1>(), 100).into(), effects: vec![ Order::<TestCall>::BuyExecution { fees, @@ -243,7 +243,7 @@ fn paying_reserve_deposit_should_work() { let weight_limit = 50; let r = XcmExecutor::<TestConfig>::execute_xcm(origin, message, weight_limit); assert_eq!(r, Outcome::Complete(30)); - assert_eq!(assets(3000), vec![(MultiLocation::with_parents(1).unwrap(), 70).into()]); + assert_eq!(assets(3000), vec![(MultiLocation::with_parents::<1>(), 70).into()]); } #[test] @@ -298,7 +298,7 @@ fn reserve_transfer_should_work() { vec![( X1(Parachain(2)).into(), Xcm::ReserveAssetDeposited { - assets: (MultiLocation::with_parents(1).unwrap(), 100).into(), + assets: (MultiLocation::with_parents::<1>(), 100).into(), effects: vec![Order::DepositAsset { assets: All.into(), max_assets: 1, @@ -311,9 +311,9 @@ fn reserve_transfer_should_work() { #[test] fn transacting_should_work() { - AllowUnpaidFrom::set(vec![MultiLocation::with_parents(1).unwrap()]); + AllowUnpaidFrom::set(vec![MultiLocation::with_parents::<1>()]); - let origin = MultiLocation::with_parents(1).unwrap(); + let origin = MultiLocation::with_parents::<1>(); let message = Xcm::<TestCall>::Transact { origin_type: OriginKind::Native, require_weight_at_most: 50, @@ -326,9 +326,9 @@ fn transacting_should_work() { #[test] fn transacting_should_respect_max_weight_requirement() { - AllowUnpaidFrom::set(vec![MultiLocation::with_parents(1).unwrap()]); + AllowUnpaidFrom::set(vec![MultiLocation::with_parents::<1>()]); - let origin = MultiLocation::with_parents(1).unwrap(); + let origin = MultiLocation::with_parents::<1>(); let message = Xcm::<TestCall>::Transact { origin_type: OriginKind::Native, require_weight_at_most: 40, @@ -341,9 +341,9 @@ fn transacting_should_respect_max_weight_requirement() { #[test] fn transacting_should_refund_weight() { - AllowUnpaidFrom::set(vec![MultiLocation::with_parents(1).unwrap()]); + AllowUnpaidFrom::set(vec![MultiLocation::with_parents::<1>()]); - let origin = MultiLocation::with_parents(1).unwrap(); + let origin = MultiLocation::with_parents::<1>(); let message = Xcm::<TestCall>::Transact { origin_type: OriginKind::Native, require_weight_at_most: 50, @@ -358,13 +358,13 @@ fn transacting_should_refund_weight() { fn paid_transacting_should_refund_payment_for_unused_weight() { let one: MultiLocation = X1(AccountIndex64 { index: 1, network: Any }).into(); AllowPaidFrom::set(vec![one.clone()]); - add_asset(1, (MultiLocation::with_parents(1).unwrap(), 100).into()); - WeightPrice::set((MultiLocation::with_parents(1).unwrap().into(), 1_000_000_000_000)); + add_asset(1, (MultiLocation::with_parents::<1>(), 100).into()); + WeightPrice::set((MultiLocation::with_parents::<1>().into(), 1_000_000_000_000)); let origin = one.clone(); - let fees = (MultiLocation::with_parents(1).unwrap(), 100).into(); + let fees = (MultiLocation::with_parents::<1>(), 100).into(); let message = Xcm::<TestCall>::WithdrawAsset { - assets: (MultiLocation::with_parents(1).unwrap(), 100).into(), // enough for 100 units of weight. + assets: (MultiLocation::with_parents::<1>(), 100).into(), // enough for 100 units of weight. effects: vec![ Order::<TestCall>::BuyExecution { fees, @@ -389,17 +389,17 @@ fn paid_transacting_should_refund_payment_for_unused_weight() { let weight_limit = 100; let r = XcmExecutor::<TestConfig>::execute_xcm(origin, message, weight_limit); assert_eq!(r, Outcome::Complete(50)); - assert_eq!(assets(1), vec![(MultiLocation::with_parents(1).unwrap(), 50).into()]); + assert_eq!(assets(1), vec![(MultiLocation::with_parents::<1>(), 50).into()]); } #[test] fn prepaid_result_of_query_should_get_free_execution() { let query_id = 33; - let origin = MultiLocation::with_parents(1).unwrap(); + let origin = MultiLocation::with_parents::<1>(); // 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((MultiLocation::with_parents(1).unwrap(), 100).into()); + let the_response = Response::Assets((MultiLocation::with_parents::<1>(), 100).into()); let message = Xcm::<TestCall>::QueryResponse { query_id, response: the_response.clone() }; let weight_limit = 10; diff --git a/xcm/xcm-simulator/example/src/lib.rs b/xcm/xcm-simulator/example/src/lib.rs index 4c46090a37c1..dba08d2335be 100644 --- a/xcm/xcm-simulator/example/src/lib.rs +++ b/xcm/xcm-simulator/example/src/lib.rs @@ -139,7 +139,7 @@ mod tests { ParaA::execute_with(|| { assert_ok!(ParachainPalletXcm::send_xcm( MultiLocation::here(), - MultiLocation::with_parents(1).unwrap(), + MultiLocation::with_parents::<1>(), Transact { origin_type: OriginKind::SovereignAccount, require_weight_at_most: INITIAL_BALANCE as u64, diff --git a/xcm/xcm-simulator/example/src/parachain.rs b/xcm/xcm-simulator/example/src/parachain.rs index 33b97d26b165..2e85e86169f6 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::with_parents_const::<1>(); + pub const KsmLocation: MultiLocation = MultiLocation::with_parents::<1>(); 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(MultiLocation::with_parents(1).unwrap()), 1); + pub KsmPerSecond: (AssetId, u128) = (Concrete(MultiLocation::with_parents::<1>()), 1); } pub type LocalAssetTransactor = @@ -267,7 +267,7 @@ pub mod mock_msg_queue { }, Ok(Ok(x)) => { let outcome = T::XcmExecutor::execute_xcm( - MultiLocation::with_parents(1).unwrap(), + MultiLocation::with_parents::<1>(), x, limit, ); From 4de501bb1b4dcf20b49bf44b81cfed0cf14ec29b Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Fri, 6 Aug 2021 12:43:31 -0700 Subject: [PATCH 104/166] Rename argument name from a to m --- xcm/src/v0/multi_asset.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/xcm/src/v0/multi_asset.rs b/xcm/src/v0/multi_asset.rs index 071ebd5bd90a..f3bfb2b2c60f 100644 --- a/xcm/src/v0/multi_asset.rs +++ b/xcm/src/v0/multi_asset.rs @@ -17,7 +17,7 @@ //! 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}, @@ -294,13 +294,13 @@ impl MultiAsset { } } -impl TryFrom<MultiAsset1> for MultiAsset { +impl TryFrom<crate::v1::MultiAsset> for MultiAsset { type Error = (); - fn try_from(a: MultiAsset1) -> result::Result<MultiAsset, ()> { + fn try_from(m: crate::v1::MultiAsset) -> result::Result<MultiAsset, ()> { use crate::v1::{AssetId::*, Fungibility::*}; use MultiAsset::*; - Ok(match (a.id, a.fun) { + Ok(match (m.id, m.fun) { (Concrete(id), Fungible(amount)) => ConcreteFungible { id: id.try_into()?, amount }, (Concrete(class), NonFungible(instance)) => ConcreteNonFungible { class: class.try_into()?, instance }, @@ -313,18 +313,18 @@ impl TryFrom<MultiAsset1> for MultiAsset { impl TryFrom<MultiAssets> for Vec<MultiAsset> { type Error = (); - fn try_from(a: MultiAssets) -> result::Result<Vec<MultiAsset>, ()> { - a.drain().into_iter().map(MultiAsset::try_from).collect() + fn try_from(m: MultiAssets) -> result::Result<Vec<MultiAsset>, ()> { + m.drain().into_iter().map(MultiAsset::try_from).collect() } } impl TryFrom<WildMultiAsset> for MultiAsset { type Error = (); - fn try_from(a: WildMultiAsset) -> result::Result<MultiAsset, ()> { + fn try_from(m: WildMultiAsset) -> result::Result<MultiAsset, ()> { use crate::v1::{AssetId::*, WildFungibility::*}; use MultiAsset::*; - Ok(match a { + Ok(match m { WildMultiAsset::All => All, WildMultiAsset::AllOf { id, fun } => match (id, fun) { (Concrete(id), Fungible) => AllConcreteFungible { id: id.try_into()? }, @@ -340,16 +340,16 @@ impl TryFrom<WildMultiAsset> for MultiAsset { impl TryFrom<WildMultiAsset> for Vec<MultiAsset> { type Error = (); - fn try_from(a: WildMultiAsset) -> result::Result<Vec<MultiAsset>, ()> { - Ok(vec![a.try_into()?]) + fn try_from(m: WildMultiAsset) -> result::Result<Vec<MultiAsset>, ()> { + Ok(vec![m.try_into()?]) } } impl TryFrom<MultiAssetFilter> for Vec<MultiAsset> { type Error = (); - fn try_from(a: MultiAssetFilter) -> result::Result<Vec<MultiAsset>, ()> { - match a { + fn try_from(m: MultiAssetFilter) -> result::Result<Vec<MultiAsset>, ()> { + match m { MultiAssetFilter::Definite(assets) => assets.try_into(), MultiAssetFilter::Wild(wildcard) => wildcard.try_into(), } From 393381d5ff7ee618e674d9550326ace350fadb16 Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Fri, 6 Aug 2021 12:45:26 -0700 Subject: [PATCH 105/166] Rename split_last to split_last_interior --- xcm/src/v1/multilocation.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/xcm/src/v1/multilocation.rs b/xcm/src/v1/multilocation.rs index 2cd8d6b81a81..6c8fc3b7253b 100644 --- a/xcm/src/v1/multilocation.rs +++ b/xcm/src/v1/multilocation.rs @@ -142,9 +142,10 @@ impl MultiLocation { (multilocation, first) } - /// 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 or if `self` only contains parents. - pub fn split_last(self) -> (MultiLocation, Option<Junction>) { + /// 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<Junction>) { let MultiLocation { parents, interior: junctions } = self; let (prefix, last) = junctions.split_last(); let multilocation = MultiLocation { parents, interior: prefix }; From a064c94476650f218161711f4ac52eb637109e85 Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Fri, 6 Aug 2021 12:55:24 -0700 Subject: [PATCH 106/166] Allow adding multiple parents in MultiLocation --- xcm/src/v1/multilocation.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/xcm/src/v1/multilocation.rs b/xcm/src/v1/multilocation.rs index 6c8fc3b7253b..c38690ddb829 100644 --- a/xcm/src/v1/multilocation.rs +++ b/xcm/src/v1/multilocation.rs @@ -152,12 +152,12 @@ impl MultiLocation { (multilocation, last) } - /// Bumps the parent count up by 1. Returns `Err` in case of overflow. - pub fn push_parent(&mut self) -> result::Result<(), ()> { - if self.len() >= MAX_MULTILOCATION_LENGTH { + /// Bumps the parent count up by `n`. Returns `Err` in case of overflow. + pub fn add_parents(&mut self, n: u8) -> result::Result<(), ()> { + if self.len() + (n as usize) > MAX_MULTILOCATION_LENGTH { return Err(()) } - self.parents = self.parents.saturating_add(1); + self.parents = self.parents.saturating_add(n); Ok(()) } @@ -193,13 +193,13 @@ impl MultiLocation { } } - /// Consumes `self` and returns a `MultiLocation` with its parent count incremented by 1, or + /// Consumes `self` and returns a `MultiLocation` with its parent count incremented by `n`, or /// an `Err` with the original value of `self` in case of overflow. - pub fn pushed_with_parent(self) -> result::Result<Self, Self> { - if self.len() >= MAX_MULTILOCATION_LENGTH { + pub fn added_with_parents(self, n: u8) -> result::Result<Self, Self> { + if self.len() + (n as usize) > MAX_MULTILOCATION_LENGTH { return Err(self) } - Ok(MultiLocation { parents: self.parents.saturating_add(1), ..self }) + Ok(MultiLocation { parents: self.parents.saturating_add(n), ..self }) } /// Consumes `self` and returns a `MultiLocation` suffixed with `new`, or an `Err` with the original value of From 0b0c22b2e1b9093da61a92a260998b7bb4272f74 Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Fri, 6 Aug 2021 13:02:11 -0700 Subject: [PATCH 107/166] Rename pop_parent to dec_parent --- xcm/src/v1/multilocation.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xcm/src/v1/multilocation.rs b/xcm/src/v1/multilocation.rs index c38690ddb829..5d6c779b9019 100644 --- a/xcm/src/v1/multilocation.rs +++ b/xcm/src/v1/multilocation.rs @@ -250,7 +250,7 @@ impl MultiLocation { } /// Decrements the parent count by 1. - pub fn pop_parent(&mut self) { + pub fn dec_parent(&mut self) { self.parents = self.parents.saturating_sub(1); } @@ -346,7 +346,7 @@ impl MultiLocation { final_parent_count += self.parents; break } - self.pop_parent(); + self.dec_parent(); } self.parents = final_parent_count; From 8df05d0619a617dcff2b290d829f84a73f88bc2c Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Fri, 6 Aug 2021 13:05:40 -0700 Subject: [PATCH 108/166] Ensure relay chain XCM sender receives a MultiLocation without any parents --- runtime/common/src/xcm_sender.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/runtime/common/src/xcm_sender.rs b/runtime/common/src/xcm_sender.rs index f1d5aede1d73..aa190296904f 100644 --- a/runtime/common/src/xcm_sender.rs +++ b/runtime/common/src/xcm_sender.rs @@ -28,8 +28,12 @@ impl<T: configuration::Config + dmp::Config, W: xcm::WrapVersion> SendXcm for ChildParachainRouter<T, W> { fn send_xcm(dest: MultiLocation, msg: Xcm) -> Result { + if dest.parent_count() > 0 { + return Err(Error::CannotReachDestination(dest, msg)) + } + match dest.interior() { - Junctions::X1(Junction::Parachain(id)) if dest.parent_count() == 0 => { + Junctions::X1(Junction::Parachain(id)) => { // Downward message passing. let versioned_xcm = W::wrap_version(&dest, msg).map_err(|()| Error::DestinationUnsupported)?; From f8bbf77c44a5750a79db0b0c5054d7abc8d93b70 Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Fri, 6 Aug 2021 13:10:43 -0700 Subject: [PATCH 109/166] Block only when MultiLocation destination length is 8 --- xcm/pallet-xcm/src/mock.rs | 2 +- xcm/xcm-builder/src/location_conversion.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/xcm/pallet-xcm/src/mock.rs b/xcm/pallet-xcm/src/mock.rs index 845ced90b58e..db41796af2a2 100644 --- a/xcm/pallet-xcm/src/mock.rs +++ b/xcm/pallet-xcm/src/mock.rs @@ -75,7 +75,7 @@ impl SendXcm for TestSendXcm { pub struct TestSendXcmErrX8; impl SendXcm for TestSendXcmErrX8 { fn send_xcm(dest: MultiLocation, msg: Xcm) -> XcmResult { - if dest.len() >= 8 { + if dest.len() == 8 { Err(XcmError::Undefined) } else { SENT_XCM.with(|q| q.borrow_mut().push((dest, msg))); diff --git a/xcm/xcm-builder/src/location_conversion.rs b/xcm/xcm-builder/src/location_conversion.rs index 05f07da0cfd2..7cf1063d29fa 100644 --- a/xcm/xcm-builder/src/location_conversion.rs +++ b/xcm/xcm-builder/src/location_conversion.rs @@ -51,7 +51,7 @@ impl<AccountId: Default + Eq + Clone> Convert<MultiLocation, AccountId> fn reverse_ref(who: impl Borrow<AccountId>) -> Result<MultiLocation, ()> { if who.borrow() == &AccountId::default() { - Ok(MultiLocation::with_parents(1).expect("well-formed MultiLocation; qed")) + Ok(MultiLocation::with_parents::<1>()) } else { Err(()) } From 9b12f9b565d091eb04ddbefc88b85fe3003587a8 Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Fri, 6 Aug 2021 13:20:29 -0700 Subject: [PATCH 110/166] Cargo fmt --- xcm/pallet-xcm/src/tests.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/xcm/pallet-xcm/src/tests.rs b/xcm/pallet-xcm/src/tests.rs index b0785493f059..6cb0e8fe5f92 100644 --- a/xcm/pallet-xcm/src/tests.rs +++ b/xcm/pallet-xcm/src/tests.rs @@ -151,10 +151,7 @@ fn reserve_transfer_assets_works() { Xcm::ReserveAssetDeposited { assets: (MultiLocation::with_parents::<1>(), SEND_AMOUNT).into(), effects: vec![ - buy_execution( - (MultiLocation::with_parents::<1>(), SEND_AMOUNT), - weight - ), + buy_execution((MultiLocation::with_parents::<1>(), SEND_AMOUNT), weight), DepositAsset { assets: All.into(), max_assets: 1, beneficiary: dest }, ] } From 5edf59c2e791fe337d9d98725532b356ba6e2620 Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Sat, 7 Aug 2021 04:42:43 -0700 Subject: [PATCH 111/166] Remove reverse iterators, implement DoubleEndedIterator and add tests --- xcm/src/v1/multilocation.rs | 91 +++++++++++++++++++++++++++++-------- 1 file changed, 71 insertions(+), 20 deletions(-) diff --git a/xcm/src/v1/multilocation.rs b/xcm/src/v1/multilocation.rs index 5d6c779b9019..f1845ba3bcef 100644 --- a/xcm/src/v1/multilocation.rs +++ b/xcm/src/v1/multilocation.rs @@ -350,7 +350,7 @@ impl MultiLocation { } self.parents = final_parent_count; - for j in prefix.interior.into_iter_rev() { + for j in prefix.interior.into_iter().rev() { self.push_front_interior(j).expect( "self junctions len + prefix parent count + prepend len is less than max length; qed" ); @@ -515,30 +515,42 @@ impl Iterator for JunctionsIterator { } } -pub struct JunctionsReverseIterator(Junctions); -impl Iterator for JunctionsReverseIterator { - type Item = Junction; - fn next(&mut self) -> Option<Junction> { +impl DoubleEndedIterator for JunctionsIterator { + fn next_back(&mut self) -> Option<Junction> { self.0.take_last() } } -pub struct JunctionsRefIterator<'a>(&'a Junctions, usize); +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 JunctionsReverseRefIterator<'a>(&'a Junctions, usize); -impl<'a> Iterator for JunctionsReverseRefIterator<'a> { - type Item = &'a Junction; - fn next(&mut self) -> Option<&'a Junction> { - self.1 += 1; - self.0.at(self.0.len().checked_sub(self.1)?) +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) } } @@ -546,7 +558,11 @@ impl<'a> IntoIterator for &'a Junctions { type Item = &'a Junction; type IntoIter = JunctionsRefIterator<'a>; fn into_iter(self) -> Self::IntoIter { - JunctionsRefIterator(self, 0) + JunctionsRefIterator { + junctions: self, + next: 0, + back: 0, + } } } @@ -775,17 +791,21 @@ impl Junctions { /// Returns a reference iterator over the junctions. pub fn iter(&self) -> JunctionsRefIterator { - JunctionsRefIterator(&self, 0) + JunctionsRefIterator { + junctions: self, + next: 0, + back: 0, + } } /// Returns a reference iterator over the junctions in reverse. - pub fn iter_rev(&self) -> JunctionsReverseRefIterator { - JunctionsReverseRefIterator(&self, 0) + 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) -> JunctionsReverseIterator { - JunctionsReverseIterator(self) + 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. @@ -1155,4 +1175,35 @@ mod tests { assert_eq!(m.prepend_with(prefix), Ok(())); assert_eq!(m, MultiLocation { parents: 254, interior: X1(Parachain(42)) }); } + + #[test] + 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 = Null + .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 = Null; + let mut iter = m.iter(); + + assert_eq!(iter.next(), None); + assert_eq!(iter.next_back(), None); + } } From e9128b928435162573b0e3ad0af8b7208eb80c0b Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Sat, 7 Aug 2021 04:50:11 -0700 Subject: [PATCH 112/166] Fix iter_rev lifetime requirements --- xcm/src/v1/multilocation.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xcm/src/v1/multilocation.rs b/xcm/src/v1/multilocation.rs index f1845ba3bcef..685619fd21b6 100644 --- a/xcm/src/v1/multilocation.rs +++ b/xcm/src/v1/multilocation.rs @@ -799,7 +799,7 @@ impl Junctions { } /// Returns a reference iterator over the junctions in reverse. - pub fn iter_rev(&self) -> impl Iterator { + pub fn iter_rev(&self) -> impl Iterator + '_ { self.iter().rev() } From 56cca551e2c00c3e38077aed30b44c6d92a3b5a1 Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Sat, 7 Aug 2021 05:03:32 -0700 Subject: [PATCH 113/166] Cargo fmt --- xcm/src/v1/multilocation.rs | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/xcm/src/v1/multilocation.rs b/xcm/src/v1/multilocation.rs index 685619fd21b6..7a42fef321be 100644 --- a/xcm/src/v1/multilocation.rs +++ b/xcm/src/v1/multilocation.rs @@ -558,11 +558,7 @@ impl<'a> IntoIterator for &'a Junctions { type Item = &'a Junction; type IntoIter = JunctionsRefIterator<'a>; fn into_iter(self) -> Self::IntoIter { - JunctionsRefIterator { - junctions: self, - next: 0, - back: 0, - } + JunctionsRefIterator { junctions: self, next: 0, back: 0 } } } @@ -791,11 +787,7 @@ impl Junctions { /// Returns a reference iterator over the junctions. pub fn iter(&self) -> JunctionsRefIterator { - JunctionsRefIterator { - junctions: self, - next: 0, - back: 0, - } + JunctionsRefIterator { junctions: self, next: 0, back: 0 } } /// Returns a reference iterator over the junctions in reverse. From 37262194fe081f716fe7a1fb9401f81659352dc7 Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Sat, 7 Aug 2021 05:15:00 -0700 Subject: [PATCH 114/166] Add an into() method for Junctions for conciseness in const context --- runtime/kusama/src/lib.rs | 2 +- runtime/rococo/src/lib.rs | 16 ++++++++-------- runtime/westend/src/lib.rs | 2 +- xcm/src/v1/multilocation.rs | 14 ++++++++++++++ 4 files changed, 24 insertions(+), 10 deletions(-) diff --git a/runtime/kusama/src/lib.rs b/runtime/kusama/src/lib.rs index d56c07cc6348..d6365e355f30 100644 --- a/runtime/kusama/src/lib.rs +++ b/runtime/kusama/src/lib.rs @@ -1263,7 +1263,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(), MultiLocation::with_parachain_interior(1000)); + pub const KusamaForStatemint: (MultiAssetFilter, MultiLocation) = (Kusama::get(), X1(Parachain(1000)).into()); } pub type TrustedTeleporters = (xcm_builder::Case<KusamaForStatemint>,); diff --git a/runtime/rococo/src/lib.rs b/runtime/rococo/src/lib.rs index 981bd3e28a56..bee3180a9187 100644 --- a/runtime/rococo/src/lib.rs +++ b/runtime/rococo/src/lib.rs @@ -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(), MultiLocation::with_parachain_interior(100)); - pub const RococoForTrick: (MultiAssetFilter, MultiLocation) = (Rococo::get(), MultiLocation::with_parachain_interior(110)); - pub const RococoForTrack: (MultiAssetFilter, MultiLocation) = (Rococo::get(), MultiLocation::with_parachain_interior(120)); - pub const RococoForStatemint: (MultiAssetFilter, MultiLocation) = (Rococo::get(), MultiLocation::with_parachain_interior(1001)); + pub const RococoForTick: (MultiAssetFilter, MultiLocation) = (Rococo::get(), X1(Parachain(100)).into()); + pub const RococoForTrick: (MultiAssetFilter, MultiLocation) = (Rococo::get(), X1(Parachain(110)).into()); + pub const RococoForTrack: (MultiAssetFilter, MultiLocation) = (Rococo::get(), X1(Parachain(120)).into()); + pub const RococoForStatemint: (MultiAssetFilter, MultiLocation) = (Rococo::get(), X1(Parachain(1001)).into()); } pub type TrustedTeleporters = ( xcm_builder::Case<RococoForTick>, @@ -640,10 +640,10 @@ pub type TrustedTeleporters = ( parameter_types! { pub AllowUnpaidFrom: Vec<MultiLocation> = vec![ - MultiLocation::with_parachain_interior(100), - MultiLocation::with_parachain_interior(110), - MultiLocation::with_parachain_interior(120), - MultiLocation::with_parachain_interior(1001), + X1(Parachain(100)).into(), + X1(Parachain(110)).into(), + X1(Parachain(120)).into(), + X1(Parachain(1001)).into(), ]; } diff --git a/runtime/westend/src/lib.rs b/runtime/westend/src/lib.rs index b08de96b23c1..4ac81ad02b03 100644 --- a/runtime/westend/src/lib.rs +++ b/runtime/westend/src/lib.rs @@ -908,7 +908,7 @@ pub type XcmRouter = ( parameter_types! { pub const WestendForWestmint: (MultiAssetFilter, MultiLocation) = - (Wild(AllOf { fun: WildFungible, id: Concrete(WndLocation::get()) }), MultiLocation::with_parachain_interior(1000)); + (Wild(AllOf { fun: WildFungible, id: Concrete(WndLocation::get()) }), X1(Parachain(1000)).into()); } pub type TrustedTeleporters = (xcm_builder::Case<WestendForWestmint>,); diff --git a/xcm/src/v1/multilocation.rs b/xcm/src/v1/multilocation.rs index 7a42fef321be..1434ec56f9a3 100644 --- a/xcm/src/v1/multilocation.rs +++ b/xcm/src/v1/multilocation.rs @@ -571,6 +571,20 @@ impl IntoIterator for Junctions { } impl Junctions { + /// Convert `self` into a MultiLocation containing 0 parents. + /// + /// Similar to `Into::into`, except that this method can be used in a const eval context. + pub const fn into(self) -> MultiLocation { + self.into_with_parents(0) + } + + /// 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_with_parents(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 { From 955b9e4289836769aaecefb751a89f7434490e1b Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Sat, 7 Aug 2021 05:21:59 -0700 Subject: [PATCH 115/166] Ensure parent count is 0 while executing who in RelayedFrom --- xcm/xcm-executor/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/xcm/xcm-executor/src/lib.rs b/xcm/xcm-executor/src/lib.rs index 4eb8a7b95314..13987461388c 100644 --- a/xcm/xcm-executor/src/lib.rs +++ b/xcm/xcm-executor/src/lib.rs @@ -234,6 +234,7 @@ impl<Config: config::Config> XcmExecutor<Config> { None }, (origin, Xcm::RelayedFrom { who, message }) => { + ensure!(who.parent_count() == 0, XcmError::EscalationOfPrivilege); let mut origin = origin; origin.append_with(who).map_err(|_| XcmError::MultiLocationFull)?; let surplus = From da521d673189d3bd418c33e9e5f41bf066bbaa22 Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Sat, 7 Aug 2021 05:24:43 -0700 Subject: [PATCH 116/166] Appease spellchecker --- xcm/src/v1/multilocation.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/xcm/src/v1/multilocation.rs b/xcm/src/v1/multilocation.rs index 1434ec56f9a3..87894d5f8036 100644 --- a/xcm/src/v1/multilocation.rs +++ b/xcm/src/v1/multilocation.rs @@ -571,14 +571,14 @@ impl IntoIterator for Junctions { } impl Junctions { - /// Convert `self` into a MultiLocation containing 0 parents. + /// Convert `self` into a `MultiLocation` containing 0 parents. /// - /// Similar to `Into::into`, except that this method can be used in a const eval context. + /// Similar to `Into::into`, except that this method can be used in a const evaluation context. pub const fn into(self) -> MultiLocation { self.into_with_parents(0) } - /// Convert `self` into a MultiLocation containing `n` parents. + /// 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_with_parents(self, n: u8) -> MultiLocation { From a3b84f0f4469f4304709ec6f729fced0ec65c9ef Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Sat, 7 Aug 2021 05:34:13 -0700 Subject: [PATCH 117/166] Use and_then instead of repeated map_err --- xcm/src/v0/multi_location.rs | 84 ++++++++++++------------------------ 1 file changed, 28 insertions(+), 56 deletions(-) diff --git a/xcm/src/v0/multi_location.rs b/xcm/src/v0/multi_location.rs index 9a63910fd128..b056e557b5d9 100644 --- a/xcm/src/v0/multi_location.rs +++ b/xcm/src/v0/multi_location.rs @@ -711,80 +711,52 @@ impl TryFrom<MultiLocation1> for MultiLocation { X1(j0) => res.pushed_with(j0.into()).map_err(|_| ()), X2(j0, j1) => res .pushed_with(j0.into()) - .map_err(|_| ())? - .pushed_with(j1.into()) + .and_then(|res| res.pushed_with(j1.into())) .map_err(|_| ()), X3(j0, j1, j2) => res .pushed_with(j0.into()) - .map_err(|_| ())? - .pushed_with(j1.into()) - .map_err(|_| ())? - .pushed_with(j2.into()) + .and_then(|res| res.pushed_with(j1.into())) + .and_then(|res| res.pushed_with(j2.into())) .map_err(|_| ()), X4(j0, j1, j2, j3) => res .pushed_with(j0.into()) - .map_err(|_| ())? - .pushed_with(j1.into()) - .map_err(|_| ())? - .pushed_with(j2.into()) - .map_err(|_| ())? - .pushed_with(j3.into()) + .and_then(|res| res.pushed_with(j1.into())) + .and_then(|res| res.pushed_with(j2.into())) + .and_then(|res| res.pushed_with(j3.into())) .map_err(|_| ()), X5(j0, j1, j2, j3, j4) => res .pushed_with(j0.into()) - .map_err(|_| ())? - .pushed_with(j1.into()) - .map_err(|_| ())? - .pushed_with(j2.into()) - .map_err(|_| ())? - .pushed_with(j3.into()) - .map_err(|_| ())? - .pushed_with(j4.into()) + .and_then(|res| res.pushed_with(j1.into())) + .and_then(|res| res.pushed_with(j2.into())) + .and_then(|res| res.pushed_with(j3.into())) + .and_then(|res| res.pushed_with(j4.into())) .map_err(|_| ()), X6(j0, j1, j2, j3, j4, j5) => res .pushed_with(j0.into()) - .map_err(|_| ())? - .pushed_with(j1.into()) - .map_err(|_| ())? - .pushed_with(j2.into()) - .map_err(|_| ())? - .pushed_with(j3.into()) - .map_err(|_| ())? - .pushed_with(j4.into()) - .map_err(|_| ())? - .pushed_with(j5.into()) + .and_then(|res| res.pushed_with(j1.into())) + .and_then(|res| res.pushed_with(j2.into())) + .and_then(|res| res.pushed_with(j3.into())) + .and_then(|res| res.pushed_with(j4.into())) + .and_then(|res| res.pushed_with(j5.into())) .map_err(|_| ()), X7(j0, j1, j2, j3, j4, j5, j6) => res .pushed_with(j0.into()) - .map_err(|_| ())? - .pushed_with(j1.into()) - .map_err(|_| ())? - .pushed_with(j2.into()) - .map_err(|_| ())? - .pushed_with(j3.into()) - .map_err(|_| ())? - .pushed_with(j4.into()) - .map_err(|_| ())? - .pushed_with(j5.into()) - .map_err(|_| ())? - .pushed_with(j6.into()) + .and_then(|res| res.pushed_with(j1.into())) + .and_then(|res| res.pushed_with(j2.into())) + .and_then(|res| res.pushed_with(j3.into())) + .and_then(|res| res.pushed_with(j4.into())) + .and_then(|res| res.pushed_with(j5.into())) + .and_then(|res| res.pushed_with(j6.into())) .map_err(|_| ()), X8(j0, j1, j2, j3, j4, j5, j6, j7) => res .pushed_with(j0.into()) - .map_err(|_| ())? - .pushed_with(j1.into()) - .map_err(|_| ())? - .pushed_with(j2.into()) - .map_err(|_| ())? - .pushed_with(j3.into()) - .map_err(|_| ())? - .pushed_with(j4.into()) - .map_err(|_| ())? - .pushed_with(j5.into()) - .map_err(|_| ())? - .pushed_with(j6.into()) - .map_err(|_| ())? - .pushed_with(j7.into()) + .and_then(|res| res.pushed_with(j1.into())) + .and_then(|res| res.pushed_with(j2.into())) + .and_then(|res| res.pushed_with(j3.into())) + .and_then(|res| res.pushed_with(j4.into())) + .and_then(|res| res.pushed_with(j5.into())) + .and_then(|res| res.pushed_with(j6.into())) + .and_then(|res| res.pushed_with(j7.into())) .map_err(|_| ()), } } From e0dcb8489c291dc521c3511eafeb0bdbb32543a3 Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Sat, 7 Aug 2021 05:35:40 -0700 Subject: [PATCH 118/166] Remove custom codec indices for v1 Junctions --- xcm/src/v1/junction.rs | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/xcm/src/v1/junction.rs b/xcm/src/v1/junction.rs index 828e2a6ed4c1..34ad0f22a64a 100644 --- a/xcm/src/v1/junction.rs +++ b/xcm/src/v1/junction.rs @@ -118,29 +118,21 @@ impl BodyPart { /// 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. -/// -/// NOTE: The codec index starts at 1, because a previous iteration of `Junction` has a `Parent` -/// variant occupying index 0. We deprecate `Junction::Parent` now by having a custom -/// Encode/Decode implementation for `MultiLocation`. Refer to [`MultiLocation`] for more -/// details. #[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. - #[codec(index = 1)] 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. - #[codec(index = 2)] 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. - #[codec(index = 3)] AccountIndex64 { network: NetworkId, #[codec(compact)] @@ -150,19 +142,16 @@ pub enum Junction { /// the context. /// /// May be used when the context is an Ethereum or Bitcoin chain or smart-contract. - #[codec(index = 4)] 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. - #[codec(index = 5)] 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. - #[codec(index = 6)] GeneralIndex { #[codec(compact)] id: u128, @@ -172,18 +161,15 @@ pub enum Junction { /// Usage will vary widely owing to its generality. /// /// NOTE: Try to avoid using this and instead use a more specific item. - #[codec(index = 7)] GeneralKey(Vec<u8>), /// The unambiguous child. /// /// Not currently used except as a fallback when deriving ancestry. - #[codec(index = 8)] 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. - #[codec(index = 9)] Plurality { id: BodyId, part: BodyPart }, } From a3459883db99fa975148fbc1208c46875af72bd6 Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Sat, 7 Aug 2021 05:43:24 -0700 Subject: [PATCH 119/166] Add convenience 'contains_parents_only' method to MultiLocation --- xcm/src/v1/multilocation.rs | 6 ++++++ xcm/xcm-builder/src/origin_conversion.rs | 5 +---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/xcm/src/v1/multilocation.rs b/xcm/src/v1/multilocation.rs index 87894d5f8036..04bbe4c5b652 100644 --- a/xcm/src/v1/multilocation.rs +++ b/xcm/src/v1/multilocation.rs @@ -117,6 +117,12 @@ impl MultiLocation { 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::Null) && 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() diff --git a/xcm/xcm-builder/src/origin_conversion.rs b/xcm/xcm-builder/src/origin_conversion.rs index 9db44e87d78a..7d724f0e54b8 100644 --- a/xcm/xcm-builder/src/origin_conversion.rs +++ b/xcm/xcm-builder/src/origin_conversion.rs @@ -45,10 +45,7 @@ where pub struct ParentAsSuperuser<Origin>(PhantomData<Origin>); impl<Origin: OriginTrait> ConvertOrigin<Origin> for ParentAsSuperuser<Origin> { fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result<Origin, MultiLocation> { - if kind == OriginKind::Superuser && - origin.parent_count() == 1 && - origin.interior().len() == 0 - { + if kind == OriginKind::Superuser && origin.contains_parents_only(1) { Ok(Origin::root()) } else { Err(origin) From bdbbd8f6862efee916c465c72f56901804d0ff1f Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Sat, 7 Aug 2021 06:02:15 -0700 Subject: [PATCH 120/166] Fix merge conflict --- xcm/xcm-simulator/example/src/lib.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/xcm/xcm-simulator/example/src/lib.rs b/xcm/xcm-simulator/example/src/lib.rs index 8d87512cc636..d1c0dabf1b35 100644 --- a/xcm/xcm-simulator/example/src/lib.rs +++ b/xcm/xcm-simulator/example/src/lib.rs @@ -190,15 +190,9 @@ mod tests { Relay::execute_with(|| { assert_ok!(RelayChainPalletXcm::reserve_transfer_assets( relay_chain::Origin::signed(ALICE), -<<<<<<< HEAD - X1(Parachain(1)).into(), - X1(AccountId32 { network: Any, id: ALICE.into() }).into(), + Box::new(X1(Parachain(1)).into()), + Box::new(X1(AccountId32 { network: Any, id: ALICE.into() }).into()), (MultiLocation::here(), 123).into(), -======= - Box::new(X1(Parachain(1))), - Box::new(X1(AccountId32 { network: Any, id: ALICE.into() })), - (Here, 123).into(), ->>>>>>> origin/master 0, 3, )); From a1489cb54015b3193a559098e91d3f644b648cb5 Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Sat, 7 Aug 2021 06:03:29 -0700 Subject: [PATCH 121/166] Use more convenience methods --- xcm/xcm-builder/src/location_conversion.rs | 6 +++--- xcm/xcm-builder/src/origin_conversion.rs | 3 +-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/xcm/xcm-builder/src/location_conversion.rs b/xcm/xcm-builder/src/location_conversion.rs index 7cf1063d29fa..65c46264102c 100644 --- a/xcm/xcm-builder/src/location_conversion.rs +++ b/xcm/xcm-builder/src/location_conversion.rs @@ -42,7 +42,7 @@ impl<AccountId: Default + Eq + Clone> Convert<MultiLocation, AccountId> for ParentIsDefault<AccountId> { fn convert_ref(location: impl Borrow<MultiLocation>) -> Result<AccountId, ()> { - if location.borrow().parent_count() == 1 && location.borrow().interior().len() == 0 { + if location.borrow().contains_parents_only(1) { Ok(AccountId::default()) } else { Err(()) @@ -248,7 +248,7 @@ mod tests { pub Ancestry: MultiLocation = X2(account20(), account20()).into(); } - let input = MultiLocation::new(2, Null).unwrap(); + let input = MultiLocation::with_parents::<2>(); let inverted = LocationInverter::<Ancestry>::invert_location(&input); assert_eq!(inverted, X2(account20(), account20()).into()); } @@ -263,7 +263,7 @@ mod tests { pub Ancestry: MultiLocation = X1(PalletInstance(5)).into(); } - let input = MultiLocation::new(2, Null).unwrap(); + let input = MultiLocation::with_parents::<2>(); let inverted = LocationInverter::<Ancestry>::invert_location(&input); assert_eq!(inverted, X2(PalletInstance(5), OnlyChild).into()); } diff --git a/xcm/xcm-builder/src/origin_conversion.rs b/xcm/xcm-builder/src/origin_conversion.rs index 7d724f0e54b8..a31d0f0ad115 100644 --- a/xcm/xcm-builder/src/origin_conversion.rs +++ b/xcm/xcm-builder/src/origin_conversion.rs @@ -116,8 +116,7 @@ impl<RelayOrigin: Get<Origin>, Origin> ConvertOrigin<Origin> for RelayChainAsNative<RelayOrigin, Origin> { fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result<Origin, MultiLocation> { - if kind == OriginKind::Native && origin.parent_count() == 1 && origin.interior().len() == 0 - { + if kind == OriginKind::Native && origin.contains_parents_only(1) { Ok(RelayOrigin::get()) } else { Err(origin) From e6e4509f8ba2ed475c9f3d00be81aa9203ed05c0 Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Sat, 7 Aug 2021 06:11:03 -0700 Subject: [PATCH 122/166] Remove with_parachain_interior --- xcm/pallet-xcm/src/lib.rs | 2 +- xcm/src/v1/multilocation.rs | 9 --------- xcm/xcm-builder/src/tests.rs | 4 ++-- 3 files changed, 3 insertions(+), 12 deletions(-) diff --git a/xcm/pallet-xcm/src/lib.rs b/xcm/pallet-xcm/src/lib.rs index 9ccce1cde797..1d7c4650833a 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, diff --git a/xcm/src/v1/multilocation.rs b/xcm/src/v1/multilocation.rs index 04bbe4c5b652..c870f017e5a8 100644 --- a/xcm/src/v1/multilocation.rs +++ b/xcm/src/v1/multilocation.rs @@ -88,15 +88,6 @@ impl MultiLocation { MultiLocation { parents: P, interior: Junctions::Null } } - /// Creates a new `MultiLocation` with no parents and a single `Parachain` interior junction - /// specified by `para_id`. - /// - /// The resulting `MultiLocation` can be interpreted as the child-parachain of the current - /// consensus system. - pub const fn with_parachain_interior(para_id: u32) -> MultiLocation { - MultiLocation { parents: 0, interior: Junctions::X1(Junction::Parachain(para_id)) } - } - /// Whether or not the `MultiLocation` has no parents and has a `Null` interior. pub const fn is_here(&self) -> bool { self.parents == 0 && self.interior.len() == 0 diff --git a/xcm/xcm-builder/src/tests.rs b/xcm/xcm-builder/src/tests.rs index 0d6ddb4d5331..8bbdcf386023 100644 --- a/xcm/xcm-builder/src/tests.rs +++ b/xcm/xcm-builder/src/tests.rs @@ -29,8 +29,8 @@ fn basic_setup_works() { &MultiLocation::with_parents::<1>(), )); - assert_eq!(to_account(MultiLocation::with_parachain_interior(1)), Ok(1001)); - assert_eq!(to_account(MultiLocation::with_parachain_interior(50)), Ok(1050)); + 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))).unwrap()), Ok(2001)); assert_eq!(to_account(MultiLocation::new(1, X1(Parachain(50))).unwrap()), Ok(2050)); assert_eq!( From 139b8b158c1149a9e7f9bc3a9a97e11460adf433 Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Sat, 7 Aug 2021 06:14:26 -0700 Subject: [PATCH 123/166] Prefer matching against tuple instead of using match guards --- xcm/xcm-builder/src/location_conversion.rs | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/xcm/xcm-builder/src/location_conversion.rs b/xcm/xcm-builder/src/location_conversion.rs index 65c46264102c..bab5ee615e41 100644 --- a/xcm/xcm-builder/src/location_conversion.rs +++ b/xcm/xcm-builder/src/location_conversion.rs @@ -109,12 +109,10 @@ impl<Network: Get<NetworkId>, AccountId: From<[u8; 32]> + Into<[u8; 32]> + Clone Convert<MultiLocation, AccountId> for AccountId32Aliases<Network, AccountId> { fn convert(location: MultiLocation) -> Result<AccountId, MultiLocation> { - let id = match location.interior() { - Junctions::X1(Junction::AccountId32 { id, network: NetworkId::Any }) - if location.parent_count() == 0 => - *id, - Junctions::X1(Junction::AccountId32 { id, network }) - if network == &Network::get() && location.parent_count() == 0 => + let id = match (location.parent_count(), location.interior()) { + (0, Junctions::X1(Junction::AccountId32 { id, network: NetworkId::Any })) => *id, + (0, Junctions::X1(Junction::AccountId32 { id, network })) + if network == &Network::get() => *id, _ => return Err(location), }; @@ -131,12 +129,10 @@ impl<Network: Get<NetworkId>, AccountId: From<[u8; 20]> + Into<[u8; 20]> + Clone Convert<MultiLocation, AccountId> for AccountKey20Aliases<Network, AccountId> { fn convert(location: MultiLocation) -> Result<AccountId, MultiLocation> { - let key = match location.interior() { - Junctions::X1(Junction::AccountKey20 { key, network: NetworkId::Any }) - if location.parent_count() == 0 => - *key, - Junctions::X1(Junction::AccountKey20 { key, network }) - if network == &Network::get() && location.parent_count() == 0 => + let key = match (location.parent_count(), location.interior()) { + (0, Junctions::X1(Junction::AccountKey20 { key, network: NetworkId::Any })) => *key, + (0, Junctions::X1(Junction::AccountKey20 { key, network })) + if network == &Network::get() => *key, _ => return Err(location), }; From 2b8a97d72dbf45426d587953149aca7ae027b255 Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Sat, 7 Aug 2021 06:20:49 -0700 Subject: [PATCH 124/166] Match against tuple instead of using more match guards --- xcm/xcm-builder/src/origin_conversion.rs | 35 +++++++++++------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/xcm/xcm-builder/src/origin_conversion.rs b/xcm/xcm-builder/src/origin_conversion.rs index a31d0f0ad115..dc01e9efde1c 100644 --- a/xcm/xcm-builder/src/origin_conversion.rs +++ b/xcm/xcm-builder/src/origin_conversion.rs @@ -58,9 +58,9 @@ impl<ParaId: IsSystem + From<u32>, Origin: OriginTrait> ConvertOrigin<Origin> for ChildSystemParachainAsSuperuser<ParaId, Origin> { fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result<Origin, MultiLocation> { - match (kind, origin.interior()) { - (OriginKind::Superuser, Junctions::X1(Junction::Parachain(id))) - if ParaId::from(*id).is_system() && origin.parent_count() == 0 => + match (kind, origin.parent_count(), origin.interior()) { + (OriginKind::Superuser, 0, Junctions::X1(Junction::Parachain(id))) + if ParaId::from(*id).is_system() => Ok(Origin::root()), _ => Err(origin), } @@ -72,9 +72,9 @@ impl<ParaId: IsSystem + From<u32>, Origin: OriginTrait> ConvertOrigin<Origin> for SiblingSystemParachainAsSuperuser<ParaId, Origin> { fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result<Origin, MultiLocation> { - match (kind, origin.interior()) { - (OriginKind::Superuser, Junctions::X1(Junction::Parachain(id))) - if ParaId::from(*id).is_system() && origin.parent_count() == 1 => + match (kind, origin.parent_count(), origin.interior()) { + (OriginKind::Superuser, 1, Junctions::X1(Junction::Parachain(id))) + if ParaId::from(*id).is_system() => Ok(Origin::root()), _ => Err(origin), } @@ -86,8 +86,8 @@ impl<ParachainOrigin: From<u32>, Origin: From<ParachainOrigin>> ConvertOrigin<Or for ChildParachainAsNative<ParachainOrigin, Origin> { fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result<Origin, MultiLocation> { - match (kind, origin.interior()) { - (OriginKind::Native, Junctions::X1(Junction::Parachain(id))) => + match (kind, origin.parent_count(), origin.interior()) { + (OriginKind::Native, 0, Junctions::X1(Junction::Parachain(id))) => Ok(Origin::from(ParachainOrigin::from(*id))), _ => Err(origin), } @@ -101,9 +101,8 @@ impl<ParachainOrigin: From<u32>, Origin: From<ParachainOrigin>> ConvertOrigin<Or for SiblingParachainAsNative<ParachainOrigin, Origin> { fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result<Origin, MultiLocation> { - match (kind, origin.interior()) { - (OriginKind::Native, Junctions::X1(Junction::Parachain(id))) - if origin.parent_count() == 1 => + match (kind, origin.parent_count(), origin.interior()) { + (OriginKind::Native, 1, Junctions::X1(Junction::Parachain(id))) => Ok(Origin::from(ParachainOrigin::from(*id))), _ => Err(origin), } @@ -131,10 +130,9 @@ where Origin::AccountId: From<[u8; 32]>, { fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result<Origin, MultiLocation> { - match (kind, origin.interior()) { - (OriginKind::Native, Junctions::X1(Junction::AccountId32 { id, network })) - if (matches!(network, NetworkId::Any) || network == &Network::get()) && - origin.parent_count() == 0 => + match (kind, origin.parent_count(), origin.interior()) { + (OriginKind::Native, 0, Junctions::X1(Junction::AccountId32 { id, network })) + if matches!(network, NetworkId::Any) || network == &Network::get() => Ok(Origin::signed((*id).into())), _ => Err(origin), } @@ -148,10 +146,9 @@ where Origin::AccountId: From<[u8; 20]>, { fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result<Origin, MultiLocation> { - match (kind, origin.interior()) { - (OriginKind::Native, Junctions::X1(Junction::AccountKey20 { key, network })) - if (matches!(network, NetworkId::Any) || network == &Network::get()) && - origin.parent_count() == 0 => + match (kind, origin.parent_count(), origin.interior()) { + (OriginKind::Native, 0, Junctions::X1(Junction::AccountKey20 { key, network })) + if (matches!(network, NetworkId::Any) || network == &Network::get()) => Ok(Origin::signed((*key).into())), _ => Err(origin), } From db5c466fc70f5e6120af9faac85df9c893b4999c Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Sat, 7 Aug 2021 07:26:21 -0700 Subject: [PATCH 125/166] Update encode/decode test for MultiLocation --- xcm/src/v1/multilocation.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xcm/src/v1/multilocation.rs b/xcm/src/v1/multilocation.rs index c870f017e5a8..1ac29cc56c2d 100644 --- a/xcm/src/v1/multilocation.rs +++ b/xcm/src/v1/multilocation.rs @@ -1115,7 +1115,7 @@ mod tests { interior: X2(Parachain(42), AccountIndex64 { network: Any, index: 23 }), }; let encoded = m.encode(); - assert_eq!(encoded, [1, 2, 1, 168, 3, 0, 92].to_vec()); + assert_eq!(encoded, [1, 2, 0, 168, 2, 0, 92].to_vec()); let decoded = MultiLocation::decode(&mut &encoded[..]); assert_eq!(decoded, Ok(m)); } From c3f372db40bb29bd0502115615a1723f1b7802b9 Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Sat, 7 Aug 2021 21:47:03 +0200 Subject: [PATCH 126/166] Minor tweaks --- runtime/kusama/src/lib.rs | 6 ++-- runtime/rococo/src/lib.rs | 20 ++++++------- runtime/westend/src/lib.rs | 6 ++-- xcm/pallet-xcm/src/lib.rs | 2 +- xcm/pallet-xcm/src/mock.rs | 4 +-- xcm/pallet-xcm/src/tests.rs | 12 ++++---- xcm/src/v1/junction.rs | 24 +++++++++++---- xcm/src/v1/multilocation.rs | 8 ++--- xcm/xcm-builder/src/mock.rs | 2 +- xcm/xcm-builder/src/origin_conversion.rs | 2 +- xcm/xcm-builder/src/tests.rs | 30 +++++++++---------- xcm/xcm-executor/src/assets.rs | 18 +++++------ xcm/xcm-executor/src/traits/transact_asset.rs | 16 +++++----- xcm/xcm-simulator/example/src/lib.rs | 8 ++--- xcm/xcm-simulator/example/src/relay_chain.rs | 4 +-- 15 files changed, 88 insertions(+), 74 deletions(-) diff --git a/runtime/kusama/src/lib.rs b/runtime/kusama/src/lib.rs index d6365e355f30..23b4d5543145 100644 --- a/runtime/kusama/src/lib.rs +++ b/runtime/kusama/src/lib.rs @@ -1201,12 +1201,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(); } @@ -1263,7 +1263,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)).into()); + pub const KusamaForStatemint: (MultiAssetFilter, MultiLocation) = (Kusama::get(), Parachain(1000).into()); } pub type TrustedTeleporters = (xcm_builder::Case<KusamaForStatemint>,); diff --git a/runtime/rococo/src/lib.rs b/runtime/rococo/src/lib.rs index bee3180a9187..2c8eecbaac17 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)).into()); - pub const RococoForTrick: (MultiAssetFilter, MultiLocation) = (Rococo::get(), X1(Parachain(110)).into()); - pub const RococoForTrack: (MultiAssetFilter, MultiLocation) = (Rococo::get(), X1(Parachain(120)).into()); - pub const RococoForStatemint: (MultiAssetFilter, MultiLocation) = (Rococo::get(), X1(Parachain(1001)).into()); + 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<RococoForTick>, @@ -640,10 +640,10 @@ pub type TrustedTeleporters = ( parameter_types! { pub AllowUnpaidFrom: Vec<MultiLocation> = vec![ - X1(Parachain(100)).into(), - X1(Parachain(110)).into(), - X1(Parachain(120)).into(), - X1(Parachain(1001)).into(), + Parachain(100).into(), + Parachain(110).into(), + Parachain(120).into(), + Parachain(1001).into(), ]; } diff --git a/runtime/westend/src/lib.rs b/runtime/westend/src/lib.rs index 4ac81ad02b03..52c601beeffc 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)).into()); + (Wild(AllOf { fun: WildFungible, id: Concrete(WndLocation::get()) }), Parachain(1000).into()); } pub type TrustedTeleporters = (xcm_builder::Case<WestendForWestmint>,); diff --git a/xcm/pallet-xcm/src/lib.rs b/xcm/pallet-xcm/src/lib.rs index 1d7c4650833a..824b652227f3 100644 --- a/xcm/pallet-xcm/src/lib.rs +++ b/xcm/pallet-xcm/src/lib.rs @@ -385,7 +385,7 @@ where #[cfg(feature = "runtime-benchmarks")] fn successful_origin() -> O { - O::from(Origin::Xcm(MultiLocation::here())) + O::from(Origin::Xcm(Here.into())) } } diff --git a/xcm/pallet-xcm/src/mock.rs b/xcm/pallet-xcm/src/mock.rs index db41796af2a2..2ee2a8b3958b 100644 --- a/xcm/pallet-xcm/src/mock.rs +++ b/xcm/pallet-xcm/src/mock.rs @@ -133,9 +133,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 4ef1bf17fcdb..1ca2a2579133 100644 --- a/xcm/pallet-xcm/src/tests.rs +++ b/xcm/pallet-xcm/src/tests.rs @@ -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()) } )] ); @@ -109,8 +109,8 @@ 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() }).into()), - (MultiLocation::here(), SEND_AMOUNT).into(), + Box::new(AccountId32 { network: Any, id: BOB.into() }.into()), + (Here.into(), SEND_AMOUNT).into(), 0, weight, )); @@ -139,7 +139,7 @@ fn reserve_transfer_assets_works() { Origin::signed(ALICE), Box::new(Parachain(PARA_ID).into()), Box::new(dest.clone()), - (MultiLocation::here(), SEND_AMOUNT).into(), + (Here.into(), SEND_AMOUNT).into(), 0, weight )); @@ -184,9 +184,9 @@ fn execute_withdraw_to_deposit_works() { assert_ok!(XcmPallet::execute( Origin::signed(ALICE), Box::new(Xcm::WithdrawAsset { - assets: (MultiLocation::here(), SEND_AMOUNT).into(), + assets: (Here.into(), SEND_AMOUNT).into(), effects: vec![ - buy_execution((MultiLocation::here(), SEND_AMOUNT), weight), + buy_execution((Here.into(), SEND_AMOUNT), weight), DepositAsset { assets: All.into(), max_assets: 1, beneficiary: dest } ], }), diff --git a/xcm/src/v1/junction.rs b/xcm/src/v1/junction.rs index 34ad0f22a64a..ff820610dab8 100644 --- a/xcm/src/v1/junction.rs +++ b/xcm/src/v1/junction.rs @@ -20,6 +20,7 @@ use crate::v0::{BodyId as BodyId0, Junction as Junction0}; use alloc::vec::Vec; use core::convert::TryFrom; use parity_scale_codec::{self, Decode, Encode}; +use super::{MultiLocation, Junctions}; /// A global identifier of an account-bearing consensus system. #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug)] @@ -152,10 +153,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. @@ -185,10 +183,26 @@ impl TryFrom<Junction0> for Junction { 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::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/multilocation.rs b/xcm/src/v1/multilocation.rs index 1ac29cc56c2d..3481be4fdf99 100644 --- a/xcm/src/v1/multilocation.rs +++ b/xcm/src/v1/multilocation.rs @@ -485,7 +485,7 @@ impl From<[Junction; 8]> for MultiLocation { #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug)] pub enum Junctions { /// The interpreting consensus system. - Null, + Here, /// A relative path comprising 1 junction. X1(Junction), /// A relative path comprising 2 junctions. @@ -572,13 +572,13 @@ impl Junctions { /// /// Similar to `Into::into`, except that this method can be used in a const evaluation context. pub const fn into(self) -> MultiLocation { - self.into_with_parents(0) + 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_with_parents(self, n: u8) -> MultiLocation { + pub const fn into_exterior(self, n: u8) -> MultiLocation { MultiLocation { parents: n, interior: self } } @@ -852,7 +852,7 @@ impl TryFrom<MultiLocation0> for MultiLocation { fn try_from(old: MultiLocation0) -> result::Result<Self, ()> { use Junctions::*; match old { - MultiLocation0::Null => Ok(MultiLocation::here()), + MultiLocation0::Null => Ok(Here.into()), MultiLocation0::X1(j0) if j0.is_parent() => Ok(MultiLocation::with_parents::<1>()), MultiLocation0::X1(j0) => Ok(X1(j0.try_into()?).into()), MultiLocation0::X2(j0, j1) if j0.is_parent() && j1.is_parent() => diff --git a/xcm/xcm-builder/src/mock.rs b/xcm/xcm-builder/src/mock.rs index 84d514731664..e290241fcf48 100644 --- a/xcm/xcm-builder/src/mock.rs +++ b/xcm/xcm-builder/src/mock.rs @@ -257,7 +257,7 @@ parameter_types! { pub static AllowUnpaidFrom: Vec<MultiLocation> = vec![]; pub static AllowPaidFrom: Vec<MultiLocation> = vec![]; // 1_000_000_000_000 => 1 unit of asset for 1 unit of Weight. - pub static WeightPrice: (AssetId, u128) = (MultiLocation::here().into(), 1_000_000_000_000); + pub static WeightPrice: (AssetId, u128) = (Here.into().into(), 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 dc01e9efde1c..f4dfaf65a693 100644 --- a/xcm/xcm-builder/src/origin_conversion.rs +++ b/xcm/xcm-builder/src/origin_conversion.rs @@ -171,7 +171,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 8bbdcf386023..fffcffaeb1e3 100644 --- a/xcm/xcm-builder/src/tests.rs +++ b/xcm/xcm-builder/src/tests.rs @@ -41,7 +41,7 @@ fn basic_setup_works() { to_account(MultiLocation::new(0, X1(AccountIndex64 { index: 42, network: Any })).unwrap()), Ok(42), ); - assert_eq!(to_account(MultiLocation::here()), Ok(3000)); + assert_eq!(to_account(Here.into()), Ok(3000)); } #[test] @@ -60,7 +60,7 @@ fn weigher_should_work() { Order::DepositAsset { assets: All.into(), max_assets: 1, - beneficiary: MultiLocation::here(), + beneficiary: Here.into(), }, ], } @@ -72,7 +72,7 @@ fn weigher_should_work() { fn take_weight_credit_barrier_should_work() { let mut message = opaque::Xcm::TransferAsset { assets: (MultiLocation::with_parents::<1>(), 100).into(), - beneficiary: MultiLocation::here(), + beneficiary: Here.into(), }; let mut weight_credit = 10; @@ -101,7 +101,7 @@ fn take_weight_credit_barrier_should_work() { fn allow_unpaid_should_work() { let mut message = opaque::Xcm::TransferAsset { assets: (MultiLocation::with_parents::<1>(), 100).into(), - beneficiary: MultiLocation::here(), + beneficiary: Here.into(), }; AllowUnpaidFrom::set(vec![MultiLocation::with_parents::<1>()]); @@ -131,7 +131,7 @@ fn allow_paid_should_work() { let mut message = opaque::Xcm::TransferAsset { assets: (MultiLocation::with_parents::<1>(), 100).into(), - beneficiary: MultiLocation::here(), + beneficiary: Here.into(), }; let r = AllowTopLevelPaidExecutionFrom::<IsInVec<AllowPaidFrom>>::should_execute( @@ -158,7 +158,7 @@ fn allow_paid_should_work() { Order::DepositAsset { assets: All.into(), max_assets: 1, - beneficiary: MultiLocation::here(), + beneficiary: Here.into(), }, ], }; @@ -187,7 +187,7 @@ fn allow_paid_should_work() { Order::DepositAsset { assets: All.into(), max_assets: 1, - beneficiary: MultiLocation::here(), + beneficiary: Here.into(), }, ], }; @@ -236,7 +236,7 @@ fn paying_reserve_deposit_should_work() { Order::<TestCall>::DepositAsset { assets: All.into(), max_assets: 1, - beneficiary: MultiLocation::here(), + beneficiary: Here.into(), }, ], }; @@ -251,19 +251,19 @@ fn transfer_should_work() { // we'll let them have message execution for free. AllowUnpaidFrom::set(vec![X1(Parachain(1)).into()]); // Child parachain #1 owns 1000 tokens held by us in reserve. - add_asset(1001, (MultiLocation::here(), 1000).into()); + add_asset(1001, (Here.into(), 1000).into()); // They want to transfer 100 of them to their sibling parachain #2 let r = XcmExecutor::<TestConfig>::execute_xcm( X1(Parachain(1)).into(), Xcm::TransferAsset { - assets: (MultiLocation::here(), 100).into(), + assets: (Here.into(), 100).into(), beneficiary: X1(AccountIndex64 { index: 3, network: Any }).into(), }, 50, ); assert_eq!(r, Outcome::Complete(10)); - assert_eq!(assets(3), vec![(MultiLocation::here(), 100).into()]); - assert_eq!(assets(1001), vec![(MultiLocation::here(), 900).into()]); + assert_eq!(assets(3), vec![(Here.into(), 100).into()]); + assert_eq!(assets(1001), vec![(Here.into(), 900).into()]); assert_eq!(sent_xcm(), vec![]); } @@ -271,7 +271,7 @@ fn transfer_should_work() { fn reserve_transfer_should_work() { AllowUnpaidFrom::set(vec![X1(Parachain(1)).into()]); // Child parachain #1 owns 1000 tokens held by us in reserve. - add_asset(1001, (MultiLocation::here(), 1000).into()); + add_asset(1001, (Here.into(), 1000).into()); // The remote account owned by gav. let three: MultiLocation = X1(AccountIndex64 { index: 3, network: Any }).into(); @@ -280,7 +280,7 @@ fn reserve_transfer_should_work() { let r = XcmExecutor::<TestConfig>::execute_xcm( X1(Parachain(1)).into(), Xcm::TransferReserveAsset { - assets: (MultiLocation::here(), 100).into(), + assets: (Here.into(), 100).into(), dest: X1(Parachain(2)).into(), effects: vec![Order::DepositAsset { assets: All.into(), @@ -292,7 +292,7 @@ fn reserve_transfer_should_work() { ); assert_eq!(r, Outcome::Complete(10)); - assert_eq!(assets(1002), vec![(MultiLocation::here(), 100).into()]); + assert_eq!(assets(1002), vec![(Here.into(), 100).into()]); assert_eq!( sent_xcm(), vec![( diff --git a/xcm/xcm-executor/src/assets.rs b/xcm/xcm-executor/src/assets.rs index b05664d8d45b..824f419c4f5c 100644 --- a/xcm/xcm-executor/src/assets.rs +++ b/xcm/xcm-executor/src/assets.rs @@ -381,12 +381,12 @@ impl Assets { /// ``` /// use xcm_executor::Assets; /// use xcm::latest::prelude::*; - /// let assets_i_have: Assets = vec![ (MultiLocation::here(), 100).into(), (vec![0], 100).into() ].into(); - /// let assets_they_want: MultiAssetFilter = vec![ (MultiLocation::here(), 200).into(), (vec![0], 50).into() ].into(); + /// let assets_i_have: Assets = vec![ (Here.into(), 100).into(), (vec![0], 100).into() ].into(); + /// let assets_they_want: MultiAssetFilter = vec![ (Here.into(), 200).into(), (vec![0], 50).into() ].into(); /// /// let assets_we_can_trade: Assets = assets_i_have.min(&assets_they_want); /// assert_eq!(assets_we_can_trade.into_assets_iter().collect::<Vec<_>>(), vec![ - /// (MultiLocation::here(), 100).into(), (vec![0], 50).into(), + /// (Here.into(), 100).into(), (vec![0], 50).into(), /// ]); /// ``` pub fn min(&self, mask: &MultiAssetFilter) -> Assets { @@ -443,12 +443,12 @@ mod tests { #[allow(non_snake_case)] /// Concrete fungible constructor fn CF(amount: u128) -> MultiAsset { - (MultiLocation::here(), amount).into() + (Here.into(), amount).into() } #[allow(non_snake_case)] /// Concrete non-fungible constructor fn CNF(instance_id: u8) -> MultiAsset { - (MultiLocation::here(), [instance_id; 4]).into() + (Here.into(), [instance_id; 4]).into() } fn test_assets() -> Assets { @@ -562,8 +562,8 @@ mod tests { #[test] fn min_all_concrete_works() { let assets = test_assets(); - let fungible = Wild((MultiLocation::here(), WildFungible).into()); - let non_fungible = Wild((MultiLocation::here(), WildNonFungible).into()); + let fungible = Wild((Here.into(), WildFungible).into()); + let non_fungible = Wild((Here.into(), WildNonFungible).into()); let fungible = assets.min(&fungible); let fungible = fungible.assets_iter().collect::<Vec<_>>(); @@ -626,8 +626,8 @@ mod tests { #[test] fn saturating_take_all_concrete_works() { let mut assets = test_assets(); - let fungible = Wild((MultiLocation::here(), WildFungible).into()); - let non_fungible = Wild((MultiLocation::here(), WildNonFungible).into()); + let fungible = Wild((Here.into(), WildFungible).into()); + let non_fungible = Wild((Here.into(), WildNonFungible).into()); let fungible = assets.saturating_take(fungible); let fungible = fungible.assets_iter().collect::<Vec<_>>(); diff --git a/xcm/xcm-executor/src/traits/transact_asset.rs b/xcm/xcm-executor/src/traits/transact_asset.rs index 608498fd2dd9..9f7adda568b5 100644 --- a/xcm/xcm-executor/src/traits/transact_asset.rs +++ b/xcm/xcm-executor/src/traits/transact_asset.rs @@ -273,8 +273,8 @@ mod tests { assert_eq!( MultiTransactor::deposit_asset( - &(MultiLocation::here(), 1).into(), - &MultiLocation::here() + &(Here.into(), 1).into(), + &Here.into() ), Err(XcmError::AssetNotFound) ); @@ -286,8 +286,8 @@ mod tests { assert_eq!( MultiTransactor::deposit_asset( - &(MultiLocation::here(), 1).into(), - &MultiLocation::here() + &(Here.into(), 1).into(), + &Here.into() ), Ok(()), ); @@ -299,8 +299,8 @@ mod tests { assert_eq!( MultiTransactor::deposit_asset( - &(MultiLocation::here(), 1).into(), - &MultiLocation::here() + &(Here.into(), 1).into(), + &Here.into() ), Err(XcmError::Overflow) ); @@ -312,8 +312,8 @@ mod tests { assert_eq!( MultiTransactor::deposit_asset( - &(MultiLocation::here(), 1).into(), - &MultiLocation::here() + &(Here.into(), 1).into(), + &Here.into() ), Ok(()), ); diff --git a/xcm/xcm-simulator/example/src/lib.rs b/xcm/xcm-simulator/example/src/lib.rs index d1c0dabf1b35..9bd86a60829d 100644 --- a/xcm/xcm-simulator/example/src/lib.rs +++ b/xcm/xcm-simulator/example/src/lib.rs @@ -111,7 +111,7 @@ mod tests { ); Relay::execute_with(|| { assert_ok!(RelayChainPalletXcm::send_xcm( - MultiLocation::here(), + Here.into(), X1(Parachain(1)).into(), Transact { origin_type: OriginKind::SovereignAccount, @@ -138,7 +138,7 @@ mod tests { ); ParaA::execute_with(|| { assert_ok!(ParachainPalletXcm::send_xcm( - MultiLocation::here(), + Here.into(), MultiLocation::with_parents::<1>(), Transact { origin_type: OriginKind::SovereignAccount, @@ -165,7 +165,7 @@ mod tests { ); ParaA::execute_with(|| { assert_ok!(ParachainPalletXcm::send_xcm( - MultiLocation::here(), + Here.into(), MultiLocation::new(1, X1(Parachain(2))).unwrap(), Transact { origin_type: OriginKind::SovereignAccount, @@ -192,7 +192,7 @@ mod tests { relay_chain::Origin::signed(ALICE), Box::new(X1(Parachain(1)).into()), Box::new(X1(AccountId32 { network: Any, id: ALICE.into() }).into()), - (MultiLocation::here(), 123).into(), + (Here.into(), 123).into(), 0, 3, )); diff --git a/xcm/xcm-simulator/example/src/relay_chain.rs b/xcm/xcm-simulator/example/src/relay_chain.rs index 1d447db741ff..76d528f4be64 100644 --- a/xcm/xcm-simulator/example/src/relay_chain.rs +++ b/xcm/xcm-simulator/example/src/relay_chain.rs @@ -91,10 +91,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; } From a6059965d00f17cdde638d99ecacfc36942e1ca9 Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Sat, 7 Aug 2021 22:14:57 +0200 Subject: [PATCH 127/166] Fixes --- xcm/pallet-xcm/src/tests.rs | 14 ++-- xcm/src/v0/junction.rs | 2 +- xcm/src/v0/multi_location.rs | 74 +++++++++---------- xcm/src/v1/multilocation.rs | 80 +++++++++++---------- xcm/src/v1/traits.rs | 4 +- xcm/xcm-builder/src/currency_adapter.rs | 2 +- xcm/xcm-builder/src/location_conversion.rs | 8 +-- xcm/xcm-builder/src/matches_fungible.rs | 4 +- xcm/xcm-builder/src/tests.rs | 84 +++++++++++----------- xcm/xcm-simulator/example/src/lib.rs | 2 +- xcm/xcm-simulator/example/src/parachain.rs | 6 +- xcm/xcm-simulator/src/lib.rs | 2 +- 12 files changed, 145 insertions(+), 137 deletions(-) diff --git a/xcm/pallet-xcm/src/tests.rs b/xcm/pallet-xcm/src/tests.rs index 1ca2a2579133..448bb71724cf 100644 --- a/xcm/pallet-xcm/src/tests.rs +++ b/xcm/pallet-xcm/src/tests.rs @@ -40,9 +40,9 @@ fn send_works() { let sender: MultiLocation = AccountId32 { network: AnyNetwork::get(), id: ALICE.into() }.into(); let message = Xcm::ReserveAssetDeposited { - assets: (MultiLocation::with_parents::<1>(), SEND_AMOUNT).into(), + assets: (MultiLocation::ancestor(1), SEND_AMOUNT).into(), effects: vec![ - buy_execution((MultiLocation::with_parents::<1>(), SEND_AMOUNT), weight), + buy_execution((MultiLocation::ancestor(1), SEND_AMOUNT), weight), DepositAsset { assets: All.into(), max_assets: 1, beneficiary: sender.clone() }, ], }; @@ -78,16 +78,16 @@ fn send_fails_when_xcm_router_blocks() { let sender: MultiLocation = Junction::AccountId32 { network: AnyNetwork::get(), id: ALICE.into() }.into(); let message = Xcm::ReserveAssetDeposited { - assets: (MultiLocation::with_parents::<1>(), SEND_AMOUNT).into(), + assets: (MultiLocation::ancestor(1), SEND_AMOUNT).into(), effects: vec![ - buy_execution((MultiLocation::with_parents::<1>(), SEND_AMOUNT), weight), + buy_execution((MultiLocation::ancestor(1), SEND_AMOUNT), weight), DepositAsset { assets: All.into(), max_assets: 1, beneficiary: sender.clone() }, ], }; assert_noop!( XcmPallet::send( Origin::signed(ALICE), - Box::new(MultiLocation::with_parents::<8>()), + Box::new(MultiLocation::ancestor(8)), Box::new(message.clone()) ), crate::Error::<Test>::SendFailure @@ -153,9 +153,9 @@ fn reserve_transfer_assets_works() { vec![( Parachain(PARA_ID).into(), Xcm::ReserveAssetDeposited { - assets: (MultiLocation::with_parents::<1>(), SEND_AMOUNT).into(), + assets: (MultiLocation::ancestor(1), SEND_AMOUNT).into(), effects: vec![ - buy_execution((MultiLocation::with_parents::<1>(), SEND_AMOUNT), weight), + buy_execution((MultiLocation::ancestor(1), 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 9ccc3424028c..cee1799081e5 100644 --- a/xcm/src/v0/junction.rs +++ b/xcm/src/v0/junction.rs @@ -159,7 +159,7 @@ impl From<Junction1> for Junction { Junction1::AccountIndex64 { network, index } => Self::AccountIndex64 { network, index }, Junction1::AccountKey20 { network, key } => Self::AccountKey20 { network, key }, Junction1::PalletInstance(index) => Self::PalletInstance(index), - Junction1::GeneralIndex { id } => Self::GeneralIndex { id }, + Junction1::GeneralIndex(id) => Self::GeneralIndex { id }, Junction1::GeneralKey(key) => Self::GeneralKey(key), Junction1::OnlyChild => Self::OnlyChild, Junction1::Plurality { id, part } => Self::Plurality { id: id.into(), part }, diff --git a/xcm/src/v0/multi_location.rs b/xcm/src/v0/multi_location.rs index b056e557b5d9..9e9514539621 100644 --- a/xcm/src/v0/multi_location.rs +++ b/xcm/src/v0/multi_location.rs @@ -707,56 +707,56 @@ impl TryFrom<MultiLocation1> for MultiLocation { } match v1.interior { - Null => Ok(res), - X1(j0) => res.pushed_with(j0.into()).map_err(|_| ()), + Here => Ok(res), + X1(j0) => res.pushed_with(Junction::from(j0)).map_err(|_| ()), X2(j0, j1) => res - .pushed_with(j0.into()) - .and_then(|res| res.pushed_with(j1.into())) + .pushed_with(Junction::from(j0)) + .and_then(|res| res.pushed_with(Junction::from(j1))) .map_err(|_| ()), X3(j0, j1, j2) => res - .pushed_with(j0.into()) - .and_then(|res| res.pushed_with(j1.into())) - .and_then(|res| res.pushed_with(j2.into())) + .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(j0.into()) - .and_then(|res| res.pushed_with(j1.into())) - .and_then(|res| res.pushed_with(j2.into())) - .and_then(|res| res.pushed_with(j3.into())) + .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(j0.into()) - .and_then(|res| res.pushed_with(j1.into())) - .and_then(|res| res.pushed_with(j2.into())) - .and_then(|res| res.pushed_with(j3.into())) - .and_then(|res| res.pushed_with(j4.into())) + .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(j0.into()) - .and_then(|res| res.pushed_with(j1.into())) - .and_then(|res| res.pushed_with(j2.into())) - .and_then(|res| res.pushed_with(j3.into())) - .and_then(|res| res.pushed_with(j4.into())) - .and_then(|res| res.pushed_with(j5.into())) + .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(j0.into()) - .and_then(|res| res.pushed_with(j1.into())) - .and_then(|res| res.pushed_with(j2.into())) - .and_then(|res| res.pushed_with(j3.into())) - .and_then(|res| res.pushed_with(j4.into())) - .and_then(|res| res.pushed_with(j5.into())) - .and_then(|res| res.pushed_with(j6.into())) + .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(j0.into()) - .and_then(|res| res.pushed_with(j1.into())) - .and_then(|res| res.pushed_with(j2.into())) - .and_then(|res| res.pushed_with(j3.into())) - .and_then(|res| res.pushed_with(j4.into())) - .and_then(|res| res.pushed_with(j5.into())) - .and_then(|res| res.pushed_with(j6.into())) - .and_then(|res| res.pushed_with(j7.into())) + .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/v1/multilocation.rs b/xcm/src/v1/multilocation.rs index 3481be4fdf99..108329ff95ca 100644 --- a/xcm/src/v1/multilocation.rs +++ b/xcm/src/v1/multilocation.rs @@ -77,15 +77,23 @@ impl MultiLocation { /// /// The resulting `MultiLocation` can be interpreted as the "current consensus system". pub const fn here() -> MultiLocation { - MultiLocation { parents: 0, interior: Junctions::Null } + MultiLocation { parents: 0, interior: Junctions::Here } } - /// Creates a new `MultiLocation` with the specified number of parents in the `P` const generic - /// parameter and a `Null` interior. - pub const fn with_parents<const P: u8>() -> MultiLocation { - // If this condition does not hold, then P may overflow MAX_MULTILOCATION_LENGTH. + /// 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 { const_assert!(MAX_MULTILOCATION_LENGTH >= 255); - MultiLocation { parents: P, interior: Junctions::Null } + MultiLocation { parents, interior: Junctions::Here } } /// Whether or not the `MultiLocation` has no parents and has a `Null` interior. @@ -111,7 +119,7 @@ impl MultiLocation { /// 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::Null) && self.parents == count + matches!(self.interior, Junctions::Here) && self.parents == count } /// Returns the number of parents and junctions in `self`. @@ -160,7 +168,7 @@ impl MultiLocation { /// 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::Null; + let mut n = Junctions::Here; mem::swap(&mut self.interior, &mut n); match n.pushed_with(new) { Ok(result) => { @@ -176,7 +184,7 @@ impl MultiLocation { /// 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::Null; + let mut n = Junctions::Here; mem::swap(&mut self.interior, &mut n); match n.pushed_front_with(new) { Ok(result) => { @@ -276,7 +284,7 @@ impl MultiLocation { /// m.match_and_split(&MultiLocation::new(1, X1(PalletInstance(3))).unwrap()), /// Some(&OnlyChild), /// ); - /// assert_eq!(m.match_and_split(&MultiLocation::new(1, Null).unwrap()), None); + /// assert_eq!(m.match_and_split(&MultiLocation::new(1, Here).unwrap()), None); /// # } /// ``` pub fn match_and_split(&self, prefix: &MultiLocation) -> Option<&Junction> { @@ -370,7 +378,7 @@ impl From<Junction> for MultiLocation { impl From<()> for MultiLocation { fn from(_: ()) -> Self { - MultiLocation { parents: 0, interior: Junctions::Null } + MultiLocation { parents: 0, interior: Junctions::Here } } } impl From<(Junction,)> for MultiLocation { @@ -425,7 +433,7 @@ impl From<(Junction, Junction, Junction, Junction, Junction, Junction, Junction, impl From<[Junction; 0]> for MultiLocation { fn from(_: [Junction; 0]) -> Self { - MultiLocation { parents: 0, interior: Junctions::Null } + MultiLocation { parents: 0, interior: Junctions::Here } } } impl From<[Junction; 1]> for MultiLocation { @@ -585,7 +593,7 @@ impl Junctions { /// Returns first junction, or `None` if the location is empty. pub fn first(&self) -> Option<&Junction> { match &self { - Junctions::Null => None, + Junctions::Here => None, Junctions::X1(ref a) => Some(a), Junctions::X2(ref a, ..) => Some(a), Junctions::X3(ref a, ..) => Some(a), @@ -600,7 +608,7 @@ impl Junctions { /// Returns last junction, or `None` if the location is empty. pub fn last(&self) -> Option<&Junction> { match &self { - Junctions::Null => None, + Junctions::Here => None, Junctions::X1(ref a) => Some(a), Junctions::X2(.., ref a) => Some(a), Junctions::X3(.., ref a) => Some(a), @@ -616,8 +624,8 @@ impl Junctions { /// (second item in tuple) or `None` if it was empty. pub fn split_first(self) -> (Junctions, Option<Junction>) { match self { - Junctions::Null => (Junctions::Null, None), - Junctions::X1(a) => (Junctions::Null, 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)), @@ -632,8 +640,8 @@ impl Junctions { /// (second item in tuple) or `None` if it was empty. pub fn split_last(self) -> (Junctions, Option<Junction>) { match self { - Junctions::Null => (Junctions::Null, None), - Junctions::X1(a) => (Junctions::Null, Some(a)), + 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)), @@ -646,7 +654,7 @@ impl Junctions { /// Removes the first element from `self`, returning it (or `None` if it was empty). pub fn take_first(&mut self) -> Option<Junction> { - let mut d = Junctions::Null; + let mut d = Junctions::Here; mem::swap(&mut *self, &mut d); let (tail, head) = d.split_first(); *self = tail; @@ -655,7 +663,7 @@ impl Junctions { /// Removes the last element from `self`, returning it (or `None` if it was empty). pub fn take_last(&mut self) -> Option<Junction> { - let mut d = Junctions::Null; + let mut d = Junctions::Here; mem::swap(&mut *self, &mut d); let (head, tail) = d.split_last(); *self = head; @@ -666,7 +674,7 @@ impl Junctions { /// `self` in case of overflow. pub fn pushed_with(self, new: Junction) -> result::Result<Self, Self> { Ok(match self { - Junctions::Null => Junctions::X1(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), @@ -682,7 +690,7 @@ impl Junctions { /// `self` in case of overflow. pub fn pushed_front_with(self, new: Junction) -> result::Result<Self, Self> { Ok(match self { - Junctions::Null => Junctions::X1(new), + 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), @@ -697,7 +705,7 @@ impl Junctions { /// Returns the number of junctions in `self`. pub const fn len(&self) -> usize { match &self { - Junctions::Null => 0, + Junctions::Here => 0, Junctions::X1(..) => 1, Junctions::X2(..) => 2, Junctions::X3(..) => 3, @@ -853,16 +861,16 @@ impl TryFrom<MultiLocation0> for MultiLocation { use Junctions::*; match old { MultiLocation0::Null => Ok(Here.into()), - MultiLocation0::X1(j0) if j0.is_parent() => Ok(MultiLocation::with_parents::<1>()), + MultiLocation0::X1(j0) if j0.is_parent() => Ok(MultiLocation::ancestor(1)), MultiLocation0::X1(j0) => Ok(X1(j0.try_into()?).into()), MultiLocation0::X2(j0, j1) if j0.is_parent() && j1.is_parent() => - Ok(MultiLocation::with_parents::<2>()), + Ok(MultiLocation::ancestor(2)), 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::with_parents::<3>()), + 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() => @@ -871,7 +879,7 @@ impl TryFrom<MultiLocation0> for MultiLocation { 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::with_parents::<4>()), + 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()?) }), @@ -887,7 +895,7 @@ impl TryFrom<MultiLocation0> for MultiLocation { if j0.is_parent() && j1.is_parent() && j2.is_parent() && j3.is_parent() && j4.is_parent() => - Ok(MultiLocation::with_parents::<5>()), + 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()?) }), @@ -916,7 +924,7 @@ impl TryFrom<MultiLocation0> for MultiLocation { j1.is_parent() && j2.is_parent() && j3.is_parent() && j4.is_parent() && j5.is_parent() => - Ok(MultiLocation::with_parents::<6>()), + Ok(MultiLocation::ancestor(6)), MultiLocation0::X6(j0, j1, j2, j3, j4, j5) if j0.is_parent() && j1.is_parent() && j2.is_parent() && @@ -960,7 +968,7 @@ impl TryFrom<MultiLocation0> for MultiLocation { j1.is_parent() && j2.is_parent() && j3.is_parent() && j4.is_parent() && j5.is_parent() && j6.is_parent() => - Ok(MultiLocation::with_parents::<7>()), + Ok(MultiLocation::ancestor(7)), MultiLocation0::X7(j0, j1, j2, j3, j4, j5, j6) if j0.is_parent() && j1.is_parent() && j2.is_parent() && @@ -1022,7 +1030,7 @@ impl TryFrom<MultiLocation0> for MultiLocation { j3.is_parent() && j4.is_parent() && j5.is_parent() && j6.is_parent() && j7.is_parent() => - Ok(MultiLocation::with_parents::<8>()), + Ok(MultiLocation::ancestor(8)), MultiLocation0::X8(j0, j1, j2, j3, j4, j5, j6, j7) if j0.is_parent() && j1.is_parent() && j2.is_parent() && @@ -1126,7 +1134,7 @@ mod tests { parents: 1, interior: X2(Parachain(42), AccountIndex64 { network: Any, index: 23 }), }; - assert_eq!(m.match_and_split(&MultiLocation { parents: 1, interior: Null }), None); + assert_eq!(m.match_and_split(&MultiLocation { parents: 1, interior: Here }), None); assert_eq!( m.match_and_split(&MultiLocation { parents: 1, interior: X1(Parachain(42)) }), Some(&AccountIndex64 { network: Any, index: 23 }) @@ -1171,10 +1179,10 @@ mod tests { // cannot prepend to create overly long multilocation let mut m = MultiLocation { parents: 253, interior: X1(Parachain(42)) }; - let prefix = MultiLocation { parents: 2, interior: Null }; + let prefix = MultiLocation { parents: 2, interior: Here }; assert_eq!(m.prepend_with(prefix.clone()), Err(prefix)); - let prefix = MultiLocation { parents: 1, interior: Null }; + let prefix = MultiLocation { parents: 1, interior: Here }; assert_eq!(m.prepend_with(prefix), Ok(())); assert_eq!(m, MultiLocation { parents: 254, interior: X1(Parachain(42)) }); } @@ -1193,7 +1201,7 @@ mod tests { assert_eq!(iter.next_back(), None); assert_eq!(second, &Parachain(3)); - let res = Null + let res = Here .pushed_with(first.clone()) .unwrap() .pushed_with(second.clone()) @@ -1203,7 +1211,7 @@ mod tests { assert_eq!(m, res); // make sure there's no funny business with the 0 indexing - let m = Null; + let m = Here; let mut iter = m.iter(); assert_eq!(iter.next(), None); diff --git a/xcm/src/v1/traits.rs b/xcm/src/v1/traits.rs index 2410223f8b3e..3e5d33d51313 100644 --- a/xcm/src/v1/traits.rs +++ b/xcm/src/v1/traits.rs @@ -215,7 +215,7 @@ impl<C> ExecuteXcm<C> for () { /// struct Sender3; /// impl SendXcm for Sender3 { /// fn send_xcm(destination: MultiLocation, message: Xcm<()>) -> Result { -/// if matches!(destination.interior(), Junctions::Null) +/// if matches!(destination.interior(), Junctions::Here) /// && destination.parent_count() == 1 /// { /// Ok(()) @@ -229,7 +229,7 @@ impl<C> ExecuteXcm<C> for () { /// # fn main() { /// let call: Vec<u8> = ().encode(); /// let message = Xcm::Transact { origin_type: OriginKind::Superuser, require_weight_at_most: 0, call: call.into() }; -/// let destination = MultiLocation::with_parents::<1>(); +/// let destination = MultiLocation::ancestor(1); /// /// assert!( /// // Sender2 will block this. diff --git a/xcm/xcm-builder/src/currency_adapter.rs b/xcm/xcm-builder/src/currency_adapter.rs index 097010d2c889..9335ab9e4d7c 100644 --- a/xcm/xcm-builder/src/currency_adapter.rs +++ b/xcm/xcm-builder/src/currency_adapter.rs @@ -61,7 +61,7 @@ impl From<Error> for XcmError { /// /// /// Our relay chain's location. /// parameter_types! { -/// RelayChain: MultiLocation = MultiLocation::with_parents::<1>(); +/// RelayChain: MultiLocation = MultiLocation::ancestor(1); /// CheckingAccount: AccountId = Default::default(); /// } /// diff --git a/xcm/xcm-builder/src/location_conversion.rs b/xcm/xcm-builder/src/location_conversion.rs index bab5ee615e41..2895fc4cc4f7 100644 --- a/xcm/xcm-builder/src/location_conversion.rs +++ b/xcm/xcm-builder/src/location_conversion.rs @@ -51,7 +51,7 @@ impl<AccountId: Default + Eq + Clone> Convert<MultiLocation, AccountId> fn reverse_ref(who: impl Borrow<AccountId>) -> Result<MultiLocation, ()> { if who.borrow() == &AccountId::default() { - Ok(MultiLocation::with_parents::<1>()) + Ok(MultiLocation::ancestor(1)) } else { Err(()) } @@ -181,7 +181,7 @@ pub struct LocationInverter<Ancestry>(PhantomData<Ancestry>); impl<Ancestry: Get<MultiLocation>> InvertLocation for LocationInverter<Ancestry> { fn invert_location(location: &MultiLocation) -> MultiLocation { let mut ancestry = Ancestry::get(); - let mut junctions = Junctions::Null; + let mut junctions = Junctions::Here; for _ in 0..location.parent_count() { junctions = junctions .pushed_with(ancestry.take_first_interior().unwrap_or(Junction::OnlyChild)) @@ -244,7 +244,7 @@ mod tests { pub Ancestry: MultiLocation = X2(account20(), account20()).into(); } - let input = MultiLocation::with_parents::<2>(); + let input = MultiLocation::ancestor(2); let inverted = LocationInverter::<Ancestry>::invert_location(&input); assert_eq!(inverted, X2(account20(), account20()).into()); } @@ -259,7 +259,7 @@ mod tests { pub Ancestry: MultiLocation = X1(PalletInstance(5)).into(); } - let input = MultiLocation::with_parents::<2>(); + let input = MultiLocation::ancestor(2); let inverted = LocationInverter::<Ancestry>::invert_location(&input); 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 579b2eba3f78..5240d341d1f5 100644 --- a/xcm/xcm-builder/src/matches_fungible.rs +++ b/xcm/xcm-builder/src/matches_fungible.rs @@ -37,11 +37,11 @@ use xcm_executor::traits::MatchesFungible; /// use xcm_executor::traits::MatchesFungible; /// /// frame_support::parameter_types! { -/// pub TargetLocation: MultiLocation = MultiLocation::with_parents::<1>(); +/// pub TargetLocation: MultiLocation = MultiLocation::ancestor(1); /// } /// /// # fn main() { -/// let asset = (MultiLocation::with_parents::<1>(), 999).into(); +/// let asset = (MultiLocation::ancestor(1), 999).into(); /// // match `asset` if it is a concrete asset in `TargetLocation`. /// assert_eq!(<IsConcrete<TargetLocation> as MatchesFungible<u128>>::matches_fungible(&asset), Some(999)); /// # } diff --git a/xcm/xcm-builder/src/tests.rs b/xcm/xcm-builder/src/tests.rs index fffcffaeb1e3..a7551143b998 100644 --- a/xcm/xcm-builder/src/tests.rs +++ b/xcm/xcm-builder/src/tests.rs @@ -21,12 +21,12 @@ use xcm_executor::{traits::*, Config, XcmExecutor}; #[test] fn basic_setup_works() { add_reserve( - MultiLocation::with_parents::<1>(), - Wild((MultiLocation::with_parents::<1>(), WildFungible).into()), + MultiLocation::ancestor(1), + Wild((MultiLocation::ancestor(1), WildFungible).into()), ); assert!(<TestConfig as Config>::IsReserve::filter_asset_location( - &(MultiLocation::with_parents::<1>(), 100).into(), - &MultiLocation::with_parents::<1>(), + &(MultiLocation::ancestor(1), 100).into(), + &MultiLocation::ancestor(1), )); assert_eq!(to_account(X1(Parachain(1)).into()), Ok(1001)); @@ -47,10 +47,10 @@ fn basic_setup_works() { #[test] fn weigher_should_work() { let mut message = opaque::Xcm::ReserveAssetDeposited { - assets: (MultiLocation::with_parents::<1>(), 100).into(), + assets: (MultiLocation::ancestor(1), 100).into(), effects: vec![ Order::BuyExecution { - fees: (MultiLocation::with_parents::<1>(), 1).into(), + fees: (MultiLocation::ancestor(1), 1).into(), weight: 0, debt: 30, halt_on_error: true, @@ -71,13 +71,13 @@ fn weigher_should_work() { #[test] fn take_weight_credit_barrier_should_work() { let mut message = opaque::Xcm::TransferAsset { - assets: (MultiLocation::with_parents::<1>(), 100).into(), + assets: (MultiLocation::ancestor(1), 100).into(), beneficiary: Here.into(), }; let mut weight_credit = 10; let r = TakeWeightCredit::should_execute( - &MultiLocation::with_parents::<1>(), + &MultiLocation::ancestor(1), true, &mut message, 10, @@ -87,7 +87,7 @@ fn take_weight_credit_barrier_should_work() { assert_eq!(weight_credit, 0); let r = TakeWeightCredit::should_execute( - &MultiLocation::with_parents::<1>(), + &MultiLocation::ancestor(1), true, &mut message, 10, @@ -100,11 +100,11 @@ fn take_weight_credit_barrier_should_work() { #[test] fn allow_unpaid_should_work() { let mut message = opaque::Xcm::TransferAsset { - assets: (MultiLocation::with_parents::<1>(), 100).into(), + assets: (MultiLocation::ancestor(1), 100).into(), beneficiary: Here.into(), }; - AllowUnpaidFrom::set(vec![MultiLocation::with_parents::<1>()]); + AllowUnpaidFrom::set(vec![MultiLocation::ancestor(1)]); let r = AllowUnpaidExecutionFrom::<IsInVec<AllowUnpaidFrom>>::should_execute( &X1(Parachain(1)).into(), @@ -116,7 +116,7 @@ fn allow_unpaid_should_work() { assert_eq!(r, Err(())); let r = AllowUnpaidExecutionFrom::<IsInVec<AllowUnpaidFrom>>::should_execute( - &MultiLocation::with_parents::<1>(), + &MultiLocation::ancestor(1), true, &mut message, 10, @@ -127,10 +127,10 @@ fn allow_unpaid_should_work() { #[test] fn allow_paid_should_work() { - AllowPaidFrom::set(vec![MultiLocation::with_parents::<1>()]); + AllowPaidFrom::set(vec![MultiLocation::ancestor(1)]); let mut message = opaque::Xcm::TransferAsset { - assets: (MultiLocation::with_parents::<1>(), 100).into(), + assets: (MultiLocation::ancestor(1), 100).into(), beneficiary: Here.into(), }; @@ -143,9 +143,9 @@ fn allow_paid_should_work() { ); assert_eq!(r, Err(())); - let fees = (MultiLocation::with_parents::<1>(), 1).into(); + let fees = (MultiLocation::ancestor(1), 1).into(); let mut underpaying_message = opaque::Xcm::ReserveAssetDeposited { - assets: (MultiLocation::with_parents::<1>(), 100).into(), + assets: (MultiLocation::ancestor(1), 100).into(), effects: vec![ Order::BuyExecution { fees, @@ -164,7 +164,7 @@ fn allow_paid_should_work() { }; let r = AllowTopLevelPaidExecutionFrom::<IsInVec<AllowPaidFrom>>::should_execute( - &MultiLocation::with_parents::<1>(), + &MultiLocation::ancestor(1), true, &mut underpaying_message, 30, @@ -172,9 +172,9 @@ fn allow_paid_should_work() { ); assert_eq!(r, Err(())); - let fees = (MultiLocation::with_parents::<1>(), 1).into(); + let fees = (MultiLocation::ancestor(1), 1).into(); let mut paying_message = opaque::Xcm::ReserveAssetDeposited { - assets: (MultiLocation::with_parents::<1>(), 100).into(), + assets: (MultiLocation::ancestor(1), 100).into(), effects: vec![ Order::BuyExecution { fees, @@ -202,7 +202,7 @@ fn allow_paid_should_work() { assert_eq!(r, Err(())); let r = AllowTopLevelPaidExecutionFrom::<IsInVec<AllowPaidFrom>>::should_execute( - &MultiLocation::with_parents::<1>(), + &MultiLocation::ancestor(1), true, &mut paying_message, 30, @@ -213,17 +213,17 @@ fn allow_paid_should_work() { #[test] fn paying_reserve_deposit_should_work() { - AllowPaidFrom::set(vec![MultiLocation::with_parents::<1>()]); + AllowPaidFrom::set(vec![MultiLocation::ancestor(1)]); add_reserve( - MultiLocation::with_parents::<1>(), - (MultiLocation::with_parents::<1>(), WildFungible).into(), + MultiLocation::ancestor(1), + (MultiLocation::ancestor(1), WildFungible).into(), ); - WeightPrice::set((MultiLocation::with_parents::<1>().into(), 1_000_000_000_000)); + WeightPrice::set((MultiLocation::ancestor(1).into(), 1_000_000_000_000)); - let origin = MultiLocation::with_parents::<1>(); - let fees = (MultiLocation::with_parents::<1>(), 30).into(); + let origin = MultiLocation::ancestor(1); + let fees = (MultiLocation::ancestor(1), 30).into(); let message = Xcm::<TestCall>::ReserveAssetDeposited { - assets: (MultiLocation::with_parents::<1>(), 100).into(), + assets: (MultiLocation::ancestor(1), 100).into(), effects: vec![ Order::<TestCall>::BuyExecution { fees, @@ -243,7 +243,7 @@ fn paying_reserve_deposit_should_work() { let weight_limit = 50; let r = XcmExecutor::<TestConfig>::execute_xcm(origin, message, weight_limit); assert_eq!(r, Outcome::Complete(30)); - assert_eq!(assets(3000), vec![(MultiLocation::with_parents::<1>(), 70).into()]); + assert_eq!(assets(3000), vec![(MultiLocation::ancestor(1), 70).into()]); } #[test] @@ -298,7 +298,7 @@ fn reserve_transfer_should_work() { vec![( X1(Parachain(2)).into(), Xcm::ReserveAssetDeposited { - assets: (MultiLocation::with_parents::<1>(), 100).into(), + assets: (MultiLocation::ancestor(1), 100).into(), effects: vec![Order::DepositAsset { assets: All.into(), max_assets: 1, @@ -311,9 +311,9 @@ fn reserve_transfer_should_work() { #[test] fn transacting_should_work() { - AllowUnpaidFrom::set(vec![MultiLocation::with_parents::<1>()]); + AllowUnpaidFrom::set(vec![MultiLocation::ancestor(1)]); - let origin = MultiLocation::with_parents::<1>(); + let origin = MultiLocation::ancestor(1); let message = Xcm::<TestCall>::Transact { origin_type: OriginKind::Native, require_weight_at_most: 50, @@ -326,9 +326,9 @@ fn transacting_should_work() { #[test] fn transacting_should_respect_max_weight_requirement() { - AllowUnpaidFrom::set(vec![MultiLocation::with_parents::<1>()]); + AllowUnpaidFrom::set(vec![MultiLocation::ancestor(1)]); - let origin = MultiLocation::with_parents::<1>(); + let origin = MultiLocation::ancestor(1); let message = Xcm::<TestCall>::Transact { origin_type: OriginKind::Native, require_weight_at_most: 40, @@ -341,9 +341,9 @@ fn transacting_should_respect_max_weight_requirement() { #[test] fn transacting_should_refund_weight() { - AllowUnpaidFrom::set(vec![MultiLocation::with_parents::<1>()]); + AllowUnpaidFrom::set(vec![MultiLocation::ancestor(1)]); - let origin = MultiLocation::with_parents::<1>(); + let origin = MultiLocation::ancestor(1); let message = Xcm::<TestCall>::Transact { origin_type: OriginKind::Native, require_weight_at_most: 50, @@ -358,13 +358,13 @@ fn transacting_should_refund_weight() { fn paid_transacting_should_refund_payment_for_unused_weight() { let one: MultiLocation = X1(AccountIndex64 { index: 1, network: Any }).into(); AllowPaidFrom::set(vec![one.clone()]); - add_asset(1, (MultiLocation::with_parents::<1>(), 100).into()); - WeightPrice::set((MultiLocation::with_parents::<1>().into(), 1_000_000_000_000)); + add_asset(1, (MultiLocation::ancestor(1), 100).into()); + WeightPrice::set((MultiLocation::ancestor(1).into(), 1_000_000_000_000)); let origin = one.clone(); - let fees = (MultiLocation::with_parents::<1>(), 100).into(); + let fees = (MultiLocation::ancestor(1), 100).into(); let message = Xcm::<TestCall>::WithdrawAsset { - assets: (MultiLocation::with_parents::<1>(), 100).into(), // enough for 100 units of weight. + assets: (MultiLocation::ancestor(1), 100).into(), // enough for 100 units of weight. effects: vec![ Order::<TestCall>::BuyExecution { fees, @@ -389,17 +389,17 @@ fn paid_transacting_should_refund_payment_for_unused_weight() { let weight_limit = 100; let r = XcmExecutor::<TestConfig>::execute_xcm(origin, message, weight_limit); assert_eq!(r, Outcome::Complete(50)); - assert_eq!(assets(1), vec![(MultiLocation::with_parents::<1>(), 50).into()]); + assert_eq!(assets(1), vec![(MultiLocation::ancestor(1), 50).into()]); } #[test] fn prepaid_result_of_query_should_get_free_execution() { let query_id = 33; - let origin = MultiLocation::with_parents::<1>(); + let origin = MultiLocation::ancestor(1); // 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((MultiLocation::with_parents::<1>(), 100).into()); + let the_response = Response::Assets((MultiLocation::ancestor(1), 100).into()); let message = Xcm::<TestCall>::QueryResponse { query_id, response: the_response.clone() }; let weight_limit = 10; diff --git a/xcm/xcm-simulator/example/src/lib.rs b/xcm/xcm-simulator/example/src/lib.rs index 9bd86a60829d..bdefffe4144b 100644 --- a/xcm/xcm-simulator/example/src/lib.rs +++ b/xcm/xcm-simulator/example/src/lib.rs @@ -139,7 +139,7 @@ mod tests { ParaA::execute_with(|| { assert_ok!(ParachainPalletXcm::send_xcm( Here.into(), - MultiLocation::with_parents::<1>(), + MultiLocation::ancestor(1), Transact { origin_type: OriginKind::SovereignAccount, require_weight_at_most: INITIAL_BALANCE as u64, diff --git a/xcm/xcm-simulator/example/src/parachain.rs b/xcm/xcm-simulator/example/src/parachain.rs index 2e85e86169f6..d066d3cd16e2 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::with_parents::<1>(); + pub const KsmLocation: MultiLocation = MultiLocation::ancestor(1); 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(MultiLocation::with_parents::<1>()), 1); + pub KsmPerSecond: (AssetId, u128) = (Concrete(MultiLocation::ancestor(1)), 1); } pub type LocalAssetTransactor = @@ -267,7 +267,7 @@ pub mod mock_msg_queue { }, Ok(Ok(x)) => { let outcome = T::XcmExecutor::execute_xcm( - MultiLocation::with_parents::<1>(), + MultiLocation::ancestor(1), x, limit, ); diff --git a/xcm/xcm-simulator/src/lib.rs b/xcm/xcm-simulator/src/lib.rs index 96669d880e4e..aed9635cff7f 100644 --- a/xcm/xcm-simulator/src/lib.rs +++ b/xcm/xcm-simulator/src/lib.rs @@ -196,7 +196,7 @@ macro_rules! decl_test_network { use $crate::{UmpSink, XcmpMessageHandlerT}; match destination.interior() { - $crate::Junctions::Null if destination.parent_count() == 1 => { + $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[..], From 0d21a4452bd85edd4f3cc7e9b86c3a50ff69dc24 Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Sat, 7 Aug 2021 22:16:14 +0200 Subject: [PATCH 128/166] Fixes --- xcm/pallet-xcm/src/tests.rs | 12 ++-- xcm/src/v1/multilocation.rs | 4 +- xcm/src/v1/traits.rs | 2 +- xcm/xcm-builder/src/currency_adapter.rs | 2 +- xcm/xcm-builder/src/location_conversion.rs | 6 +- xcm/xcm-builder/src/matches_fungible.rs | 4 +- xcm/xcm-builder/src/tests.rs | 84 +++++++++++----------- xcm/xcm-simulator/example/src/lib.rs | 2 +- xcm/xcm-simulator/example/src/parachain.rs | 6 +- 9 files changed, 61 insertions(+), 61 deletions(-) diff --git a/xcm/pallet-xcm/src/tests.rs b/xcm/pallet-xcm/src/tests.rs index 448bb71724cf..5bd3eb69f5ff 100644 --- a/xcm/pallet-xcm/src/tests.rs +++ b/xcm/pallet-xcm/src/tests.rs @@ -40,9 +40,9 @@ fn send_works() { let sender: MultiLocation = AccountId32 { network: AnyNetwork::get(), id: ALICE.into() }.into(); let message = Xcm::ReserveAssetDeposited { - assets: (MultiLocation::ancestor(1), SEND_AMOUNT).into(), + assets: (MultiLocation::parent(), SEND_AMOUNT).into(), effects: vec![ - buy_execution((MultiLocation::ancestor(1), SEND_AMOUNT), weight), + buy_execution((MultiLocation::parent(), SEND_AMOUNT), weight), DepositAsset { assets: All.into(), max_assets: 1, beneficiary: sender.clone() }, ], }; @@ -78,9 +78,9 @@ fn send_fails_when_xcm_router_blocks() { let sender: MultiLocation = Junction::AccountId32 { network: AnyNetwork::get(), id: ALICE.into() }.into(); let message = Xcm::ReserveAssetDeposited { - assets: (MultiLocation::ancestor(1), SEND_AMOUNT).into(), + assets: (MultiLocation::parent(), SEND_AMOUNT).into(), effects: vec![ - buy_execution((MultiLocation::ancestor(1), SEND_AMOUNT), weight), + buy_execution((MultiLocation::parent(), SEND_AMOUNT), weight), DepositAsset { assets: All.into(), max_assets: 1, beneficiary: sender.clone() }, ], }; @@ -153,9 +153,9 @@ fn reserve_transfer_assets_works() { vec![( Parachain(PARA_ID).into(), Xcm::ReserveAssetDeposited { - assets: (MultiLocation::ancestor(1), SEND_AMOUNT).into(), + assets: (MultiLocation::parent(), SEND_AMOUNT).into(), effects: vec![ - buy_execution((MultiLocation::ancestor(1), SEND_AMOUNT), weight), + buy_execution((MultiLocation::parent(), SEND_AMOUNT), weight), DepositAsset { assets: All.into(), max_assets: 1, beneficiary: dest }, ] } diff --git a/xcm/src/v1/multilocation.rs b/xcm/src/v1/multilocation.rs index 108329ff95ca..8e3bc1060c35 100644 --- a/xcm/src/v1/multilocation.rs +++ b/xcm/src/v1/multilocation.rs @@ -861,10 +861,10 @@ impl TryFrom<MultiLocation0> for MultiLocation { use Junctions::*; match old { MultiLocation0::Null => Ok(Here.into()), - MultiLocation0::X1(j0) if j0.is_parent() => Ok(MultiLocation::ancestor(1)), + MultiLocation0::X1(j0) if j0.is_parent() => Ok(MultiLocation::parent()), MultiLocation0::X1(j0) => Ok(X1(j0.try_into()?).into()), MultiLocation0::X2(j0, j1) if j0.is_parent() && j1.is_parent() => - Ok(MultiLocation::ancestor(2)), + 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()), diff --git a/xcm/src/v1/traits.rs b/xcm/src/v1/traits.rs index 3e5d33d51313..338ca55521de 100644 --- a/xcm/src/v1/traits.rs +++ b/xcm/src/v1/traits.rs @@ -229,7 +229,7 @@ impl<C> ExecuteXcm<C> for () { /// # fn main() { /// let call: Vec<u8> = ().encode(); /// let message = Xcm::Transact { origin_type: OriginKind::Superuser, require_weight_at_most: 0, call: call.into() }; -/// let destination = MultiLocation::ancestor(1); +/// let destination = MultiLocation::parent(); /// /// assert!( /// // Sender2 will block this. diff --git a/xcm/xcm-builder/src/currency_adapter.rs b/xcm/xcm-builder/src/currency_adapter.rs index 9335ab9e4d7c..cd6e03c365db 100644 --- a/xcm/xcm-builder/src/currency_adapter.rs +++ b/xcm/xcm-builder/src/currency_adapter.rs @@ -61,7 +61,7 @@ impl From<Error> for XcmError { /// /// /// Our relay chain's location. /// parameter_types! { -/// RelayChain: MultiLocation = MultiLocation::ancestor(1); +/// RelayChain: MultiLocation = MultiLocation::parent(); /// CheckingAccount: AccountId = Default::default(); /// } /// diff --git a/xcm/xcm-builder/src/location_conversion.rs b/xcm/xcm-builder/src/location_conversion.rs index 2895fc4cc4f7..7dde7acfe7ee 100644 --- a/xcm/xcm-builder/src/location_conversion.rs +++ b/xcm/xcm-builder/src/location_conversion.rs @@ -51,7 +51,7 @@ impl<AccountId: Default + Eq + Clone> Convert<MultiLocation, AccountId> fn reverse_ref(who: impl Borrow<AccountId>) -> Result<MultiLocation, ()> { if who.borrow() == &AccountId::default() { - Ok(MultiLocation::ancestor(1)) + Ok(MultiLocation::parent()) } else { Err(()) } @@ -244,7 +244,7 @@ mod tests { pub Ancestry: MultiLocation = X2(account20(), account20()).into(); } - let input = MultiLocation::ancestor(2); + let input = MultiLocation::grandparent(); let inverted = LocationInverter::<Ancestry>::invert_location(&input); assert_eq!(inverted, X2(account20(), account20()).into()); } @@ -259,7 +259,7 @@ mod tests { pub Ancestry: MultiLocation = X1(PalletInstance(5)).into(); } - let input = MultiLocation::ancestor(2); + let input = MultiLocation::grandparent(); let inverted = LocationInverter::<Ancestry>::invert_location(&input); 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 5240d341d1f5..e14fcdaa9409 100644 --- a/xcm/xcm-builder/src/matches_fungible.rs +++ b/xcm/xcm-builder/src/matches_fungible.rs @@ -37,11 +37,11 @@ use xcm_executor::traits::MatchesFungible; /// use xcm_executor::traits::MatchesFungible; /// /// frame_support::parameter_types! { -/// pub TargetLocation: MultiLocation = MultiLocation::ancestor(1); +/// pub TargetLocation: MultiLocation = MultiLocation::parent(); /// } /// /// # fn main() { -/// let asset = (MultiLocation::ancestor(1), 999).into(); +/// let asset = (MultiLocation::parent(), 999).into(); /// // match `asset` if it is a concrete asset in `TargetLocation`. /// assert_eq!(<IsConcrete<TargetLocation> as MatchesFungible<u128>>::matches_fungible(&asset), Some(999)); /// # } diff --git a/xcm/xcm-builder/src/tests.rs b/xcm/xcm-builder/src/tests.rs index a7551143b998..0a4b966c6acf 100644 --- a/xcm/xcm-builder/src/tests.rs +++ b/xcm/xcm-builder/src/tests.rs @@ -21,12 +21,12 @@ use xcm_executor::{traits::*, Config, XcmExecutor}; #[test] fn basic_setup_works() { add_reserve( - MultiLocation::ancestor(1), - Wild((MultiLocation::ancestor(1), WildFungible).into()), + MultiLocation::parent(), + Wild((MultiLocation::parent(), WildFungible).into()), ); assert!(<TestConfig as Config>::IsReserve::filter_asset_location( - &(MultiLocation::ancestor(1), 100).into(), - &MultiLocation::ancestor(1), + &(MultiLocation::parent(), 100).into(), + &MultiLocation::parent(), )); assert_eq!(to_account(X1(Parachain(1)).into()), Ok(1001)); @@ -47,10 +47,10 @@ fn basic_setup_works() { #[test] fn weigher_should_work() { let mut message = opaque::Xcm::ReserveAssetDeposited { - assets: (MultiLocation::ancestor(1), 100).into(), + assets: (MultiLocation::parent(), 100).into(), effects: vec![ Order::BuyExecution { - fees: (MultiLocation::ancestor(1), 1).into(), + fees: (MultiLocation::parent(), 1).into(), weight: 0, debt: 30, halt_on_error: true, @@ -71,13 +71,13 @@ fn weigher_should_work() { #[test] fn take_weight_credit_barrier_should_work() { let mut message = opaque::Xcm::TransferAsset { - assets: (MultiLocation::ancestor(1), 100).into(), + assets: (MultiLocation::parent(), 100).into(), beneficiary: Here.into(), }; let mut weight_credit = 10; let r = TakeWeightCredit::should_execute( - &MultiLocation::ancestor(1), + &MultiLocation::parent(), true, &mut message, 10, @@ -87,7 +87,7 @@ fn take_weight_credit_barrier_should_work() { assert_eq!(weight_credit, 0); let r = TakeWeightCredit::should_execute( - &MultiLocation::ancestor(1), + &MultiLocation::parent(), true, &mut message, 10, @@ -100,11 +100,11 @@ fn take_weight_credit_barrier_should_work() { #[test] fn allow_unpaid_should_work() { let mut message = opaque::Xcm::TransferAsset { - assets: (MultiLocation::ancestor(1), 100).into(), + assets: (MultiLocation::parent(), 100).into(), beneficiary: Here.into(), }; - AllowUnpaidFrom::set(vec![MultiLocation::ancestor(1)]); + AllowUnpaidFrom::set(vec![MultiLocation::parent()]); let r = AllowUnpaidExecutionFrom::<IsInVec<AllowUnpaidFrom>>::should_execute( &X1(Parachain(1)).into(), @@ -116,7 +116,7 @@ fn allow_unpaid_should_work() { assert_eq!(r, Err(())); let r = AllowUnpaidExecutionFrom::<IsInVec<AllowUnpaidFrom>>::should_execute( - &MultiLocation::ancestor(1), + &MultiLocation::parent(), true, &mut message, 10, @@ -127,10 +127,10 @@ fn allow_unpaid_should_work() { #[test] fn allow_paid_should_work() { - AllowPaidFrom::set(vec![MultiLocation::ancestor(1)]); + AllowPaidFrom::set(vec![MultiLocation::parent()]); let mut message = opaque::Xcm::TransferAsset { - assets: (MultiLocation::ancestor(1), 100).into(), + assets: (MultiLocation::parent(), 100).into(), beneficiary: Here.into(), }; @@ -143,9 +143,9 @@ fn allow_paid_should_work() { ); assert_eq!(r, Err(())); - let fees = (MultiLocation::ancestor(1), 1).into(); + let fees = (MultiLocation::parent(), 1).into(); let mut underpaying_message = opaque::Xcm::ReserveAssetDeposited { - assets: (MultiLocation::ancestor(1), 100).into(), + assets: (MultiLocation::parent(), 100).into(), effects: vec![ Order::BuyExecution { fees, @@ -164,7 +164,7 @@ fn allow_paid_should_work() { }; let r = AllowTopLevelPaidExecutionFrom::<IsInVec<AllowPaidFrom>>::should_execute( - &MultiLocation::ancestor(1), + &MultiLocation::parent(), true, &mut underpaying_message, 30, @@ -172,9 +172,9 @@ fn allow_paid_should_work() { ); assert_eq!(r, Err(())); - let fees = (MultiLocation::ancestor(1), 1).into(); + let fees = (MultiLocation::parent(), 1).into(); let mut paying_message = opaque::Xcm::ReserveAssetDeposited { - assets: (MultiLocation::ancestor(1), 100).into(), + assets: (MultiLocation::parent(), 100).into(), effects: vec![ Order::BuyExecution { fees, @@ -202,7 +202,7 @@ fn allow_paid_should_work() { assert_eq!(r, Err(())); let r = AllowTopLevelPaidExecutionFrom::<IsInVec<AllowPaidFrom>>::should_execute( - &MultiLocation::ancestor(1), + &MultiLocation::parent(), true, &mut paying_message, 30, @@ -213,17 +213,17 @@ fn allow_paid_should_work() { #[test] fn paying_reserve_deposit_should_work() { - AllowPaidFrom::set(vec![MultiLocation::ancestor(1)]); + AllowPaidFrom::set(vec![MultiLocation::parent()]); add_reserve( - MultiLocation::ancestor(1), - (MultiLocation::ancestor(1), WildFungible).into(), + MultiLocation::parent(), + (MultiLocation::parent(), WildFungible).into(), ); - WeightPrice::set((MultiLocation::ancestor(1).into(), 1_000_000_000_000)); + WeightPrice::set((MultiLocation::parent().into(), 1_000_000_000_000)); - let origin = MultiLocation::ancestor(1); - let fees = (MultiLocation::ancestor(1), 30).into(); + let origin = MultiLocation::parent(); + let fees = (MultiLocation::parent(), 30).into(); let message = Xcm::<TestCall>::ReserveAssetDeposited { - assets: (MultiLocation::ancestor(1), 100).into(), + assets: (MultiLocation::parent(), 100).into(), effects: vec![ Order::<TestCall>::BuyExecution { fees, @@ -243,7 +243,7 @@ fn paying_reserve_deposit_should_work() { let weight_limit = 50; let r = XcmExecutor::<TestConfig>::execute_xcm(origin, message, weight_limit); assert_eq!(r, Outcome::Complete(30)); - assert_eq!(assets(3000), vec![(MultiLocation::ancestor(1), 70).into()]); + assert_eq!(assets(3000), vec![(MultiLocation::parent(), 70).into()]); } #[test] @@ -298,7 +298,7 @@ fn reserve_transfer_should_work() { vec![( X1(Parachain(2)).into(), Xcm::ReserveAssetDeposited { - assets: (MultiLocation::ancestor(1), 100).into(), + assets: (MultiLocation::parent(), 100).into(), effects: vec![Order::DepositAsset { assets: All.into(), max_assets: 1, @@ -311,9 +311,9 @@ fn reserve_transfer_should_work() { #[test] fn transacting_should_work() { - AllowUnpaidFrom::set(vec![MultiLocation::ancestor(1)]); + AllowUnpaidFrom::set(vec![MultiLocation::parent()]); - let origin = MultiLocation::ancestor(1); + let origin = MultiLocation::parent(); let message = Xcm::<TestCall>::Transact { origin_type: OriginKind::Native, require_weight_at_most: 50, @@ -326,9 +326,9 @@ fn transacting_should_work() { #[test] fn transacting_should_respect_max_weight_requirement() { - AllowUnpaidFrom::set(vec![MultiLocation::ancestor(1)]); + AllowUnpaidFrom::set(vec![MultiLocation::parent()]); - let origin = MultiLocation::ancestor(1); + let origin = MultiLocation::parent(); let message = Xcm::<TestCall>::Transact { origin_type: OriginKind::Native, require_weight_at_most: 40, @@ -341,9 +341,9 @@ fn transacting_should_respect_max_weight_requirement() { #[test] fn transacting_should_refund_weight() { - AllowUnpaidFrom::set(vec![MultiLocation::ancestor(1)]); + AllowUnpaidFrom::set(vec![MultiLocation::parent()]); - let origin = MultiLocation::ancestor(1); + let origin = MultiLocation::parent(); let message = Xcm::<TestCall>::Transact { origin_type: OriginKind::Native, require_weight_at_most: 50, @@ -358,13 +358,13 @@ fn transacting_should_refund_weight() { fn paid_transacting_should_refund_payment_for_unused_weight() { let one: MultiLocation = X1(AccountIndex64 { index: 1, network: Any }).into(); AllowPaidFrom::set(vec![one.clone()]); - add_asset(1, (MultiLocation::ancestor(1), 100).into()); - WeightPrice::set((MultiLocation::ancestor(1).into(), 1_000_000_000_000)); + add_asset(1, (MultiLocation::parent(), 100).into()); + WeightPrice::set((MultiLocation::parent().into(), 1_000_000_000_000)); let origin = one.clone(); - let fees = (MultiLocation::ancestor(1), 100).into(); + let fees = (MultiLocation::parent(), 100).into(); let message = Xcm::<TestCall>::WithdrawAsset { - assets: (MultiLocation::ancestor(1), 100).into(), // enough for 100 units of weight. + assets: (MultiLocation::parent(), 100).into(), // enough for 100 units of weight. effects: vec![ Order::<TestCall>::BuyExecution { fees, @@ -389,17 +389,17 @@ fn paid_transacting_should_refund_payment_for_unused_weight() { let weight_limit = 100; let r = XcmExecutor::<TestConfig>::execute_xcm(origin, message, weight_limit); assert_eq!(r, Outcome::Complete(50)); - assert_eq!(assets(1), vec![(MultiLocation::ancestor(1), 50).into()]); + assert_eq!(assets(1), vec![(MultiLocation::parent(), 50).into()]); } #[test] fn prepaid_result_of_query_should_get_free_execution() { let query_id = 33; - let origin = MultiLocation::ancestor(1); + let origin = MultiLocation::parent(); // 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((MultiLocation::ancestor(1), 100).into()); + let the_response = Response::Assets((MultiLocation::parent(), 100).into()); let message = Xcm::<TestCall>::QueryResponse { query_id, response: the_response.clone() }; let weight_limit = 10; diff --git a/xcm/xcm-simulator/example/src/lib.rs b/xcm/xcm-simulator/example/src/lib.rs index bdefffe4144b..cbff1672a544 100644 --- a/xcm/xcm-simulator/example/src/lib.rs +++ b/xcm/xcm-simulator/example/src/lib.rs @@ -139,7 +139,7 @@ mod tests { ParaA::execute_with(|| { assert_ok!(ParachainPalletXcm::send_xcm( Here.into(), - MultiLocation::ancestor(1), + MultiLocation::parent(), Transact { origin_type: OriginKind::SovereignAccount, require_weight_at_most: INITIAL_BALANCE as u64, diff --git a/xcm/xcm-simulator/example/src/parachain.rs b/xcm/xcm-simulator/example/src/parachain.rs index d066d3cd16e2..2feb89fe499b 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::ancestor(1); + 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(MultiLocation::ancestor(1)), 1); + pub KsmPerSecond: (AssetId, u128) = (Concrete(MultiLocation::parent()), 1); } pub type LocalAssetTransactor = @@ -267,7 +267,7 @@ pub mod mock_msg_queue { }, Ok(Ok(x)) => { let outcome = T::XcmExecutor::execute_xcm( - MultiLocation::ancestor(1), + MultiLocation::parent(), x, limit, ); From da7731298753cde49777238fba1835830522d912 Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Sat, 7 Aug 2021 22:21:17 +0200 Subject: [PATCH 129/166] Fixes --- xcm/xcm-builder/src/fungibles_adapter.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xcm/xcm-builder/src/fungibles_adapter.rs b/xcm/xcm-builder/src/fungibles_adapter.rs index 2647c36b5f22..2107acdb4a36 100644 --- a/xcm/xcm-builder/src/fungibles_adapter.rs +++ b/xcm/xcm-builder/src/fungibles_adapter.rs @@ -48,14 +48,14 @@ impl<Prefix: Get<MultiLocation>, AssetId: Clone, ConvertAssetId: Convert<u128, A return Err(()) } match id.interior().at(prefix.interior().len()) { - Some(Junction::GeneralIndex { id }) => ConvertAssetId::convert_ref(id), + Some(Junction::GeneralIndex(id)) => ConvertAssetId::convert_ref(id), _ => Err(()), } } fn reverse_ref(what: impl Borrow<AssetId>) -> result::Result<MultiLocation, ()> { let mut location = Prefix::get(); let id = ConvertAssetId::reverse_ref(what)?; - location.push_interior(Junction::GeneralIndex { id })?; + location.push_interior(Junction::GeneralIndex(id))?; Ok(location) } } From 7d3a238c0c2711658803dccf9507335c565f7155 Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Sat, 7 Aug 2021 23:14:59 +0200 Subject: [PATCH 130/166] Fix MultiLocation --- xcm/src/v1/multilocation.rs | 120 +++++++++++++++--------------------- 1 file changed, 49 insertions(+), 71 deletions(-) diff --git a/xcm/src/v1/multilocation.rs b/xcm/src/v1/multilocation.rs index 8e3bc1060c35..37055550ea41 100644 --- a/xcm/src/v1/multilocation.rs +++ b/xcm/src/v1/multilocation.rs @@ -22,7 +22,6 @@ use core::{ mem, result, }; use parity_scale_codec::{self, Decode, Encode}; -use static_assertions::const_assert; /// A relative path between state-bearing consensus systems. /// @@ -60,17 +59,11 @@ impl Default for MultiLocation { } } -/// Maximum number of junctions a `MultiLocation` can contain. -pub const MAX_MULTILOCATION_LENGTH: usize = 255; - impl MultiLocation { /// Creates a new `MultiLocation`, ensuring that the length of it does not exceed the maximum, /// otherwise returns `Err`. - pub fn new(parents: u8, junctions: Junctions) -> result::Result<MultiLocation, ()> { - if parents as usize + junctions.len() > MAX_MULTILOCATION_LENGTH { - return Err(()) - } - Ok(MultiLocation { parents, interior: junctions }) + pub fn new(parents: u8, junctions: Junctions) -> MultiLocation { + MultiLocation { parents, interior: junctions } } /// Creates a new `MultiLocation` with 0 parents and a `Null` interior. @@ -92,7 +85,6 @@ impl MultiLocation { /// Creates a new `MultiLocation` with `parents` and an empty (`Here`) interior. pub const fn ancestor(parents: u8) -> MultiLocation { - const_assert!(MAX_MULTILOCATION_LENGTH >= 255); MultiLocation { parents, interior: Junctions::Here } } @@ -157,15 +149,6 @@ impl MultiLocation { (multilocation, last) } - /// Bumps the parent count up by `n`. Returns `Err` in case of overflow. - pub fn add_parents(&mut self, n: u8) -> result::Result<(), ()> { - if self.len() + (n as usize) > MAX_MULTILOCATION_LENGTH { - return Err(()) - } - self.parents = self.parents.saturating_add(n); - Ok(()) - } - /// 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; @@ -198,40 +181,22 @@ impl MultiLocation { } } - /// Consumes `self` and returns a `MultiLocation` with its parent count incremented by `n`, or - /// an `Err` with the original value of `self` in case of overflow. - pub fn added_with_parents(self, n: u8) -> result::Result<Self, Self> { - if self.len() + (n as usize) > MAX_MULTILOCATION_LENGTH { - return Err(self) - } - Ok(MultiLocation { parents: self.parents.saturating_add(n), ..self }) - } - /// 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<Self, Self> { - if self.len() >= MAX_MULTILOCATION_LENGTH { - return Err(self) + match self.interior.pushed_with(new) { + Ok(i) => Ok(MultiLocation { interior: i, parents: self.parents }), + Err(i) => Err(MultiLocation { interior: i, parents: self.parents }), } - Ok(MultiLocation { - parents: self.parents, - interior: self.interior.pushed_with(new).expect("length is less than max length; qed"), - }) } /// 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<Self, Self> { - if self.len() >= MAX_MULTILOCATION_LENGTH { - return Err(self) + 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 }), } - Ok(MultiLocation { - parents: self.parents, - interior: self - .interior - .pushed_front_with(new) - .expect("length is less than max length; qed"), - }) } /// Returns the junction at index `i`, or `None` if the location is a parent or if the location @@ -279,12 +244,12 @@ impl MultiLocation { /// ```rust /// # use xcm::v1::{Junctions::*, Junction::*, MultiLocation}; /// # fn main() { - /// let mut m = MultiLocation::new(1, X2(PalletInstance(3), OnlyChild)).unwrap(); + /// let mut m = MultiLocation::new(1, X2(PalletInstance(3), OnlyChild)); /// assert_eq!( - /// m.match_and_split(&MultiLocation::new(1, X1(PalletInstance(3))).unwrap()), + /// m.match_and_split(&MultiLocation::new(1, X1(PalletInstance(3)))), /// Some(&OnlyChild), /// ); - /// assert_eq!(m.match_and_split(&MultiLocation::new(1, Here).unwrap()), None); + /// assert_eq!(m.match_and_split(&MultiLocation::new(1, Here)), None); /// # } /// ``` pub fn match_and_split(&self, prefix: &MultiLocation) -> Option<&Junction> { @@ -303,9 +268,9 @@ impl MultiLocation { /// ```rust /// # use xcm::v1::{Junctions::*, Junction::*, MultiLocation}; /// # fn main() { - /// let mut m = MultiLocation::new(1, X2(Parachain(21), OnlyChild)).unwrap(); - /// assert_eq!(m.append_with(MultiLocation::new(1, X1(PalletInstance(3))).unwrap()), Ok(())); - /// assert_eq!(m, MultiLocation::new(1, X2(Parachain(21), PalletInstance(3))).unwrap()); + /// 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> { @@ -329,35 +294,42 @@ impl MultiLocation { /// ```rust /// # use xcm::v1::{Junctions::*, Junction::*, MultiLocation}; /// # fn main() { - /// let mut m = MultiLocation::new(2, X1(PalletInstance(3))).unwrap(); - /// assert_eq!(m.prepend_with(MultiLocation::new(1, X2(Parachain(21), OnlyChild)).unwrap()), Ok(())); - /// assert_eq!(m, MultiLocation::new(1, X1(PalletInstance(3))).unwrap()); + /// 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> { - let self_parents = self.parent_count(); - let prepend_len = (self_parents as isize - prefix.interior.len() as isize).abs() as usize; - if self.interior.len() + prefix.parent_count() as usize + prepend_len > - MAX_MULTILOCATION_LENGTH - { + // 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) } - let mut final_parent_count = prefix.parents; - for _ in 0..self_parents { - if prefix.take_last().is_none() { - // If true, this means self parent count is greater than prefix junctions length; - // add the resulting self parent count to final_parent_count - final_parent_count += self.parents; - break - } + // 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(); } - self.parents = final_parent_count; + // 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( - "self junctions len + prefix parent count + prepend len is less than max length; qed" + "final_interior no greater than MAX_JUNCTIONS; qed" ); } Ok(()) @@ -485,6 +457,9 @@ impl From<[Junction; 8]> for MultiLocation { } } +/// 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. /// @@ -1157,8 +1132,11 @@ mod tests { // cannot append to create overly long multilocation let acc = AccountIndex64 { network: Any, index: 23 }; - let mut m = MultiLocation { parents: 254, interior: X1(Parachain(42)) }; - let suffix = MultiLocation::from(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)); } @@ -1178,13 +1156,13 @@ mod tests { ); // cannot prepend to create overly long multilocation - let mut m = MultiLocation { parents: 253, interior: X1(Parachain(42)) }; + 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 prefix = MultiLocation { parents: 1, interior: Here }; assert_eq!(m.prepend_with(prefix), Ok(())); - assert_eq!(m, MultiLocation { parents: 254, interior: X1(Parachain(42)) }); + assert_eq!(m, MultiLocation { parents: 255, interior: X1(Parachain(42)) }); } #[test] From cf1482047f8ff592a6ab728fc004ec0f827ffde2 Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Sun, 8 Aug 2021 02:15:46 -0700 Subject: [PATCH 131/166] Add deprecation note for iter_rev and into_iter_rev --- xcm/src/v1/multilocation.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/xcm/src/v1/multilocation.rs b/xcm/src/v1/multilocation.rs index 37055550ea41..685a9430fe79 100644 --- a/xcm/src/v1/multilocation.rs +++ b/xcm/src/v1/multilocation.rs @@ -785,11 +785,13 @@ impl Junctions { } /// Returns a reference iterator over the junctions in reverse. + #[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. + #[deprecated(note = "Please use into_iter().rev()")] pub fn into_iter_rev(self) -> impl Iterator { self.into_iter().rev() } From a2839cf7c5cd1e01a3af94406b3360dd0516ca4f Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Sun, 8 Aug 2021 02:23:01 -0700 Subject: [PATCH 132/166] Update some rustdocs --- xcm/src/v1/multilocation.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/xcm/src/v1/multilocation.rs b/xcm/src/v1/multilocation.rs index 685a9430fe79..465d9a121303 100644 --- a/xcm/src/v1/multilocation.rs +++ b/xcm/src/v1/multilocation.rs @@ -60,13 +60,12 @@ impl Default for MultiLocation { } impl MultiLocation { - /// Creates a new `MultiLocation`, ensuring that the length of it does not exceed the maximum, - /// otherwise returns `Err`. + /// 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 `Null` interior. + /// 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 { @@ -88,7 +87,7 @@ impl MultiLocation { MultiLocation { parents, interior: Junctions::Here } } - /// Whether or not the `MultiLocation` has no parents and has a `Null` interior. + /// 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 } From 4970fff1072f980854660b63646eb028533003a6 Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Sun, 8 Aug 2021 02:24:38 -0700 Subject: [PATCH 133/166] cargo fmt --- xcm/xcm-builder/src/tests.rs | 28 ++++--------------- xcm/xcm-executor/src/traits/transact_asset.rs | 26 +++-------------- 2 files changed, 9 insertions(+), 45 deletions(-) diff --git a/xcm/xcm-builder/src/tests.rs b/xcm/xcm-builder/src/tests.rs index 0a4b966c6acf..df778fe3559d 100644 --- a/xcm/xcm-builder/src/tests.rs +++ b/xcm/xcm-builder/src/tests.rs @@ -20,10 +20,7 @@ use xcm_executor::{traits::*, Config, XcmExecutor}; #[test] fn basic_setup_works() { - add_reserve( - MultiLocation::parent(), - Wild((MultiLocation::parent(), WildFungible).into()), - ); + add_reserve(MultiLocation::parent(), Wild((MultiLocation::parent(), WildFungible).into())); assert!(<TestConfig as Config>::IsReserve::filter_asset_location( &(MultiLocation::parent(), 100).into(), &MultiLocation::parent(), @@ -57,11 +54,7 @@ fn weigher_should_work() { orders: vec![], instructions: vec![], }, - Order::DepositAsset { - assets: All.into(), - max_assets: 1, - beneficiary: Here.into(), - }, + Order::DepositAsset { assets: All.into(), max_assets: 1, beneficiary: Here.into() }, ], } .into(); @@ -155,11 +148,7 @@ fn allow_paid_should_work() { orders: vec![], instructions: vec![], }, - Order::DepositAsset { - assets: All.into(), - max_assets: 1, - beneficiary: Here.into(), - }, + Order::DepositAsset { assets: All.into(), max_assets: 1, beneficiary: Here.into() }, ], }; @@ -184,11 +173,7 @@ fn allow_paid_should_work() { orders: vec![], instructions: vec![], }, - Order::DepositAsset { - assets: All.into(), - max_assets: 1, - beneficiary: Here.into(), - }, + Order::DepositAsset { assets: All.into(), max_assets: 1, beneficiary: Here.into() }, ], }; @@ -214,10 +199,7 @@ fn allow_paid_should_work() { #[test] fn paying_reserve_deposit_should_work() { AllowPaidFrom::set(vec![MultiLocation::parent()]); - add_reserve( - MultiLocation::parent(), - (MultiLocation::parent(), WildFungible).into(), - ); + add_reserve(MultiLocation::parent(), (MultiLocation::parent(), WildFungible).into()); WeightPrice::set((MultiLocation::parent().into(), 1_000_000_000_000)); let origin = MultiLocation::parent(); diff --git a/xcm/xcm-executor/src/traits/transact_asset.rs b/xcm/xcm-executor/src/traits/transact_asset.rs index 9f7adda568b5..c7bac9d9bf09 100644 --- a/xcm/xcm-executor/src/traits/transact_asset.rs +++ b/xcm/xcm-executor/src/traits/transact_asset.rs @@ -272,10 +272,7 @@ mod tests { (UnimplementedTransactor, NotFoundTransactor, UnimplementedTransactor); assert_eq!( - MultiTransactor::deposit_asset( - &(Here.into(), 1).into(), - &Here.into() - ), + MultiTransactor::deposit_asset(&(Here.into(), 1).into(), &Here.into()), Err(XcmError::AssetNotFound) ); } @@ -284,13 +281,7 @@ mod tests { fn unimplemented_and_not_found_continue_iteration() { type MultiTransactor = (UnimplementedTransactor, NotFoundTransactor, SuccessfulTransactor); - assert_eq!( - MultiTransactor::deposit_asset( - &(Here.into(), 1).into(), - &Here.into() - ), - Ok(()), - ); + assert_eq!(MultiTransactor::deposit_asset(&(Here.into(), 1).into(), &Here.into()), Ok(()),); } #[test] @@ -298,10 +289,7 @@ mod tests { type MultiTransactor = (OverflowTransactor, SuccessfulTransactor); assert_eq!( - MultiTransactor::deposit_asset( - &(Here.into(), 1).into(), - &Here.into() - ), + MultiTransactor::deposit_asset(&(Here.into(), 1).into(), &Here.into()), Err(XcmError::Overflow) ); } @@ -310,12 +298,6 @@ mod tests { fn success_stops_iteration() { type MultiTransactor = (SuccessfulTransactor, OverflowTransactor); - assert_eq!( - MultiTransactor::deposit_asset( - &(Here.into(), 1).into(), - &Here.into() - ), - Ok(()), - ); + assert_eq!(MultiTransactor::deposit_asset(&(Here.into(), 1).into(), &Here.into()), Ok(()),); } } From 9644979c0a5c353cd112caf61acb9c3eb90f4990 Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Sun, 8 Aug 2021 02:30:35 -0700 Subject: [PATCH 134/166] Fix xcm-executor unit tests --- xcm/xcm-executor/src/traits/transact_asset.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/xcm/xcm-executor/src/traits/transact_asset.rs b/xcm/xcm-executor/src/traits/transact_asset.rs index c7bac9d9bf09..b46a5e9b8d5e 100644 --- a/xcm/xcm-executor/src/traits/transact_asset.rs +++ b/xcm/xcm-executor/src/traits/transact_asset.rs @@ -193,6 +193,7 @@ impl TransactAsset for Tuple { #[cfg(test)] mod tests { use super::*; + use xcm::latest::Junctions::Here; pub struct UnimplementedTransactor; impl TransactAsset for UnimplementedTransactor {} From a71cb28ce60da02fd3ed8a1b875cb282fe985511 Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Sun, 8 Aug 2021 02:57:21 -0700 Subject: [PATCH 135/166] Fix compilation and unit tests in xcm-builder --- xcm/xcm-builder/src/location_conversion.rs | 38 ++++++++++------------ xcm/xcm-builder/src/mock.rs | 6 ++-- xcm/xcm-builder/src/origin_conversion.rs | 14 ++++---- xcm/xcm-builder/src/tests.rs | 8 ++--- 4 files changed, 32 insertions(+), 34 deletions(-) diff --git a/xcm/xcm-builder/src/location_conversion.rs b/xcm/xcm-builder/src/location_conversion.rs index 7dde7acfe7ee..d1c129998210 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, Junctions, MultiLocation, NetworkId}; +use xcm::latest::{Junction::*, Junctions::*, MultiLocation, NetworkId}; use xcm_executor::traits::{Convert, InvertLocation}; pub struct Account32Hash<Network, AccountId>(PhantomData<(Network, AccountId)>); @@ -65,7 +65,7 @@ impl<ParaId: From<u32> + Into<u32> + AccountIdConversion<AccountId>, AccountId: fn convert_ref(location: impl Borrow<MultiLocation>) -> Result<AccountId, ()> { let location = location.borrow(); match location.interior() { - Junctions::X1(Junction::Parachain(id)) if location.parent_count() == 0 => + X1(Parachain(id)) if location.parent_count() == 0 => Ok(ParaId::from(*id).into_account()), _ => Err(()), } @@ -73,7 +73,7 @@ impl<ParaId: From<u32> + Into<u32> + AccountIdConversion<AccountId>, AccountId: fn reverse_ref(who: impl Borrow<AccountId>) -> Result<MultiLocation, ()> { if let Some(id) = ParaId::try_from_account(who.borrow()) { - Ok(Junction::Parachain(id.into()).into()) + Ok(Parachain(id.into()).into()) } else { Err(()) } @@ -87,7 +87,7 @@ impl<ParaId: From<u32> + Into<u32> + AccountIdConversion<AccountId>, AccountId: fn convert_ref(location: impl Borrow<MultiLocation>) -> Result<AccountId, ()> { let location = location.borrow(); match location.interior() { - Junctions::X1(Junction::Parachain(id)) if location.parent_count() == 1 => + X1(Parachain(id)) if location.parent_count() == 1 => Ok(ParaId::from(*id).into_account()), _ => Err(()), } @@ -95,8 +95,7 @@ impl<ParaId: From<u32> + Into<u32> + AccountIdConversion<AccountId>, AccountId: fn reverse_ref(who: impl Borrow<AccountId>) -> Result<MultiLocation, ()> { if let Some(id) = ParaId::try_from_account(who.borrow()) { - Ok(MultiLocation::new(1, Junctions::X1(Junction::Parachain(id.into()))) - .expect("well-formed MultiLocation; qed")) + Ok(MultiLocation::new(1, X1(Parachain(id.into())))) } else { Err(()) } @@ -110,8 +109,8 @@ impl<Network: Get<NetworkId>, AccountId: From<[u8; 32]> + Into<[u8; 32]> + Clone { fn convert(location: MultiLocation) -> Result<AccountId, MultiLocation> { let id = match (location.parent_count(), location.interior()) { - (0, Junctions::X1(Junction::AccountId32 { id, network: NetworkId::Any })) => *id, - (0, Junctions::X1(Junction::AccountId32 { id, network })) + (0, X1(AccountId32 { id, network: NetworkId::Any })) => *id, + (0, X1(AccountId32 { id, network })) if network == &Network::get() => *id, _ => return Err(location), @@ -120,7 +119,7 @@ impl<Network: Get<NetworkId>, AccountId: From<[u8; 32]> + Into<[u8; 32]> + Clone } fn reverse(who: AccountId) -> Result<MultiLocation, AccountId> { - Ok(Junction::AccountId32 { id: who.into(), network: Network::get() }.into()) + Ok(AccountId32 { id: who.into(), network: Network::get() }.into()) } } @@ -130,8 +129,8 @@ impl<Network: Get<NetworkId>, AccountId: From<[u8; 20]> + Into<[u8; 20]> + Clone { fn convert(location: MultiLocation) -> Result<AccountId, MultiLocation> { let key = match (location.parent_count(), location.interior()) { - (0, Junctions::X1(Junction::AccountKey20 { key, network: NetworkId::Any })) => *key, - (0, Junctions::X1(Junction::AccountKey20 { key, network })) + (0, X1(AccountKey20 { key, network: NetworkId::Any })) => *key, + (0, X1(AccountKey20 { key, network })) if network == &Network::get() => *key, _ => return Err(location), @@ -140,7 +139,7 @@ impl<Network: Get<NetworkId>, AccountId: From<[u8; 20]> + Into<[u8; 20]> + Clone } fn reverse(who: AccountId) -> Result<MultiLocation, AccountId> { - let j = Junction::AccountKey20 { key: who.into(), network: Network::get() }; + let j = AccountKey20 { key: who.into(), network: Network::get() }; Ok(j.into()) } } @@ -169,27 +168,26 @@ impl<Network: Get<NetworkId>, AccountId: From<[u8; 20]> + Into<[u8; 20]> + Clone /// ).into(); /// } /// -/// let input = MultiLocation::new(2, X2(Parachain(2), AccountId32 { network: Any, id: Default::default() })).unwrap(); +/// let input = MultiLocation::new(2, X2(Parachain(2), AccountId32 { network: Any, id: Default::default() })); /// let inverted = LocationInverter::<Ancestry>::invert_location(&input); /// assert_eq!(inverted, MultiLocation::new( /// 2, /// X2(Parachain(1), AccountKey20 { network: Any, key: Default::default() }), -/// ).unwrap()); +/// )); /// # } /// ``` pub struct LocationInverter<Ancestry>(PhantomData<Ancestry>); impl<Ancestry: Get<MultiLocation>> InvertLocation for LocationInverter<Ancestry> { fn invert_location(location: &MultiLocation) -> MultiLocation { let mut ancestry = Ancestry::get(); - let mut junctions = Junctions::Here; + let mut junctions = Here; for _ in 0..location.parent_count() { junctions = junctions - .pushed_with(ancestry.take_first_interior().unwrap_or(Junction::OnlyChild)) + .pushed_with(ancestry.take_first_interior().unwrap_or(OnlyChild)) .expect("ancestry is well-formed and has less than 8 non-parent junctions; qed"); } let parents = location.interior().len() as u8; MultiLocation::new(parents, junctions) - .expect("parents + junctions len must equal location len; qed") } } @@ -198,7 +196,7 @@ mod tests { use super::*; use frame_support::parameter_types; - use xcm::latest::{Junction::*, Junctions::*, MultiLocation, NetworkId::Any}; + use xcm::latest::{Junction, NetworkId::Any}; fn account20() -> Junction { AccountKey20 { network: Any, key: Default::default() } @@ -226,11 +224,11 @@ mod tests { pub Ancestry: MultiLocation = X3(Parachain(1), account20(), account20()).into(); } - let input = MultiLocation::new(3, X2(Parachain(2), account32())).unwrap(); + let input = MultiLocation::new(3, X2(Parachain(2), account32())); let inverted = LocationInverter::<Ancestry>::invert_location(&input); assert_eq!( inverted, - MultiLocation::new(2, X3(Parachain(1), account20(), account20())).unwrap() + MultiLocation::new(2, X3(Parachain(1), account20(), account20())) ); } diff --git a/xcm/xcm-builder/src/mock.rs b/xcm/xcm-builder/src/mock.rs index e290241fcf48..1a4c31fe199e 100644 --- a/xcm/xcm-builder/src/mock.rs +++ b/xcm/xcm-builder/src/mock.rs @@ -152,9 +152,9 @@ pub fn to_account(l: MultiLocation) -> Result<u64, MultiLocation> { // Children at 1000+id X1(Parachain(id)) if l.parent_count() == 0 => 1000 + *id as u64, // Self at 3000 - Null if l.parent_count() == 0 => 3000, + Here if l.parent_count() == 0 => 3000, // Parent at 3001 - Null if l.parent_count() == 1 => 3001, + Here if l.parent_count() == 1 => 3001, _ => return Err(l), }) } @@ -171,7 +171,7 @@ impl ConvertOrigin<TestOrigin> for TestOriginConverter { (SovereignAccount, _) => Ok(TestOrigin::Signed(to_account(origin)?)), (Native, X1(Parachain(id))) if origin.parent_count() == 0 => Ok(TestOrigin::Parachain(*id)), - (Native, Null) if origin.parent_count() == 1 => Ok(TestOrigin::Relay), + (Native, Here) if origin.parent_count() == 1 => Ok(TestOrigin::Relay), (Native, X1(AccountIndex64 { index, .. })) if origin.parent_count() == 0 => Ok(TestOrigin::Signed(*index)), _ => Err(origin), diff --git a/xcm/xcm-builder/src/origin_conversion.rs b/xcm/xcm-builder/src/origin_conversion.rs index f4dfaf65a693..614e2ffd39c3 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, Junctions, 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`. @@ -59,7 +59,7 @@ impl<ParaId: IsSystem + From<u32>, Origin: OriginTrait> ConvertOrigin<Origin> { fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result<Origin, MultiLocation> { match (kind, origin.parent_count(), origin.interior()) { - (OriginKind::Superuser, 0, Junctions::X1(Junction::Parachain(id))) + (OriginKind::Superuser, 0, X1(Junction::Parachain(id))) if ParaId::from(*id).is_system() => Ok(Origin::root()), _ => Err(origin), @@ -73,7 +73,7 @@ impl<ParaId: IsSystem + From<u32>, Origin: OriginTrait> ConvertOrigin<Origin> { fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result<Origin, MultiLocation> { match (kind, origin.parent_count(), origin.interior()) { - (OriginKind::Superuser, 1, Junctions::X1(Junction::Parachain(id))) + (OriginKind::Superuser, 1, X1(Junction::Parachain(id))) if ParaId::from(*id).is_system() => Ok(Origin::root()), _ => Err(origin), @@ -87,7 +87,7 @@ impl<ParachainOrigin: From<u32>, Origin: From<ParachainOrigin>> ConvertOrigin<Or { fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result<Origin, MultiLocation> { match (kind, origin.parent_count(), origin.interior()) { - (OriginKind::Native, 0, Junctions::X1(Junction::Parachain(id))) => + (OriginKind::Native, 0, X1(Junction::Parachain(id))) => Ok(Origin::from(ParachainOrigin::from(*id))), _ => Err(origin), } @@ -102,7 +102,7 @@ impl<ParachainOrigin: From<u32>, Origin: From<ParachainOrigin>> ConvertOrigin<Or { fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result<Origin, MultiLocation> { match (kind, origin.parent_count(), origin.interior()) { - (OriginKind::Native, 1, Junctions::X1(Junction::Parachain(id))) => + (OriginKind::Native, 1, X1(Junction::Parachain(id))) => Ok(Origin::from(ParachainOrigin::from(*id))), _ => Err(origin), } @@ -131,7 +131,7 @@ where { fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result<Origin, MultiLocation> { match (kind, origin.parent_count(), origin.interior()) { - (OriginKind::Native, 0, Junctions::X1(Junction::AccountId32 { id, network })) + (OriginKind::Native, 0, X1(Junction::AccountId32 { id, network })) if matches!(network, NetworkId::Any) || network == &Network::get() => Ok(Origin::signed((*id).into())), _ => Err(origin), @@ -147,7 +147,7 @@ where { fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result<Origin, MultiLocation> { match (kind, origin.parent_count(), origin.interior()) { - (OriginKind::Native, 0, Junctions::X1(Junction::AccountKey20 { key, network })) + (OriginKind::Native, 0, X1(Junction::AccountKey20 { key, network })) if (matches!(network, NetworkId::Any) || network == &Network::get()) => Ok(Origin::signed((*key).into())), _ => Err(origin), diff --git a/xcm/xcm-builder/src/tests.rs b/xcm/xcm-builder/src/tests.rs index df778fe3559d..bf65fd9cf63a 100644 --- a/xcm/xcm-builder/src/tests.rs +++ b/xcm/xcm-builder/src/tests.rs @@ -28,14 +28,14 @@ fn basic_setup_works() { 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))).unwrap()), Ok(2001)); - assert_eq!(to_account(MultiLocation::new(1, X1(Parachain(50))).unwrap()), Ok(2050)); + 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 })).unwrap()), + 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 })).unwrap()), + to_account(MultiLocation::new(0, X1(AccountIndex64 { index: 42, network: Any }))), Ok(42), ); assert_eq!(to_account(Here.into()), Ok(3000)); From 74d4db953ca72e6c271368921b584ff82058660a Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Sun, 8 Aug 2021 03:05:52 -0700 Subject: [PATCH 136/166] cargo fmt --- xcm/xcm-builder/src/location_conversion.rs | 13 +++---------- xcm/xcm-simulator/example/src/parachain.rs | 7 ++----- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/xcm/xcm-builder/src/location_conversion.rs b/xcm/xcm-builder/src/location_conversion.rs index d1c129998210..cf7f87e238a4 100644 --- a/xcm/xcm-builder/src/location_conversion.rs +++ b/xcm/xcm-builder/src/location_conversion.rs @@ -110,9 +110,7 @@ impl<Network: Get<NetworkId>, AccountId: From<[u8; 32]> + Into<[u8; 32]> + Clone fn convert(location: MultiLocation) -> Result<AccountId, MultiLocation> { let id = match (location.parent_count(), location.interior()) { (0, X1(AccountId32 { id, network: NetworkId::Any })) => *id, - (0, X1(AccountId32 { id, network })) - if network == &Network::get() => - *id, + (0, X1(AccountId32 { id, network })) if network == &Network::get() => *id, _ => return Err(location), }; Ok(id.into()) @@ -130,9 +128,7 @@ impl<Network: Get<NetworkId>, AccountId: From<[u8; 20]> + Into<[u8; 20]> + Clone fn convert(location: MultiLocation) -> Result<AccountId, MultiLocation> { let key = match (location.parent_count(), location.interior()) { (0, X1(AccountKey20 { key, network: NetworkId::Any })) => *key, - (0, X1(AccountKey20 { key, network })) - if network == &Network::get() => - *key, + (0, X1(AccountKey20 { key, network })) if network == &Network::get() => *key, _ => return Err(location), }; Ok(key.into()) @@ -226,10 +222,7 @@ mod tests { let input = MultiLocation::new(3, X2(Parachain(2), account32())); let inverted = LocationInverter::<Ancestry>::invert_location(&input); - assert_eq!( - inverted, - MultiLocation::new(2, X3(Parachain(1), account20(), account20())) - ); + assert_eq!(inverted, MultiLocation::new(2, X3(Parachain(1), account20(), account20()))); } // Network Topology diff --git a/xcm/xcm-simulator/example/src/parachain.rs b/xcm/xcm-simulator/example/src/parachain.rs index 2feb89fe499b..6380bebb6fee 100644 --- a/xcm/xcm-simulator/example/src/parachain.rs +++ b/xcm/xcm-simulator/example/src/parachain.rs @@ -266,11 +266,8 @@ pub mod mock_msg_queue { Self::deposit_event(Event::UnsupportedVersion(id)); }, Ok(Ok(x)) => { - let outcome = T::XcmExecutor::execute_xcm( - MultiLocation::parent(), - x, - limit, - ); + let outcome = + T::XcmExecutor::execute_xcm(MultiLocation::parent(), x, limit); Self::deposit_event(Event::ExecutedDownward(id, outcome)); }, } From b72f1272ab1dea4ee5d587b78cdaf0fde35bd78e Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Sun, 8 Aug 2021 03:07:32 -0700 Subject: [PATCH 137/166] Fix tests in xcm-simulator-example --- xcm/xcm-simulator/example/src/lib.rs | 2 +- xcm/xcm-simulator/example/src/parachain.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/xcm/xcm-simulator/example/src/lib.rs b/xcm/xcm-simulator/example/src/lib.rs index cbff1672a544..6e48ecc250bd 100644 --- a/xcm/xcm-simulator/example/src/lib.rs +++ b/xcm/xcm-simulator/example/src/lib.rs @@ -166,7 +166,7 @@ mod tests { ParaA::execute_with(|| { assert_ok!(ParachainPalletXcm::send_xcm( Here.into(), - MultiLocation::new(1, X1(Parachain(2))).unwrap(), + MultiLocation::new(1, X1(Parachain(2))), Transact { origin_type: OriginKind::SovereignAccount, require_weight_at_most: INITIAL_BALANCE as u64, diff --git a/xcm/xcm-simulator/example/src/parachain.rs b/xcm/xcm-simulator/example/src/parachain.rs index 6380bebb6fee..7536a4ccc728 100644 --- a/xcm/xcm-simulator/example/src/parachain.rs +++ b/xcm/xcm-simulator/example/src/parachain.rs @@ -210,7 +210,7 @@ pub mod mock_msg_queue { let hash = Encode::using_encoded(&xcm, T::Hashing::hash); let (result, event) = match Xcm::<T::Call>::try_from(xcm) { Ok(xcm) => { - let location = MultiLocation::new(1, X1(Parachain(sender.into()))).unwrap(); + 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))), From 1112e0e7a2430ad758e59b358aaa60313d879726 Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Sun, 8 Aug 2021 03:08:15 -0700 Subject: [PATCH 138/166] Publicize MultiLocation fields --- xcm/src/v1/multilocation.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/xcm/src/v1/multilocation.rs b/xcm/src/v1/multilocation.rs index 465d9a121303..ed56cf8afb1c 100644 --- a/xcm/src/v1/multilocation.rs +++ b/xcm/src/v1/multilocation.rs @@ -21,7 +21,7 @@ use core::{ convert::{TryFrom, TryInto}, mem, result, }; -use parity_scale_codec::{self, Decode, Encode}; +use parity_scale_codec::{Decode, Encode}; /// A relative path between state-bearing consensus systems. /// @@ -48,9 +48,9 @@ use parity_scale_codec::{self, Decode, Encode}; #[derive(Clone, Decode, Encode, Eq, PartialEq, Ord, PartialOrd, Debug)] pub struct MultiLocation { /// The number of parent junctions at the beginning of this `MultiLocation`. - pub(crate) parents: u8, + pub parents: u8, /// The interior (i.e. non-parent) junctions that this `MultiLocation` contains. - pub(crate) interior: Junctions, + pub interior: Junctions, } impl Default for MultiLocation { From b444e2354983728fbd2bb2de82fffbc24b273b72 Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Sun, 8 Aug 2021 04:16:37 -0700 Subject: [PATCH 139/166] Match on the MultiLocation struct directly in xcm-builder --- xcm/src/v1/junction.rs | 2 +- xcm/src/v1/multilocation.rs | 7 +-- xcm/xcm-builder/src/location_conversion.rs | 32 +++++++---- xcm/xcm-builder/src/mock.rs | 20 +++---- xcm/xcm-builder/src/origin_conversion.rs | 66 +++++++++++++--------- 5 files changed, 72 insertions(+), 55 deletions(-) diff --git a/xcm/src/v1/junction.rs b/xcm/src/v1/junction.rs index ff820610dab8..cbf9419e64d9 100644 --- a/xcm/src/v1/junction.rs +++ b/xcm/src/v1/junction.rs @@ -16,11 +16,11 @@ //! Support data structures for `MultiLocation`, primarily the `Junction` datatype. +use super::{Junctions, MultiLocation}; use crate::v0::{BodyId as BodyId0, Junction as Junction0}; use alloc::vec::Vec; use core::convert::TryFrom; use parity_scale_codec::{self, Decode, Encode}; -use super::{MultiLocation, Junctions}; /// A global identifier of an account-bearing consensus system. #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug)] diff --git a/xcm/src/v1/multilocation.rs b/xcm/src/v1/multilocation.rs index ed56cf8afb1c..5c58ce8418e9 100644 --- a/xcm/src/v1/multilocation.rs +++ b/xcm/src/v1/multilocation.rs @@ -327,9 +327,8 @@ impl MultiLocation { 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" - ); + self.push_front_interior(j) + .expect("final_interior no greater than MAX_JUNCTIONS; qed"); } Ok(()) } @@ -1135,7 +1134,7 @@ mod tests { let acc = AccountIndex64 { network: Any, index: 23 }; let mut m = MultiLocation { parents: 254, - interior: X5(Parachain(42), OnlyChild, OnlyChild, OnlyChild, OnlyChild) + 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)); diff --git a/xcm/xcm-builder/src/location_conversion.rs b/xcm/xcm-builder/src/location_conversion.rs index cf7f87e238a4..5f8363c1546f 100644 --- a/xcm/xcm-builder/src/location_conversion.rs +++ b/xcm/xcm-builder/src/location_conversion.rs @@ -63,9 +63,8 @@ impl<ParaId: From<u32> + Into<u32> + AccountIdConversion<AccountId>, AccountId: Convert<MultiLocation, AccountId> for ChildParachainConvertsVia<ParaId, AccountId> { fn convert_ref(location: impl Borrow<MultiLocation>) -> Result<AccountId, ()> { - let location = location.borrow(); - match location.interior() { - X1(Parachain(id)) if location.parent_count() == 0 => + match location.borrow() { + MultiLocation { parents: 0, interior: X1(Parachain(id)) } => Ok(ParaId::from(*id).into_account()), _ => Err(()), } @@ -85,9 +84,8 @@ impl<ParaId: From<u32> + Into<u32> + AccountIdConversion<AccountId>, AccountId: Convert<MultiLocation, AccountId> for SiblingParachainConvertsVia<ParaId, AccountId> { fn convert_ref(location: impl Borrow<MultiLocation>) -> Result<AccountId, ()> { - let location = location.borrow(); - match location.interior() { - X1(Parachain(id)) if location.parent_count() == 1 => + match location.borrow() { + MultiLocation { parents: 1, interior: X1(Parachain(id)) } => Ok(ParaId::from(*id).into_account()), _ => Err(()), } @@ -108,9 +106,14 @@ impl<Network: Get<NetworkId>, AccountId: From<[u8; 32]> + Into<[u8; 32]> + Clone Convert<MultiLocation, AccountId> for AccountId32Aliases<Network, AccountId> { fn convert(location: MultiLocation) -> Result<AccountId, MultiLocation> { - let id = match (location.parent_count(), location.interior()) { - (0, X1(AccountId32 { id, network: NetworkId::Any })) => *id, - (0, X1(AccountId32 { id, network })) if network == &Network::get() => *id, + let id = match location { + MultiLocation { + parents: 0, + interior: X1(AccountId32 { id, network: NetworkId::Any }), + } => id, + MultiLocation { parents: 0, interior: X1(AccountId32 { id, network }) } + if network == Network::get() => + id, _ => return Err(location), }; Ok(id.into()) @@ -126,9 +129,14 @@ impl<Network: Get<NetworkId>, AccountId: From<[u8; 20]> + Into<[u8; 20]> + Clone Convert<MultiLocation, AccountId> for AccountKey20Aliases<Network, AccountId> { fn convert(location: MultiLocation) -> Result<AccountId, MultiLocation> { - let key = match (location.parent_count(), location.interior()) { - (0, X1(AccountKey20 { key, network: NetworkId::Any })) => *key, - (0, X1(AccountKey20 { key, network })) if network == &Network::get() => *key, + let key = match location { + MultiLocation { + parents: 0, + interior: X1(AccountKey20 { key, network: NetworkId::Any }), + } => key, + MultiLocation { parents: 0, interior: X1(AccountKey20 { key, network }) } + if network == Network::get() => + key, _ => return Err(location), }; Ok(key.into()) diff --git a/xcm/xcm-builder/src/mock.rs b/xcm/xcm-builder/src/mock.rs index 1a4c31fe199e..1db39793619c 100644 --- a/xcm/xcm-builder/src/mock.rs +++ b/xcm/xcm-builder/src/mock.rs @@ -144,17 +144,17 @@ impl TransactAsset for TestAssetTransactor { } pub fn to_account(l: MultiLocation) -> Result<u64, MultiLocation> { - Ok(match l.interior() { + Ok(match l { // Siblings at 2000+id - X1(Parachain(id)) if l.parent_count() == 1 => 2000 + *id as u64, + MultiLocation { parents: 1, interior: X1(Parachain(id)) } => 2000 + id as u64, // Accounts are their number - X1(AccountIndex64 { index, .. }) if l.parent_count() == 0 => *index, + MultiLocation { parents: 0, interior: X1(AccountIndex64 { index, .. }) } => index, // Children at 1000+id - X1(Parachain(id)) if l.parent_count() == 0 => 1000 + *id as u64, + MultiLocation { parents: 0, interior: X1(Parachain(id)) } => 1000 + id as u64, // Self at 3000 - Here if l.parent_count() == 0 => 3000, + MultiLocation { parents: 0, interior: Here } => 3000, // Parent at 3001 - Here if l.parent_count() == 1 => 3001, + MultiLocation { parents: 1, interior: Here } => 3001, _ => return Err(l), }) } @@ -166,13 +166,13 @@ impl ConvertOrigin<TestOrigin> for TestOriginConverter { kind: OriginKind, ) -> Result<TestOrigin, MultiLocation> { use OriginKind::*; - match (kind, origin.interior()) { + match (kind, origin) { (Superuser, _) => Ok(TestOrigin::Root), (SovereignAccount, _) => Ok(TestOrigin::Signed(to_account(origin)?)), - (Native, X1(Parachain(id))) if origin.parent_count() == 0 => + (Native, MultiLocation { parents: 0, interior: X1(Parachain(id)) }) => Ok(TestOrigin::Parachain(*id)), - (Native, Here) if origin.parent_count() == 1 => Ok(TestOrigin::Relay), - (Native, X1(AccountIndex64 { index, .. })) if origin.parent_count() == 0 => + (Native, MultiLocation { parents: 1, interior: Here }) => Ok(TestOrigin::Relay), + (Native, MultiLocation { parents: 0, interior: X1(AccountIndex64 { index, .. }) }) => Ok(TestOrigin::Signed(*index)), _ => Err(origin), } diff --git a/xcm/xcm-builder/src/origin_conversion.rs b/xcm/xcm-builder/src/origin_conversion.rs index 614e2ffd39c3..b1800de2c6c8 100644 --- a/xcm/xcm-builder/src/origin_conversion.rs +++ b/xcm/xcm-builder/src/origin_conversion.rs @@ -58,11 +58,12 @@ impl<ParaId: IsSystem + From<u32>, Origin: OriginTrait> ConvertOrigin<Origin> for ChildSystemParachainAsSuperuser<ParaId, Origin> { fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result<Origin, MultiLocation> { - match (kind, origin.parent_count(), origin.interior()) { - (OriginKind::Superuser, 0, X1(Junction::Parachain(id))) - if ParaId::from(*id).is_system() => - Ok(Origin::root()), - _ => Err(origin), + match (kind, origin) { + ( + OriginKind::Superuser, + MultiLocation { parents: 0, interior: X1(Junction::Parachain(id)) }, + ) if ParaId::from(id).is_system() => Ok(Origin::root()), + (_, origin) => Err(origin), } } } @@ -72,11 +73,12 @@ impl<ParaId: IsSystem + From<u32>, Origin: OriginTrait> ConvertOrigin<Origin> for SiblingSystemParachainAsSuperuser<ParaId, Origin> { fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result<Origin, MultiLocation> { - match (kind, origin.parent_count(), origin.interior()) { - (OriginKind::Superuser, 1, X1(Junction::Parachain(id))) - if ParaId::from(*id).is_system() => - Ok(Origin::root()), - _ => Err(origin), + match (kind, origin) { + ( + OriginKind::Superuser, + MultiLocation { parents: 1, interior: X1(Junction::Parachain(id)) }, + ) if ParaId::from(id).is_system() => Ok(Origin::root()), + (_, origin) => Err(origin), } } } @@ -86,10 +88,12 @@ impl<ParachainOrigin: From<u32>, Origin: From<ParachainOrigin>> ConvertOrigin<Or for ChildParachainAsNative<ParachainOrigin, Origin> { fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result<Origin, MultiLocation> { - match (kind, origin.parent_count(), origin.interior()) { - (OriginKind::Native, 0, X1(Junction::Parachain(id))) => - Ok(Origin::from(ParachainOrigin::from(*id))), - _ => Err(origin), + match (kind, origin) { + ( + OriginKind::Native, + MultiLocation { parents: 0, interior: X1(Junction::Parachain(id)) }, + ) => Ok(Origin::from(ParachainOrigin::from(id))), + (_, origin) => Err(origin), } } } @@ -101,10 +105,12 @@ impl<ParachainOrigin: From<u32>, Origin: From<ParachainOrigin>> ConvertOrigin<Or for SiblingParachainAsNative<ParachainOrigin, Origin> { fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result<Origin, MultiLocation> { - match (kind, origin.parent_count(), origin.interior()) { - (OriginKind::Native, 1, X1(Junction::Parachain(id))) => - Ok(Origin::from(ParachainOrigin::from(*id))), - _ => Err(origin), + match (kind, origin) { + ( + OriginKind::Native, + MultiLocation { parents: 1, interior: X1(Junction::Parachain(id)) }, + ) => Ok(Origin::from(ParachainOrigin::from(id))), + (_, origin) => Err(origin), } } } @@ -130,11 +136,13 @@ where Origin::AccountId: From<[u8; 32]>, { fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result<Origin, MultiLocation> { - match (kind, origin.parent_count(), origin.interior()) { - (OriginKind::Native, 0, X1(Junction::AccountId32 { id, network })) - if matches!(network, NetworkId::Any) || network == &Network::get() => - Ok(Origin::signed((*id).into())), - _ => Err(origin), + match (kind, origin) { + ( + 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,11 +154,13 @@ where Origin::AccountId: From<[u8; 20]>, { fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result<Origin, MultiLocation> { - match (kind, origin.parent_count(), origin.interior()) { - (OriginKind::Native, 0, X1(Junction::AccountKey20 { key, network })) - if (matches!(network, NetworkId::Any) || network == &Network::get()) => - Ok(Origin::signed((*key).into())), - _ => Err(origin), + match (kind, origin) { + ( + 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), } } } From cdbaccc0a4739b5daad94589925631b969f5b0a0 Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Sun, 8 Aug 2021 04:34:18 -0700 Subject: [PATCH 140/166] Do not dereference undereferenceable types --- xcm/xcm-builder/src/mock.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xcm/xcm-builder/src/mock.rs b/xcm/xcm-builder/src/mock.rs index 1db39793619c..47150685f851 100644 --- a/xcm/xcm-builder/src/mock.rs +++ b/xcm/xcm-builder/src/mock.rs @@ -170,10 +170,10 @@ impl ConvertOrigin<TestOrigin> for TestOriginConverter { (Superuser, _) => Ok(TestOrigin::Root), (SovereignAccount, _) => Ok(TestOrigin::Signed(to_account(origin)?)), (Native, MultiLocation { parents: 0, interior: X1(Parachain(id)) }) => - Ok(TestOrigin::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)), + Ok(TestOrigin::Signed(index)), _ => Err(origin), } } From 18a82ecde21c855ae87c7a3f5e839e5ccb2cc041 Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Sun, 8 Aug 2021 04:55:31 -0700 Subject: [PATCH 141/166] Add convenience MultiLocation conversions for tuples --- xcm/src/v1/multilocation.rs | 91 +++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/xcm/src/v1/multilocation.rs b/xcm/src/v1/multilocation.rs index 5c58ce8418e9..4d9cb0d2d4b8 100644 --- a/xcm/src/v1/multilocation.rs +++ b/xcm/src/v1/multilocation.rs @@ -340,6 +340,12 @@ impl From<Junctions> for MultiLocation { } } +impl From<(u8, Junctions)> for MultiLocation { + fn from((parents, interior): (u8, Junctions)) -> Self { + MultiLocation { parents, interior } + } +} + impl From<Junction> for MultiLocation { fn from(x: Junction) -> Self { MultiLocation { parents: 0, interior: Junctions::X1(x) } @@ -401,6 +407,91 @@ impl From<(Junction, Junction, Junction, Junction, Junction, Junction, Junction, } } +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 { parents: 0, interior: Junctions::Here } From d82fb6bf4f1a19f86bc4c000ab579ac5a94f65a5 Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Sun, 8 Aug 2021 05:10:58 -0700 Subject: [PATCH 142/166] Use clearer import paths --- xcm/src/v0/multi_location.rs | 4 ++-- xcm/src/v1/multilocation.rs | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/xcm/src/v0/multi_location.rs b/xcm/src/v0/multi_location.rs index 9e9514539621..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 super::Junction; +use crate::v1::MultiLocation as MultiLocation1; use core::{convert::TryFrom, mem, result}; - -use super::{super::v1::MultiLocation as MultiLocation1, Junction}; use parity_scale_codec::{self, Decode, Encode}; /// A relative path between state-bearing consensus systems. diff --git a/xcm/src/v1/multilocation.rs b/xcm/src/v1/multilocation.rs index 4d9cb0d2d4b8..e333e70e494e 100644 --- a/xcm/src/v1/multilocation.rs +++ b/xcm/src/v1/multilocation.rs @@ -16,7 +16,8 @@ //! Cross-Consensus Message format data structures. -use super::{super::v0::MultiLocation as MultiLocation0, Junction}; +use super::Junction; +use crate::v0::MultiLocation as MultiLocation0; use core::{ convert::{TryFrom, TryInto}, mem, result, From 2281325a580dc7bb00af1392d4f16d03a6ee59b9 Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Sun, 8 Aug 2021 05:11:51 -0700 Subject: [PATCH 143/166] Remove unused dependency --- Cargo.lock | 1 - xcm/Cargo.toml | 1 - 2 files changed, 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f9a7c97a4ac8..83554af1c532 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12267,7 +12267,6 @@ dependencies = [ "impl-trait-for-tuples", "log", "parity-scale-codec", - "static_assertions", ] [[package]] diff --git a/xcm/Cargo.toml b/xcm/Cargo.toml index 67865f32f929..a1bfa76130a7 100644 --- a/xcm/Cargo.toml +++ b/xcm/Cargo.toml @@ -10,7 +10,6 @@ impl-trait-for-tuples = "0.2.0" parity-scale-codec = { version = "2.0.0", default-features = false, features = [ "derive" ] } derivative = {version = "2.2.0", default-features = false, features = [ "use_core" ] } log = { version = "0.4.14", default-features = false } -static_assertions = "1.1.0" [features] default = ["std"] From fe78be8bbd5880c0ce6c6308dc33c9cc97572a6c Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi <shawntabrizi@gmail.com> Date: Sun, 8 Aug 2021 14:36:37 +0200 Subject: [PATCH 144/166] fix junction + response --- xcm/src/{v1 => v0}/junction.rs | 0 xcm/src/v0/mod.rs | 48 +++++++++++++++++++++++++++++++--- xcm/src/v1/mod.rs | 44 ++++++++++--------------------- 3 files changed, 59 insertions(+), 33 deletions(-) rename xcm/src/{v1 => v0}/junction.rs (100%) diff --git a/xcm/src/v1/junction.rs b/xcm/src/v0/junction.rs similarity index 100% rename from xcm/src/v1/junction.rs rename to xcm/src/v0/junction.rs diff --git a/xcm/src/v0/mod.rs b/xcm/src/v0/mod.rs index ad2f70e31cf5..626353abf275 100644 --- a/xcm/src/v0/mod.rs +++ b/xcm/src/v0/mod.rs @@ -25,11 +25,13 @@ use core::{ use derivative::Derivative; use parity_scale_codec::{self, Decode, Encode}; +mod junction; mod multi_asset; mod multi_location; mod order; mod traits; -use super::v1::Xcm as Xcm1; +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 order::Order; @@ -52,7 +54,38 @@ pub mod prelude { }; } -pub use super::v1::{BodyId, BodyPart, Junction, NetworkId, OriginKind, Response}; +// TODO: #2841 #XCMENCODE Efficient encodings for MultiAssets, Vec<Order>, using initial byte values 128+ to encode +// the number of items in the vector. + +/// Basically just the XCM (more general) version of `ParachainDispatchOrigin`. +#[derive(Copy, Clone, Eq, PartialEq, Encode, Decode, Debug)] +pub enum OriginKind { + /// Origin should just be the native dispatch origin representation for the sender in the + /// local runtime framework. For Cumulus/Frame chains this is the `Parachain` or `Relay` origin + /// if coming from a chain, though there may be others if the `MultiLocation` XCM origin has a + /// primary/native dispatch origin form. + Native, + + /// Origin should just be the standard account-based origin with the sovereign account of + /// the sender. For Cumulus/Frame chains, this is the `Signed` origin. + SovereignAccount, + + /// Origin should be the super-user. For Cumulus/Frame chains, this is the `Root` origin. + /// This will not usually be an available option. + Superuser, + + /// Origin should be interpreted as an XCM native origin and the `MultiLocation` should be + /// encoded directly in the dispatch origin unchanged. For Cumulus/Frame chains, this will be + /// the `pallet_xcm::Origin::Xcm` type. + Xcm, +} + +/// Response data to a query. +#[derive(Clone, Eq, PartialEq, Encode, Decode, Debug)] +pub enum Response { + /// Some assets. + Assets(Vec<MultiAsset>), +} /// Cross-Consensus Message: A message from one consensus system to another. /// @@ -287,6 +320,15 @@ pub mod opaque { pub use super::order::opaque::*; } +// Convert from a v1 response to a v0 response +impl From<Response1> for Response { + fn from(new_response: Response1) -> Self { + match new_response { + Response1::Assets(assets) => Self::Assets(assets.into()), + } + } +} + impl<Call> TryFrom<Xcm1<Call>> for Xcm<Call> { type Error = (); fn try_from(x: Xcm1<Call>) -> result::Result<Xcm<Call>, ()> { @@ -314,7 +356,7 @@ impl<Call> TryFrom<Xcm1<Call>> for Xcm<Call> { .collect::<result::Result<_, _>>()?, }, Xcm1::QueryResponse { query_id: u64, response } => - QueryResponse { query_id: u64, response }, + QueryResponse { query_id: u64, response: response.into() }, Xcm1::TransferAsset { assets, beneficiary } => TransferAsset { assets: assets.into(), dest: beneficiary.into() }, Xcm1::TransferReserveAsset { assets, dest, effects } => TransferReserveAsset { diff --git a/xcm/src/v1/mod.rs b/xcm/src/v1/mod.rs index 6b7b4d4f2aea..2933c03cdfe9 100644 --- a/xcm/src/v1/mod.rs +++ b/xcm/src/v1/mod.rs @@ -16,7 +16,7 @@ //! Version 1 of the Cross-Consensus Message format data structures. -use super::v0::Xcm as Xcm0; +use super::v0::{Response as Response0, Xcm as Xcm0}; use crate::DoubleEncoded; use alloc::vec::Vec; use core::{ @@ -27,13 +27,11 @@ 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::{BodyId, BodyPart, Junction, NetworkId}; pub use multiasset::{ AssetId, AssetInstance, Fungibility, MultiAsset, MultiAssetFilter, MultiAssets, WildFungibility, WildMultiAsset, @@ -45,7 +43,7 @@ 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::{ + super::v0::{ BodyId, BodyPart, Junction::*, NetworkId::{self, *}, @@ -69,31 +67,7 @@ pub mod prelude { }; } -// TODO: #2841 #XCMENCODE Efficient encodings for MultiAssets, Vec<Order>, using initial byte values 128+ to encode -// the number of items in the vector. - -/// Basically just the XCM (more general) version of `ParachainDispatchOrigin`. -#[derive(Copy, Clone, Eq, PartialEq, Encode, Decode, Debug)] -pub enum OriginKind { - /// Origin should just be the native dispatch origin representation for the sender in the - /// local runtime framework. For Cumulus/Frame chains this is the `Parachain` or `Relay` origin - /// if coming from a chain, though there may be others if the `MultiLocation` XCM origin has a - /// primary/native dispatch origin form. - Native, - - /// Origin should just be the standard account-based origin with the sovereign account of - /// the sender. For Cumulus/Frame chains, this is the `Signed` origin. - SovereignAccount, - - /// Origin should be the super-user. For Cumulus/Frame chains, this is the `Root` origin. - /// This will not usually be an available option. - Superuser, - - /// Origin should be interpreted as an XCM native origin and the `MultiLocation` should be - /// encoded directly in the dispatch origin unchanged. For Cumulus/Frame chains, this will be - /// the `pallet_xcm::Origin::Xcm` type. - Xcm, -} +pub use super::v0::{BodyId, BodyPart, Junction, NetworkId, OriginKind}; /// Response data to a query. #[derive(Clone, Eq, PartialEq, Encode, Decode, Debug)] @@ -338,6 +312,16 @@ pub mod opaque { pub use super::order::opaque::*; } +// Convert from a v0 response to a v1 response +impl TryFrom<Response0> for Response { + type Error = (); + fn try_from(old_response: Response0) -> result::Result<Self, ()> { + match old_response { + Response0::Assets(assets) => Ok(Self::Assets(assets.try_into()?)), + } + } +} + impl<Call> TryFrom<Xcm0<Call>> for Xcm<Call> { type Error = (); fn try_from(old: Xcm0<Call>) -> result::Result<Xcm<Call>, ()> { @@ -365,7 +349,7 @@ impl<Call> TryFrom<Xcm0<Call>> for Xcm<Call> { .collect::<result::Result<_, _>>()?, }, Xcm0::QueryResponse { query_id: u64, response } => - 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() }, Xcm0::TransferReserveAsset { assets, dest, effects } => TransferReserveAsset { From 5d581055818a77c0a8cf851a53313d71765a880e Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Sun, 8 Aug 2021 06:19:39 -0700 Subject: [PATCH 145/166] Import from latest opaque xcm module --- runtime/common/src/xcm_sender.rs | 14 +++++--------- xcm/xcm-builder/src/mock.rs | 2 +- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/runtime/common/src/xcm_sender.rs b/runtime/common/src/xcm_sender.rs index aa190296904f..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, Junctions, MultiLocation, Result, SendXcm, Xcm}; +use xcm::opaque::latest::*; /// XCM sender for relay chain. It only sends downward message. pub struct ChildParachainRouter<T, W>(PhantomData<(T, W)>); @@ -28,25 +28,21 @@ impl<T: configuration::Config + dmp::Config, W: xcm::WrapVersion> SendXcm for ChildParachainRouter<T, W> { fn send_xcm(dest: MultiLocation, msg: Xcm) -> Result { - if dest.parent_count() > 0 { - return Err(Error::CannotReachDestination(dest, msg)) - } - - match dest.interior() { - Junctions::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 = <configuration::Pallet<T>>::config(); <dmp::Pallet<T>>::queue_downward_message( &config, - (*id).into(), + id.into(), versioned_xcm.encode(), ) .map_err(Into::<Error>::into)?; Ok(()) }, - _ => Err(Error::CannotReachDestination(dest, msg)), + dest => Err(Error::CannotReachDestination(dest, msg)), } } } diff --git a/xcm/xcm-builder/src/mock.rs b/xcm/xcm-builder/src/mock.rs index 47150685f851..f7ebbc8a1cd8 100644 --- a/xcm/xcm-builder/src/mock.rs +++ b/xcm/xcm-builder/src/mock.rs @@ -168,7 +168,7 @@ impl ConvertOrigin<TestOrigin> for TestOriginConverter { use OriginKind::*; match (kind, origin) { (Superuser, _) => Ok(TestOrigin::Root), - (SovereignAccount, _) => Ok(TestOrigin::Signed(to_account(origin)?)), + (SovereignAccount, l) => Ok(TestOrigin::Signed(to_account(l)?)), (Native, MultiLocation { parents: 0, interior: X1(Parachain(id)) }) => Ok(TestOrigin::Parachain(id)), (Native, MultiLocation { parents: 1, interior: Here }) => Ok(TestOrigin::Relay), From 1ab9719f0ce063fce55d4a8b283adc429a833ef4 Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi <shawntabrizi@gmail.com> Date: Sun, 8 Aug 2021 16:13:45 +0200 Subject: [PATCH 146/166] Update xcm/src/v1/mod.rs --- xcm/src/v1/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/xcm/src/v1/mod.rs b/xcm/src/v1/mod.rs index 2933c03cdfe9..a8921ce1dd35 100644 --- a/xcm/src/v1/mod.rs +++ b/xcm/src/v1/mod.rs @@ -43,6 +43,7 @@ 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::{ + // These parts of XCM v0 have been unchanged in XCM v1 super::v0::{ BodyId, BodyPart, Junction::*, From 7d6dabac7b0ab3f2865836aeaeff9992dc15e637 Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi <shawntabrizi@gmail.com> Date: Sun, 8 Aug 2021 16:15:53 +0200 Subject: [PATCH 147/166] better comment --- xcm/src/v1/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/xcm/src/v1/mod.rs b/xcm/src/v1/mod.rs index a8921ce1dd35..94bdef024af9 100644 --- a/xcm/src/v1/mod.rs +++ b/xcm/src/v1/mod.rs @@ -40,10 +40,12 @@ pub use multilocation::MultiLocation; 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}; + /// A prelude for importing all types typically used when interacting with XCM messages. pub mod prelude { pub use super::{ - // These parts of XCM v0 have been unchanged in XCM v1 super::v0::{ BodyId, BodyPart, Junction::*, @@ -68,8 +70,6 @@ pub mod prelude { }; } -pub use super::v0::{BodyId, BodyPart, Junction, NetworkId, OriginKind}; - /// Response data to a query. #[derive(Clone, Eq, PartialEq, Encode, Decode, Debug)] pub enum Response { From dbc412b4328d768e1fa2121dd92d082ae7bc2c24 Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Sun, 8 Aug 2021 07:37:32 -0700 Subject: [PATCH 148/166] Fix ownership transfer --- xcm/xcm-builder/src/mock.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xcm/xcm-builder/src/mock.rs b/xcm/xcm-builder/src/mock.rs index f7ebbc8a1cd8..2e6237e7528a 100644 --- a/xcm/xcm-builder/src/mock.rs +++ b/xcm/xcm-builder/src/mock.rs @@ -174,7 +174,7 @@ impl ConvertOrigin<TestOrigin> for TestOriginConverter { (Native, MultiLocation { parents: 1, interior: Here }) => Ok(TestOrigin::Relay), (Native, MultiLocation { parents: 0, interior: X1(AccountIndex64 { index, .. }) }) => Ok(TestOrigin::Signed(index)), - _ => Err(origin), + (_, origin) => Err(origin), } } } From 7727c4b09d235dfe0c68d7342404ccf0ddeefa32 Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Sun, 8 Aug 2021 07:56:48 -0700 Subject: [PATCH 149/166] Fix merge --- runtime/test-runtime/src/xcm_config.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/runtime/test-runtime/src/xcm_config.rs b/runtime/test-runtime/src/xcm_config.rs index a87e8730c746..0ebb555a5a0c 100644 --- a/runtime/test-runtime/src/xcm_config.rs +++ b/runtime/test-runtime/src/xcm_config.rs @@ -16,8 +16,8 @@ use frame_support::{parameter_types, traits::Everything, weights::Weight}; use xcm::latest::{ - Error as XcmError, Junction::*, MultiAsset, MultiLocation, MultiLocation::*, NetworkId, - Result as XcmResult, SendXcm, Xcm, + Error as XcmError, Junction::*, MultiAsset, MultiLocation, NetworkId, Result as XcmResult, + SendXcm, Xcm, }; use xcm_builder::{AllowUnpaidExecutionFrom, FixedWeightBounds, SignedToAccountId32}; use xcm_executor::{ @@ -52,7 +52,7 @@ impl TransactAsset for DummyAssetTransactor { } fn withdraw_asset(_what: &MultiAsset, _who: &MultiLocation) -> Result<Assets, XcmError> { - let asset: MultiAsset = (X1(Parent), 100_000).into(); + let asset: MultiAsset = (MultiLocation::parent(), 100_000).into(); Ok(asset.into()) } } From e6a2160bc201359fa28eaade25ad01b8d557500c Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Sun, 8 Aug 2021 08:47:10 -0700 Subject: [PATCH 150/166] Fix merge --- runtime/test-runtime/src/xcm_config.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/runtime/test-runtime/src/xcm_config.rs b/runtime/test-runtime/src/xcm_config.rs index 0ebb555a5a0c..ae89d96e6d76 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, NetworkId, Result as XcmResult, + Error as XcmError, MultiAsset, MultiLocation, NetworkId, Result as XcmResult, SendXcm, Xcm, }; use xcm_builder::{AllowUnpaidExecutionFrom, FixedWeightBounds, SignedToAccountId32}; @@ -71,7 +71,7 @@ impl WeightTrader for DummyWeightTrader { pub struct InvertNothing; impl InvertLocation for InvertNothing { fn invert_location(_: &MultiLocation) -> MultiLocation { - MultiLocation::Here + MultiLocation::here() } } From aa4933398444aea4b05a3695c97b410242b06e3f Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Sun, 8 Aug 2021 08:57:30 -0700 Subject: [PATCH 151/166] cargo fmt --- runtime/test-runtime/src/xcm_config.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/runtime/test-runtime/src/xcm_config.rs b/runtime/test-runtime/src/xcm_config.rs index ae89d96e6d76..b9ea1318ae0f 100644 --- a/runtime/test-runtime/src/xcm_config.rs +++ b/runtime/test-runtime/src/xcm_config.rs @@ -16,8 +16,7 @@ use frame_support::{parameter_types, traits::Everything, weights::Weight}; use xcm::latest::{ - Error as XcmError, MultiAsset, MultiLocation, NetworkId, Result as XcmResult, - SendXcm, Xcm, + Error as XcmError, MultiAsset, MultiLocation, NetworkId, Result as XcmResult, SendXcm, Xcm, }; use xcm_builder::{AllowUnpaidExecutionFrom, FixedWeightBounds, SignedToAccountId32}; use xcm_executor::{ From c3c000530fa00c3774011341599241265aa5bd7d Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Sun, 8 Aug 2021 09:42:31 -0700 Subject: [PATCH 152/166] Fix merge --- xcm/src/v1/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xcm/src/v1/mod.rs b/xcm/src/v1/mod.rs index 2f4f125e7887..bf9b4c890f87 100644 --- a/xcm/src/v1/mod.rs +++ b/xcm/src/v1/mod.rs @@ -50,9 +50,9 @@ pub mod prelude { pub use super::{ super::v0::{ BodyId, BodyPart, - Junction::*, NetworkId::{self, *}, }, + junction::Junction::*, multiasset::{ AssetId::{self, *}, AssetInstance::{self, *}, From 15f83c326652349cece9061f25753416afd2560f Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Sun, 8 Aug 2021 09:43:32 -0700 Subject: [PATCH 153/166] Fix merge --- xcm/src/v1/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xcm/src/v1/mod.rs b/xcm/src/v1/mod.rs index bf9b4c890f87..da616896b8dc 100644 --- a/xcm/src/v1/mod.rs +++ b/xcm/src/v1/mod.rs @@ -52,7 +52,7 @@ pub mod prelude { BodyId, BodyPart, NetworkId::{self, *}, }, - junction::Junction::*, + junction::Junction::{self, *}, multiasset::{ AssetId::{self, *}, AssetInstance::{self, *}, From d73fd905d98a2f022dd6b784a5041694ff0b256b Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Sun, 8 Aug 2021 10:09:09 -0700 Subject: [PATCH 154/166] Fix integration test --- xcm/xcm-executor/integration-tests/src/lib.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/xcm/xcm-executor/integration-tests/src/lib.rs b/xcm/xcm-executor/integration-tests/src/lib.rs index 209b44b8981e..c1b2b6b31072 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::{Error as XcmError, MultiLocation, Order, Outcome, Xcm::*}; 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: (MultiLocation::parent(), 100).into(), effects: vec![] }; for _ in 0..MAX_RECURSION_CHECK { msg = WithdrawAsset { - assets: (X1(Parent), 100).into(), + assets: (MultiLocation::parent(), 100).into(), effects: vec![Order::BuyExecution { - fees: (X1(Parent), 1).into(), + fees: (MultiLocation::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: (MultiLocation::parent(), 100).into(), effects: vec![] }; for _ in 0..(MAX_RECURSION_CHECK + 1) { msg = WithdrawAsset { - assets: (X1(Parent), 100).into(), + assets: (MultiLocation::parent(), 100).into(), effects: vec![Order::BuyExecution { - fees: (X1(Parent), 1).into(), + fees: (MultiLocation::parent(), 1).into(), weight: 0, debt: 0, halt_on_error: true, From 1a1708c78c0ffa42c3c5900d50ee91d1e6d59b36 Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Mon, 9 Aug 2021 13:03:12 +0200 Subject: [PATCH 155/166] More readable Parent syntax --- runtime/test-runtime/src/xcm_config.rs | 4 +- xcm/pallet-xcm/src/tests.rs | 12 +-- xcm/src/v1/mod.rs | 4 +- xcm/src/v1/multiasset.rs | 14 +--- xcm/src/v1/multilocation.rs | 34 +++++++- xcm/src/v1/traits.rs | 2 +- xcm/xcm-builder/src/currency_adapter.rs | 2 +- xcm/xcm-builder/src/location_conversion.rs | 4 +- xcm/xcm-builder/src/matches_fungible.rs | 4 +- xcm/xcm-builder/src/mock.rs | 2 +- xcm/xcm-builder/src/tests.rs | 80 +++++++++---------- xcm/xcm-executor/integration-tests/src/lib.rs | 14 ++-- xcm/xcm-simulator/example/src/lib.rs | 2 +- xcm/xcm-simulator/example/src/parachain.rs | 4 +- 14 files changed, 104 insertions(+), 78 deletions(-) diff --git a/runtime/test-runtime/src/xcm_config.rs b/runtime/test-runtime/src/xcm_config.rs index b9ea1318ae0f..8466d49445f8 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, MultiAsset, MultiLocation, NetworkId, Result as XcmResult, SendXcm, Xcm, + Error as XcmError, MultiAsset, MultiLocation, NetworkId, Result as XcmResult, SendXcm, Xcm, Parent, }; use xcm_builder::{AllowUnpaidExecutionFrom, FixedWeightBounds, SignedToAccountId32}; use xcm_executor::{ @@ -51,7 +51,7 @@ impl TransactAsset for DummyAssetTransactor { } fn withdraw_asset(_what: &MultiAsset, _who: &MultiLocation) -> Result<Assets, XcmError> { - let asset: MultiAsset = (MultiLocation::parent(), 100_000).into(); + let asset: MultiAsset = (Parent, 100_000).into(); Ok(asset.into()) } } diff --git a/xcm/pallet-xcm/src/tests.rs b/xcm/pallet-xcm/src/tests.rs index 5bd3eb69f5ff..2d8ef67c0e00 100644 --- a/xcm/pallet-xcm/src/tests.rs +++ b/xcm/pallet-xcm/src/tests.rs @@ -40,9 +40,9 @@ fn send_works() { let sender: MultiLocation = AccountId32 { network: AnyNetwork::get(), id: ALICE.into() }.into(); let message = Xcm::ReserveAssetDeposited { - assets: (MultiLocation::parent(), SEND_AMOUNT).into(), + assets: (Parent, SEND_AMOUNT).into(), effects: vec![ - buy_execution((MultiLocation::parent(), SEND_AMOUNT), weight), + buy_execution((Parent, SEND_AMOUNT), weight), DepositAsset { assets: All.into(), max_assets: 1, beneficiary: sender.clone() }, ], }; @@ -78,9 +78,9 @@ fn send_fails_when_xcm_router_blocks() { let sender: MultiLocation = Junction::AccountId32 { network: AnyNetwork::get(), id: ALICE.into() }.into(); let message = Xcm::ReserveAssetDeposited { - assets: (MultiLocation::parent(), SEND_AMOUNT).into(), + assets: (Parent, SEND_AMOUNT).into(), effects: vec![ - buy_execution((MultiLocation::parent(), SEND_AMOUNT), weight), + buy_execution((Parent, SEND_AMOUNT), weight), DepositAsset { assets: All.into(), max_assets: 1, beneficiary: sender.clone() }, ], }; @@ -153,9 +153,9 @@ fn reserve_transfer_assets_works() { vec![( Parachain(PARA_ID).into(), Xcm::ReserveAssetDeposited { - assets: (MultiLocation::parent(), SEND_AMOUNT).into(), + assets: (Parent, SEND_AMOUNT).into(), effects: vec![ - buy_execution((MultiLocation::parent(), SEND_AMOUNT), weight), + buy_execution((Parent, SEND_AMOUNT), weight), DepositAsset { assets: All.into(), max_assets: 1, beneficiary: dest }, ] } diff --git a/xcm/src/v1/mod.rs b/xcm/src/v1/mod.rs index da616896b8dc..ad2fa40a9123 100644 --- a/xcm/src/v1/mod.rs +++ b/xcm/src/v1/mod.rs @@ -38,7 +38,7 @@ pub use multiasset::{ AssetId, AssetInstance, Fungibility, MultiAsset, MultiAssetFilter, MultiAssets, WildFungibility, WildMultiAsset, }; -pub use multilocation::{Junctions, MultiLocation}; +pub use multilocation::{Junctions, MultiLocation, Parent, ParentThen, Ancestor, AncestorThen}; pub use order::Order; pub use traits::{Error, ExecuteXcm, Outcome, Result, SendXcm}; @@ -65,7 +65,7 @@ pub mod prelude { }, multilocation::{ Junctions::{self, *}, - MultiLocation, + MultiLocation, Parent, ParentThen, Ancestor, AncestorThen, }, opaque, order::Order::{self, *}, diff --git a/xcm/src/v1/multiasset.rs b/xcm/src/v1/multiasset.rs index b1bb2b98d9d4..9d4fa945edff 100644 --- a/xcm/src/v1/multiasset.rs +++ b/xcm/src/v1/multiasset.rs @@ -23,7 +23,7 @@ //! - `MultiAssetFilter`: A combination of `Wild` and `MultiAssets` designed for efficiently filtering an XCM holding //! account. -use super::{Junction, Junctions::X1, MultiLocation}; +use super::MultiLocation; use alloc::{vec, vec::Vec}; use core::{ cmp::Ordering, @@ -101,15 +101,9 @@ pub enum AssetId { Abstract(Vec<u8>), } -impl From<MultiLocation> for AssetId { - fn from(x: MultiLocation) -> Self { - Self::Concrete(x) - } -} - -impl From<Junction> for AssetId { - fn from(x: Junction) -> Self { - Self::Concrete(X1(x).into()) +impl<T: Into<MultiLocation>> From<T> for AssetId { + fn from(x: T) -> Self { + Self::Concrete(x.into()) } } diff --git a/xcm/src/v1/multilocation.rs b/xcm/src/v1/multilocation.rs index e333e70e494e..165d1941956c 100644 --- a/xcm/src/v1/multilocation.rs +++ b/xcm/src/v1/multilocation.rs @@ -335,6 +335,38 @@ impl MultiLocation { } } +/// A unit struct which can be converted into a `MultiLocation` of `parents` value 1. +pub struct Parent; +impl From<Parent> for MultiLocation { + fn from(_: Parent) -> Self { + MultiLocation { parents: 1, interior: Junctions::Here } + } +} + +/// A tuple struct which can be converted into a `MultiLocation` of `parents` value 1 with the inner interior. +pub struct ParentThen(Junctions); +impl From<ParentThen> 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<Ancestor> 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<AncestorThen> for MultiLocation { + fn from(x: AncestorThen) -> Self { + MultiLocation { parents: x.0, interior: x.1 } + } +} + impl From<Junctions> for MultiLocation { fn from(junctions: Junctions) -> Self { MultiLocation { parents: 0, interior: junctions } @@ -928,7 +960,7 @@ impl TryFrom<MultiLocation0> for MultiLocation { use Junctions::*; match old { MultiLocation0::Null => Ok(Here.into()), - MultiLocation0::X1(j0) if j0.is_parent() => Ok(MultiLocation::parent()), + 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()), diff --git a/xcm/src/v1/traits.rs b/xcm/src/v1/traits.rs index 1632408c5846..13c5f3cda0cf 100644 --- a/xcm/src/v1/traits.rs +++ b/xcm/src/v1/traits.rs @@ -231,7 +231,7 @@ impl<C> ExecuteXcm<C> for () { /// # fn main() { /// let call: Vec<u8> = ().encode(); /// let message = Xcm::Transact { origin_type: OriginKind::Superuser, require_weight_at_most: 0, call: call.into() }; -/// let destination = MultiLocation::parent(); +/// let destination = Parent.into(); /// /// assert!( /// // Sender2 will block this. diff --git a/xcm/xcm-builder/src/currency_adapter.rs b/xcm/xcm-builder/src/currency_adapter.rs index cd6e03c365db..feea36707684 100644 --- a/xcm/xcm-builder/src/currency_adapter.rs +++ b/xcm/xcm-builder/src/currency_adapter.rs @@ -61,7 +61,7 @@ impl From<Error> for XcmError { /// /// /// Our relay chain's location. /// parameter_types! { -/// RelayChain: MultiLocation = MultiLocation::parent(); +/// RelayChain: MultiLocation = Parent.into(); /// CheckingAccount: AccountId = Default::default(); /// } /// diff --git a/xcm/xcm-builder/src/location_conversion.rs b/xcm/xcm-builder/src/location_conversion.rs index 5f8363c1546f..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::*, Junctions::*, MultiLocation, NetworkId}; +use xcm::latest::{Junction::*, Junctions::*, MultiLocation, NetworkId, Parent}; use xcm_executor::traits::{Convert, InvertLocation}; pub struct Account32Hash<Network, AccountId>(PhantomData<(Network, AccountId)>); @@ -51,7 +51,7 @@ impl<AccountId: Default + Eq + Clone> Convert<MultiLocation, AccountId> fn reverse_ref(who: impl Borrow<AccountId>) -> Result<MultiLocation, ()> { if who.borrow() == &AccountId::default() { - Ok(MultiLocation::parent()) + Ok(Parent.into()) } else { Err(()) } diff --git a/xcm/xcm-builder/src/matches_fungible.rs b/xcm/xcm-builder/src/matches_fungible.rs index e14fcdaa9409..accb4aa75256 100644 --- a/xcm/xcm-builder/src/matches_fungible.rs +++ b/xcm/xcm-builder/src/matches_fungible.rs @@ -37,11 +37,11 @@ use xcm_executor::traits::MatchesFungible; /// use xcm_executor::traits::MatchesFungible; /// /// frame_support::parameter_types! { -/// pub TargetLocation: MultiLocation = MultiLocation::parent(); +/// pub TargetLocation: MultiLocation = Parent.into(); /// } /// /// # fn main() { -/// let asset = (MultiLocation::parent(), 999).into(); +/// let asset = (Parent, 999).into(); /// // match `asset` if it is a concrete asset in `TargetLocation`. /// assert_eq!(<IsConcrete<TargetLocation> as MatchesFungible<u128>>::matches_fungible(&asset), Some(999)); /// # } diff --git a/xcm/xcm-builder/src/mock.rs b/xcm/xcm-builder/src/mock.rs index 2e6237e7528a..21ce7d26ccf5 100644 --- a/xcm/xcm-builder/src/mock.rs +++ b/xcm/xcm-builder/src/mock.rs @@ -257,7 +257,7 @@ parameter_types! { pub static AllowUnpaidFrom: Vec<MultiLocation> = vec![]; pub static AllowPaidFrom: Vec<MultiLocation> = vec![]; // 1_000_000_000_000 => 1 unit of asset for 1 unit of Weight. - pub static WeightPrice: (AssetId, u128) = (Here.into().into(), 1_000_000_000_000); + pub static WeightPrice: (AssetId, u128) = (AssetId::from(Here), 1_000_000_000_000); } pub type TestBarrier = ( diff --git a/xcm/xcm-builder/src/tests.rs b/xcm/xcm-builder/src/tests.rs index bf65fd9cf63a..d56b0ffb0538 100644 --- a/xcm/xcm-builder/src/tests.rs +++ b/xcm/xcm-builder/src/tests.rs @@ -20,10 +20,10 @@ use xcm_executor::{traits::*, Config, XcmExecutor}; #[test] fn basic_setup_works() { - add_reserve(MultiLocation::parent(), Wild((MultiLocation::parent(), WildFungible).into())); + add_reserve(Parent.into(), Wild((Parent, WildFungible).into())); assert!(<TestConfig as Config>::IsReserve::filter_asset_location( - &(MultiLocation::parent(), 100).into(), - &MultiLocation::parent(), + &(Parent, 100).into(), + &Parent.into(), )); assert_eq!(to_account(X1(Parachain(1)).into()), Ok(1001)); @@ -44,10 +44,10 @@ fn basic_setup_works() { #[test] fn weigher_should_work() { let mut message = opaque::Xcm::ReserveAssetDeposited { - assets: (MultiLocation::parent(), 100).into(), + assets: (Parent, 100).into(), effects: vec![ Order::BuyExecution { - fees: (MultiLocation::parent(), 1).into(), + fees: (Parent, 1).into(), weight: 0, debt: 30, halt_on_error: true, @@ -64,13 +64,13 @@ fn weigher_should_work() { #[test] fn take_weight_credit_barrier_should_work() { let mut message = opaque::Xcm::TransferAsset { - assets: (MultiLocation::parent(), 100).into(), + assets: (Parent, 100).into(), beneficiary: Here.into(), }; let mut weight_credit = 10; let r = TakeWeightCredit::should_execute( - &MultiLocation::parent(), + &Parent.into(), true, &mut message, 10, @@ -80,7 +80,7 @@ fn take_weight_credit_barrier_should_work() { assert_eq!(weight_credit, 0); let r = TakeWeightCredit::should_execute( - &MultiLocation::parent(), + &Parent.into(), true, &mut message, 10, @@ -93,11 +93,11 @@ fn take_weight_credit_barrier_should_work() { #[test] fn allow_unpaid_should_work() { let mut message = opaque::Xcm::TransferAsset { - assets: (MultiLocation::parent(), 100).into(), + assets: (Parent, 100).into(), beneficiary: Here.into(), }; - AllowUnpaidFrom::set(vec![MultiLocation::parent()]); + AllowUnpaidFrom::set(vec![Parent.into()]); let r = AllowUnpaidExecutionFrom::<IsInVec<AllowUnpaidFrom>>::should_execute( &X1(Parachain(1)).into(), @@ -109,7 +109,7 @@ fn allow_unpaid_should_work() { assert_eq!(r, Err(())); let r = AllowUnpaidExecutionFrom::<IsInVec<AllowUnpaidFrom>>::should_execute( - &MultiLocation::parent(), + &Parent.into(), true, &mut message, 10, @@ -120,10 +120,10 @@ fn allow_unpaid_should_work() { #[test] fn allow_paid_should_work() { - AllowPaidFrom::set(vec![MultiLocation::parent()]); + AllowPaidFrom::set(vec![Parent.into()]); let mut message = opaque::Xcm::TransferAsset { - assets: (MultiLocation::parent(), 100).into(), + assets: (Parent, 100).into(), beneficiary: Here.into(), }; @@ -136,9 +136,9 @@ fn allow_paid_should_work() { ); assert_eq!(r, Err(())); - let fees = (MultiLocation::parent(), 1).into(); + let fees = (Parent, 1).into(); let mut underpaying_message = opaque::Xcm::ReserveAssetDeposited { - assets: (MultiLocation::parent(), 100).into(), + assets: (Parent, 100).into(), effects: vec![ Order::BuyExecution { fees, @@ -153,7 +153,7 @@ fn allow_paid_should_work() { }; let r = AllowTopLevelPaidExecutionFrom::<IsInVec<AllowPaidFrom>>::should_execute( - &MultiLocation::parent(), + &Parent.into(), true, &mut underpaying_message, 30, @@ -161,9 +161,9 @@ fn allow_paid_should_work() { ); assert_eq!(r, Err(())); - let fees = (MultiLocation::parent(), 1).into(); + let fees = (Parent, 1).into(); let mut paying_message = opaque::Xcm::ReserveAssetDeposited { - assets: (MultiLocation::parent(), 100).into(), + assets: (Parent, 100).into(), effects: vec![ Order::BuyExecution { fees, @@ -187,7 +187,7 @@ fn allow_paid_should_work() { assert_eq!(r, Err(())); let r = AllowTopLevelPaidExecutionFrom::<IsInVec<AllowPaidFrom>>::should_execute( - &MultiLocation::parent(), + &Parent.into(), true, &mut paying_message, 30, @@ -198,14 +198,14 @@ fn allow_paid_should_work() { #[test] fn paying_reserve_deposit_should_work() { - AllowPaidFrom::set(vec![MultiLocation::parent()]); - add_reserve(MultiLocation::parent(), (MultiLocation::parent(), WildFungible).into()); - WeightPrice::set((MultiLocation::parent().into(), 1_000_000_000_000)); + AllowPaidFrom::set(vec![Parent.into()]); + add_reserve(Parent.into(), (Parent, WildFungible).into()); + WeightPrice::set((Parent.into(), 1_000_000_000_000)); - let origin = MultiLocation::parent(); - let fees = (MultiLocation::parent(), 30).into(); + let origin = Parent.into(); + let fees = (Parent, 30).into(); let message = Xcm::<TestCall>::ReserveAssetDeposited { - assets: (MultiLocation::parent(), 100).into(), + assets: (Parent, 100).into(), effects: vec![ Order::<TestCall>::BuyExecution { fees, @@ -225,7 +225,7 @@ fn paying_reserve_deposit_should_work() { let weight_limit = 50; let r = XcmExecutor::<TestConfig>::execute_xcm(origin, message, weight_limit); assert_eq!(r, Outcome::Complete(30)); - assert_eq!(assets(3000), vec![(MultiLocation::parent(), 70).into()]); + assert_eq!(assets(3000), vec![(Parent, 70).into()]); } #[test] @@ -280,7 +280,7 @@ fn reserve_transfer_should_work() { vec![( X1(Parachain(2)).into(), Xcm::ReserveAssetDeposited { - assets: (MultiLocation::parent(), 100).into(), + assets: (Parent, 100).into(), effects: vec![Order::DepositAsset { assets: All.into(), max_assets: 1, @@ -293,9 +293,9 @@ fn reserve_transfer_should_work() { #[test] fn transacting_should_work() { - AllowUnpaidFrom::set(vec![MultiLocation::parent()]); + AllowUnpaidFrom::set(vec![Parent.into()]); - let origin = MultiLocation::parent(); + let origin = Parent.into(); let message = Xcm::<TestCall>::Transact { origin_type: OriginKind::Native, require_weight_at_most: 50, @@ -308,9 +308,9 @@ fn transacting_should_work() { #[test] fn transacting_should_respect_max_weight_requirement() { - AllowUnpaidFrom::set(vec![MultiLocation::parent()]); + AllowUnpaidFrom::set(vec![Parent.into()]); - let origin = MultiLocation::parent(); + let origin = Parent.into(); let message = Xcm::<TestCall>::Transact { origin_type: OriginKind::Native, require_weight_at_most: 40, @@ -323,9 +323,9 @@ fn transacting_should_respect_max_weight_requirement() { #[test] fn transacting_should_refund_weight() { - AllowUnpaidFrom::set(vec![MultiLocation::parent()]); + AllowUnpaidFrom::set(vec![Parent.into()]); - let origin = MultiLocation::parent(); + let origin = Parent.into(); let message = Xcm::<TestCall>::Transact { origin_type: OriginKind::Native, require_weight_at_most: 50, @@ -340,13 +340,13 @@ fn transacting_should_refund_weight() { fn paid_transacting_should_refund_payment_for_unused_weight() { let one: MultiLocation = X1(AccountIndex64 { index: 1, network: Any }).into(); AllowPaidFrom::set(vec![one.clone()]); - add_asset(1, (MultiLocation::parent(), 100).into()); - WeightPrice::set((MultiLocation::parent().into(), 1_000_000_000_000)); + add_asset(1, (Parent, 100).into()); + WeightPrice::set((Parent.into(), 1_000_000_000_000)); let origin = one.clone(); - let fees = (MultiLocation::parent(), 100).into(); + let fees = (Parent, 100).into(); let message = Xcm::<TestCall>::WithdrawAsset { - assets: (MultiLocation::parent(), 100).into(), // enough for 100 units of weight. + assets: (Parent, 100).into(), // enough for 100 units of weight. effects: vec![ Order::<TestCall>::BuyExecution { fees, @@ -371,17 +371,17 @@ fn paid_transacting_should_refund_payment_for_unused_weight() { let weight_limit = 100; let r = XcmExecutor::<TestConfig>::execute_xcm(origin, message, weight_limit); assert_eq!(r, Outcome::Complete(50)); - assert_eq!(assets(1), vec![(MultiLocation::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 = MultiLocation::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((MultiLocation::parent(), 100).into()); + let the_response = Response::Assets((Parent, 100).into()); let message = Xcm::<TestCall>::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 c1b2b6b31072..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, 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: (MultiLocation::parent(), 100).into(), effects: vec![] }; + let mut msg = WithdrawAsset { assets: (Parent, 100).into(), effects: vec![] }; for _ in 0..MAX_RECURSION_CHECK { msg = WithdrawAsset { - assets: (MultiLocation::parent(), 100).into(), + assets: (Parent, 100).into(), effects: vec![Order::BuyExecution { - fees: (MultiLocation::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: (MultiLocation::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: (MultiLocation::parent(), 100).into(), + assets: (Parent, 100).into(), effects: vec![Order::BuyExecution { - fees: (MultiLocation::parent(), 1).into(), + fees: (Parent, 1).into(), weight: 0, debt: 0, halt_on_error: true, diff --git a/xcm/xcm-simulator/example/src/lib.rs b/xcm/xcm-simulator/example/src/lib.rs index 6e48ecc250bd..fd17891c1820 100644 --- a/xcm/xcm-simulator/example/src/lib.rs +++ b/xcm/xcm-simulator/example/src/lib.rs @@ -139,7 +139,7 @@ mod tests { ParaA::execute_with(|| { assert_ok!(ParachainPalletXcm::send_xcm( Here.into(), - MultiLocation::parent(), + Parent.into(), Transact { origin_type: OriginKind::SovereignAccount, require_weight_at_most: INITIAL_BALANCE as u64, diff --git a/xcm/xcm-simulator/example/src/parachain.rs b/xcm/xcm-simulator/example/src/parachain.rs index 3ff3ea1e540b..87fe111e57a6 100644 --- a/xcm/xcm-simulator/example/src/parachain.rs +++ b/xcm/xcm-simulator/example/src/parachain.rs @@ -120,7 +120,7 @@ pub type XcmOriginToCallOrigin = ( parameter_types! { pub const UnitWeightCost: Weight = 1; - pub KsmPerSecond: (AssetId, u128) = (Concrete(MultiLocation::parent()), 1); + pub KsmPerSecond: (AssetId, u128) = (Concrete(Parent.into()), 1); } pub type LocalAssetTransactor = @@ -267,7 +267,7 @@ pub mod mock_msg_queue { }, Ok(Ok(x)) => { let outcome = - T::XcmExecutor::execute_xcm(MultiLocation::parent(), x, limit); + T::XcmExecutor::execute_xcm(Parent.into(), x, limit); Self::deposit_event(Event::ExecutedDownward(id, outcome)); }, } From 102b9d9707751ce4751a8772a04529a43507fd31 Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Mon, 9 Aug 2021 13:10:08 +0200 Subject: [PATCH 156/166] cleanup --- runtime/kusama/src/lib.rs | 4 ++-- runtime/rococo/src/lib.rs | 4 ++-- runtime/westend/src/lib.rs | 4 ++-- xcm/pallet-xcm/src/mock.rs | 4 ++-- xcm/xcm-simulator/example/src/relay_chain.rs | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/runtime/kusama/src/lib.rs b/runtime/kusama/src/lib.rs index fdbf7ccdecfa..3a57fd3b2750 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 = Here.into(); + pub const KsmLocation: MultiLocation = Here; /// 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 = Here.into(); + pub const Ancestry: MultiLocation = Here; /// The check account, which holds any native assets that have been teleported out and not back in (yet). pub CheckAccount: AccountId = XcmPallet::check_account(); } diff --git a/runtime/rococo/src/lib.rs b/runtime/rococo/src/lib.rs index b0f412eb1c68..0a3afd96c8b2 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 = Here.into(); + pub const RocLocation: MultiLocation = Here; pub const RococoNetwork: NetworkId = NetworkId::Polkadot; - pub const Ancestry: MultiLocation = Here.into(); + pub const Ancestry: MultiLocation = Here; pub CheckAccount: AccountId = XcmPallet::check_account(); } diff --git a/runtime/westend/src/lib.rs b/runtime/westend/src/lib.rs index 93fd23c48f08..e54d6c0136b3 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 = Here.into(); - pub const Ancestry: MultiLocation = Here.into(); + pub const WndLocation: MultiLocation = Here; + pub const Ancestry: MultiLocation = Here; pub WestendNetwork: NetworkId = NetworkId::Named(b"Westend".to_vec()); pub CheckAccount: AccountId = XcmPallet::check_account(); } diff --git a/xcm/pallet-xcm/src/mock.rs b/xcm/pallet-xcm/src/mock.rs index 4dd6537cc1d7..6cd2768fc5a8 100644 --- a/xcm/pallet-xcm/src/mock.rs +++ b/xcm/pallet-xcm/src/mock.rs @@ -129,9 +129,9 @@ impl pallet_balances::Config for Test { } parameter_types! { - pub const RelayLocation: MultiLocation = Here.into(); + pub const RelayLocation: MultiLocation = Here; pub const AnyNetwork: NetworkId = NetworkId::Any; - pub Ancestry: MultiLocation = Here.into(); + pub Ancestry: MultiLocation = Here; pub UnitWeightCost: Weight = 1_000; } diff --git a/xcm/xcm-simulator/example/src/relay_chain.rs b/xcm/xcm-simulator/example/src/relay_chain.rs index 8dd543d428fd..b20e2d5204cb 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 = Here.into(); + pub const KsmLocation: MultiLocation = Here; pub const KusamaNetwork: NetworkId = NetworkId::Kusama; pub const AnyNetwork: NetworkId = NetworkId::Any; - pub Ancestry: MultiLocation = Here.into(); + pub Ancestry: MultiLocation = Here; pub UnitWeightCost: Weight = 1_000; } From 36b10f376d08aae08b7657b93be2650d6f8db864 Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Mon, 9 Aug 2021 13:12:35 +0200 Subject: [PATCH 157/166] cleanup --- runtime/kusama/src/lib.rs | 4 ++-- runtime/rococo/src/lib.rs | 4 ++-- runtime/test-runtime/src/xcm_config.rs | 2 +- runtime/westend/src/lib.rs | 4 ++-- xcm/pallet-xcm/src/mock.rs | 4 ++-- xcm/xcm-simulator/example/src/relay_chain.rs | 4 ++-- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/runtime/kusama/src/lib.rs b/runtime/kusama/src/lib.rs index 3a57fd3b2750..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 = 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 = 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(); } diff --git a/runtime/rococo/src/lib.rs b/runtime/rococo/src/lib.rs index 0a3afd96c8b2..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 = Here; + pub const RocLocation: MultiLocation = Here.into(); pub const RococoNetwork: NetworkId = NetworkId::Polkadot; - pub const Ancestry: MultiLocation = Here; + pub const Ancestry: MultiLocation = Here.into(); pub CheckAccount: AccountId = XcmPallet::check_account(); } diff --git a/runtime/test-runtime/src/xcm_config.rs b/runtime/test-runtime/src/xcm_config.rs index 8466d49445f8..5355e03c9184 100644 --- a/runtime/test-runtime/src/xcm_config.rs +++ b/runtime/test-runtime/src/xcm_config.rs @@ -70,7 +70,7 @@ impl WeightTrader for DummyWeightTrader { pub struct InvertNothing; impl InvertLocation for InvertNothing { fn invert_location(_: &MultiLocation) -> MultiLocation { - MultiLocation::here() + Junction::Here.into() } } diff --git a/runtime/westend/src/lib.rs b/runtime/westend/src/lib.rs index e54d6c0136b3..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 = Here; - pub const Ancestry: 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(); } diff --git a/xcm/pallet-xcm/src/mock.rs b/xcm/pallet-xcm/src/mock.rs index 6cd2768fc5a8..4dd6537cc1d7 100644 --- a/xcm/pallet-xcm/src/mock.rs +++ b/xcm/pallet-xcm/src/mock.rs @@ -129,9 +129,9 @@ impl pallet_balances::Config for Test { } parameter_types! { - pub const RelayLocation: MultiLocation = Here; + pub const RelayLocation: MultiLocation = Here.into(); pub const AnyNetwork: NetworkId = NetworkId::Any; - pub Ancestry: MultiLocation = Here; + pub Ancestry: MultiLocation = Here.into(); pub UnitWeightCost: Weight = 1_000; } diff --git a/xcm/xcm-simulator/example/src/relay_chain.rs b/xcm/xcm-simulator/example/src/relay_chain.rs index b20e2d5204cb..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 = Here; + pub const KsmLocation: MultiLocation = Here.into(); pub const KusamaNetwork: NetworkId = NetworkId::Kusama; pub const AnyNetwork: NetworkId = NetworkId::Any; - pub Ancestry: MultiLocation = Here; + pub Ancestry: MultiLocation = Here.into(); pub UnitWeightCost: Weight = 1_000; } From 92c97853fc526f3f3327a5fbc18c4e9d24d4c352 Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Mon, 9 Aug 2021 13:13:29 +0200 Subject: [PATCH 158/166] cleanup --- runtime/test-runtime/src/xcm_config.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/runtime/test-runtime/src/xcm_config.rs b/runtime/test-runtime/src/xcm_config.rs index 5355e03c9184..caa313b8c6ff 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, MultiAsset, MultiLocation, NetworkId, Result as XcmResult, SendXcm, Xcm, Parent, + Error as XcmError, MultiAsset, MultiLocation, NetworkId, Result as XcmResult, SendXcm, Xcm, Parent, Junction::Here, }; use xcm_builder::{AllowUnpaidExecutionFrom, FixedWeightBounds, SignedToAccountId32}; use xcm_executor::{ @@ -70,7 +70,7 @@ impl WeightTrader for DummyWeightTrader { pub struct InvertNothing; impl InvertLocation for InvertNothing { fn invert_location(_: &MultiLocation) -> MultiLocation { - Junction::Here.into() + Here.into() } } From 30c404c5a6bb89185cef6e45bfd9f956c11ce096 Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Mon, 9 Aug 2021 13:18:37 +0200 Subject: [PATCH 159/166] cleanup --- runtime/test-runtime/src/xcm_config.rs | 2 +- xcm/pallet-xcm/src/tests.rs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/runtime/test-runtime/src/xcm_config.rs b/runtime/test-runtime/src/xcm_config.rs index caa313b8c6ff..7380f68584b1 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, MultiAsset, MultiLocation, NetworkId, Result as XcmResult, SendXcm, Xcm, Parent, Junction::Here, + Error as XcmError, MultiAsset, MultiLocation, NetworkId, Result as XcmResult, SendXcm, Xcm, Parent, Junctions::Here, }; use xcm_builder::{AllowUnpaidExecutionFrom, FixedWeightBounds, SignedToAccountId32}; use xcm_executor::{ diff --git a/xcm/pallet-xcm/src/tests.rs b/xcm/pallet-xcm/src/tests.rs index 2d8ef67c0e00..424adb7caba8 100644 --- a/xcm/pallet-xcm/src/tests.rs +++ b/xcm/pallet-xcm/src/tests.rs @@ -110,7 +110,7 @@ fn teleport_assets_works() { Origin::signed(ALICE), Box::new(RelayLocation::get()), Box::new(AccountId32 { network: Any, id: BOB.into() }.into()), - (Here.into(), SEND_AMOUNT).into(), + (Here, SEND_AMOUNT).into(), 0, weight, )); @@ -139,7 +139,7 @@ fn reserve_transfer_assets_works() { Origin::signed(ALICE), Box::new(Parachain(PARA_ID).into()), Box::new(dest.clone()), - (Here.into(), SEND_AMOUNT).into(), + (Here, SEND_AMOUNT).into(), 0, weight )); @@ -184,7 +184,7 @@ fn execute_withdraw_to_deposit_works() { assert_ok!(XcmPallet::execute( Origin::signed(ALICE), Box::new(Xcm::WithdrawAsset { - assets: (Here.into(), SEND_AMOUNT).into(), + assets: (Here, SEND_AMOUNT).into(), effects: vec![ buy_execution((Here.into(), SEND_AMOUNT), weight), DepositAsset { assets: All.into(), max_assets: 1, beneficiary: dest } From 4e9f95830b5ace7984cb5c5f09b835f016f58f05 Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Mon, 9 Aug 2021 13:19:55 +0200 Subject: [PATCH 160/166] cleanup --- xcm/pallet-xcm/src/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xcm/pallet-xcm/src/tests.rs b/xcm/pallet-xcm/src/tests.rs index 424adb7caba8..1e9d9acb42dc 100644 --- a/xcm/pallet-xcm/src/tests.rs +++ b/xcm/pallet-xcm/src/tests.rs @@ -186,7 +186,7 @@ fn execute_withdraw_to_deposit_works() { Box::new(Xcm::WithdrawAsset { assets: (Here, SEND_AMOUNT).into(), effects: vec![ - buy_execution((Here.into(), SEND_AMOUNT), weight), + buy_execution((Here, SEND_AMOUNT), weight), DepositAsset { assets: All.into(), max_assets: 1, beneficiary: dest } ], }), From 52c0621dc0e4bd4c6ace4cb8b7236909b0bc36c9 Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Mon, 9 Aug 2021 13:24:12 +0200 Subject: [PATCH 161/166] cleanup --- xcm/xcm-builder/src/mock.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xcm/xcm-builder/src/mock.rs b/xcm/xcm-builder/src/mock.rs index 21ce7d26ccf5..7c1e93a2b9dd 100644 --- a/xcm/xcm-builder/src/mock.rs +++ b/xcm/xcm-builder/src/mock.rs @@ -257,7 +257,7 @@ parameter_types! { pub static AllowUnpaidFrom: Vec<MultiLocation> = vec![]; pub static AllowPaidFrom: Vec<MultiLocation> = vec![]; // 1_000_000_000_000 => 1 unit of asset for 1 unit of Weight. - pub static WeightPrice: (AssetId, u128) = (AssetId::from(Here), 1_000_000_000_000); + pub static WeightPrice: (AssetId, u128) = (From::from(Here), 1_000_000_000_000); } pub type TestBarrier = ( From 623039b36636fc26add89d5add18b74c7573b0d5 Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Mon, 9 Aug 2021 13:30:22 +0200 Subject: [PATCH 162/166] cleanup --- xcm/xcm-builder/src/tests.rs | 14 +++++++------- xcm/xcm-executor/src/assets.rs | 18 +++++++++--------- xcm/xcm-executor/src/traits/transact_asset.rs | 8 ++++---- xcm/xcm-simulator/example/src/lib.rs | 2 +- 4 files changed, 21 insertions(+), 21 deletions(-) diff --git a/xcm/xcm-builder/src/tests.rs b/xcm/xcm-builder/src/tests.rs index d56b0ffb0538..0db2424b90b6 100644 --- a/xcm/xcm-builder/src/tests.rs +++ b/xcm/xcm-builder/src/tests.rs @@ -233,19 +233,19 @@ fn transfer_should_work() { // we'll let them have message execution for free. AllowUnpaidFrom::set(vec![X1(Parachain(1)).into()]); // Child parachain #1 owns 1000 tokens held by us in reserve. - add_asset(1001, (Here.into(), 1000).into()); + add_asset(1001, (Here, 1000).into()); // They want to transfer 100 of them to their sibling parachain #2 let r = XcmExecutor::<TestConfig>::execute_xcm( X1(Parachain(1)).into(), Xcm::TransferAsset { - assets: (Here.into(), 100).into(), + assets: (Here, 100).into(), beneficiary: X1(AccountIndex64 { index: 3, network: Any }).into(), }, 50, ); assert_eq!(r, Outcome::Complete(10)); - assert_eq!(assets(3), vec![(Here.into(), 100).into()]); - assert_eq!(assets(1001), vec![(Here.into(), 900).into()]); + assert_eq!(assets(3), vec![(Here, 100).into()]); + assert_eq!(assets(1001), vec![(Here, 900).into()]); assert_eq!(sent_xcm(), vec![]); } @@ -253,7 +253,7 @@ fn transfer_should_work() { fn reserve_transfer_should_work() { AllowUnpaidFrom::set(vec![X1(Parachain(1)).into()]); // Child parachain #1 owns 1000 tokens held by us in reserve. - add_asset(1001, (Here.into(), 1000).into()); + add_asset(1001, (Here, 1000).into()); // The remote account owned by gav. let three: MultiLocation = X1(AccountIndex64 { index: 3, network: Any }).into(); @@ -262,7 +262,7 @@ fn reserve_transfer_should_work() { let r = XcmExecutor::<TestConfig>::execute_xcm( X1(Parachain(1)).into(), Xcm::TransferReserveAsset { - assets: (Here.into(), 100).into(), + assets: (Here, 100).into(), dest: X1(Parachain(2)).into(), effects: vec![Order::DepositAsset { assets: All.into(), @@ -274,7 +274,7 @@ fn reserve_transfer_should_work() { ); assert_eq!(r, Outcome::Complete(10)); - assert_eq!(assets(1002), vec![(Here.into(), 100).into()]); + assert_eq!(assets(1002), vec![(Here, 100).into()]); assert_eq!( sent_xcm(), vec![( diff --git a/xcm/xcm-executor/src/assets.rs b/xcm/xcm-executor/src/assets.rs index 824f419c4f5c..8b87cc7ca5c4 100644 --- a/xcm/xcm-executor/src/assets.rs +++ b/xcm/xcm-executor/src/assets.rs @@ -381,12 +381,12 @@ impl Assets { /// ``` /// use xcm_executor::Assets; /// use xcm::latest::prelude::*; - /// let assets_i_have: Assets = vec![ (Here.into(), 100).into(), (vec![0], 100).into() ].into(); - /// let assets_they_want: MultiAssetFilter = vec![ (Here.into(), 200).into(), (vec![0], 50).into() ].into(); + /// let assets_i_have: Assets = vec![ (Here, 100).into(), (vec![0], 100).into() ].into(); + /// let assets_they_want: MultiAssetFilter = vec![ (Here, 200).into(), (vec![0], 50).into() ].into(); /// /// let assets_we_can_trade: Assets = assets_i_have.min(&assets_they_want); /// assert_eq!(assets_we_can_trade.into_assets_iter().collect::<Vec<_>>(), vec![ - /// (Here.into(), 100).into(), (vec![0], 50).into(), + /// (Here, 100).into(), (vec![0], 50).into(), /// ]); /// ``` pub fn min(&self, mask: &MultiAssetFilter) -> Assets { @@ -443,12 +443,12 @@ mod tests { #[allow(non_snake_case)] /// Concrete fungible constructor fn CF(amount: u128) -> MultiAsset { - (Here.into(), amount).into() + (Here, amount).into() } #[allow(non_snake_case)] /// Concrete non-fungible constructor fn CNF(instance_id: u8) -> MultiAsset { - (Here.into(), [instance_id; 4]).into() + (Here, [instance_id; 4]).into() } fn test_assets() -> Assets { @@ -562,8 +562,8 @@ mod tests { #[test] fn min_all_concrete_works() { let assets = test_assets(); - let fungible = Wild((Here.into(), WildFungible).into()); - let non_fungible = Wild((Here.into(), WildNonFungible).into()); + let fungible = Wild((Here, WildFungible).into()); + let non_fungible = Wild((Here, WildNonFungible).into()); let fungible = assets.min(&fungible); let fungible = fungible.assets_iter().collect::<Vec<_>>(); @@ -626,8 +626,8 @@ mod tests { #[test] fn saturating_take_all_concrete_works() { let mut assets = test_assets(); - let fungible = Wild((Here.into(), WildFungible).into()); - let non_fungible = Wild((Here.into(), WildNonFungible).into()); + let fungible = Wild((Here, WildFungible).into()); + let non_fungible = Wild((Here, WildNonFungible).into()); let fungible = assets.saturating_take(fungible); let fungible = fungible.assets_iter().collect::<Vec<_>>(); diff --git a/xcm/xcm-executor/src/traits/transact_asset.rs b/xcm/xcm-executor/src/traits/transact_asset.rs index b46a5e9b8d5e..80ee2de660c3 100644 --- a/xcm/xcm-executor/src/traits/transact_asset.rs +++ b/xcm/xcm-executor/src/traits/transact_asset.rs @@ -273,7 +273,7 @@ mod tests { (UnimplementedTransactor, NotFoundTransactor, UnimplementedTransactor); assert_eq!( - MultiTransactor::deposit_asset(&(Here.into(), 1).into(), &Here.into()), + 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.into(), 1).into(), &Here.into()), 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.into(), 1).into(), &Here.into()), + 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.into(), 1).into(), &Here.into()), 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 fd17891c1820..2d67419dc524 100644 --- a/xcm/xcm-simulator/example/src/lib.rs +++ b/xcm/xcm-simulator/example/src/lib.rs @@ -192,7 +192,7 @@ mod tests { relay_chain::Origin::signed(ALICE), Box::new(X1(Parachain(1)).into()), Box::new(X1(AccountId32 { network: Any, id: ALICE.into() }).into()), - (Here.into(), 123).into(), + (Here, 123).into(), 0, 3, )); From 1c97d0f9096a02ad893ad9b92bcbb701f240faaa Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Mon, 9 Aug 2021 13:32:52 +0200 Subject: [PATCH 163/166] cleanup --- xcm/xcm-builder/src/tests.rs | 14 +++++++------- xcm/xcm-simulator/example/src/lib.rs | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/xcm/xcm-builder/src/tests.rs b/xcm/xcm-builder/src/tests.rs index 0db2424b90b6..de46744bb455 100644 --- a/xcm/xcm-builder/src/tests.rs +++ b/xcm/xcm-builder/src/tests.rs @@ -100,7 +100,7 @@ fn allow_unpaid_should_work() { AllowUnpaidFrom::set(vec![Parent.into()]); let r = AllowUnpaidExecutionFrom::<IsInVec<AllowUnpaidFrom>>::should_execute( - &X1(Parachain(1)).into(), + &Parachain(1).into(), true, &mut message, 10, @@ -128,7 +128,7 @@ fn allow_paid_should_work() { }; let r = AllowTopLevelPaidExecutionFrom::<IsInVec<AllowPaidFrom>>::should_execute( - &X1(Parachain(1)).into(), + &Parachain(1).into(), true, &mut message, 10, @@ -178,7 +178,7 @@ fn allow_paid_should_work() { }; let r = AllowTopLevelPaidExecutionFrom::<IsInVec<AllowPaidFrom>>::should_execute( - &X1(Parachain(1)).into(), + &Parachain(1).into(), true, &mut paying_message, 30, @@ -236,7 +236,7 @@ fn transfer_should_work() { add_asset(1001, (Here, 1000).into()); // They want to transfer 100 of them to their sibling parachain #2 let r = XcmExecutor::<TestConfig>::execute_xcm( - X1(Parachain(1)).into(), + Parachain(1).into(), Xcm::TransferAsset { assets: (Here, 100).into(), beneficiary: X1(AccountIndex64 { index: 3, network: Any }).into(), @@ -260,10 +260,10 @@ fn reserve_transfer_should_work() { // 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::<TestConfig>::execute_xcm( - X1(Parachain(1)).into(), + Parachain(1).into(), Xcm::TransferReserveAsset { assets: (Here, 100).into(), - dest: X1(Parachain(2)).into(), + dest: Parachain(2).into(), effects: vec![Order::DepositAsset { assets: All.into(), max_assets: 1, @@ -278,7 +278,7 @@ fn reserve_transfer_should_work() { assert_eq!( sent_xcm(), vec![( - X1(Parachain(2)).into(), + Parachain(2).into(), Xcm::ReserveAssetDeposited { assets: (Parent, 100).into(), effects: vec![Order::DepositAsset { diff --git a/xcm/xcm-simulator/example/src/lib.rs b/xcm/xcm-simulator/example/src/lib.rs index 2d67419dc524..547c6f1858be 100644 --- a/xcm/xcm-simulator/example/src/lib.rs +++ b/xcm/xcm-simulator/example/src/lib.rs @@ -112,7 +112,7 @@ mod tests { Relay::execute_with(|| { assert_ok!(RelayChainPalletXcm::send_xcm( Here.into(), - X1(Parachain(1)).into(), + Parachain(1).into(), Transact { origin_type: OriginKind::SovereignAccount, require_weight_at_most: INITIAL_BALANCE as u64, From 425116f35fc307e2440a4e3cb36a06b4bd590e32 Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Mon, 9 Aug 2021 04:52:43 -0700 Subject: [PATCH 164/166] cargo fmt --- runtime/test-runtime/src/xcm_config.rs | 3 ++- xcm/src/v1/mod.rs | 5 +++-- xcm/xcm-builder/src/tests.rs | 18 ++++++------------ xcm/xcm-simulator/example/src/parachain.rs | 3 +-- 4 files changed, 12 insertions(+), 17 deletions(-) diff --git a/runtime/test-runtime/src/xcm_config.rs b/runtime/test-runtime/src/xcm_config.rs index 7380f68584b1..7748d55e1875 100644 --- a/runtime/test-runtime/src/xcm_config.rs +++ b/runtime/test-runtime/src/xcm_config.rs @@ -16,7 +16,8 @@ use frame_support::{parameter_types, traits::Everything, weights::Weight}; use xcm::latest::{ - Error as XcmError, MultiAsset, MultiLocation, NetworkId, Result as XcmResult, SendXcm, Xcm, Parent, Junctions::Here, + Error as XcmError, Junctions::Here, MultiAsset, MultiLocation, NetworkId, Parent, + Result as XcmResult, SendXcm, Xcm, }; use xcm_builder::{AllowUnpaidExecutionFrom, FixedWeightBounds, SignedToAccountId32}; use xcm_executor::{ diff --git a/xcm/src/v1/mod.rs b/xcm/src/v1/mod.rs index ad2fa40a9123..acf60252a1f2 100644 --- a/xcm/src/v1/mod.rs +++ b/xcm/src/v1/mod.rs @@ -38,7 +38,7 @@ pub use multiasset::{ AssetId, AssetInstance, Fungibility, MultiAsset, MultiAssetFilter, MultiAssets, WildFungibility, WildMultiAsset, }; -pub use multilocation::{Junctions, MultiLocation, Parent, ParentThen, Ancestor, AncestorThen}; +pub use multilocation::{Ancestor, AncestorThen, Junctions, MultiLocation, Parent, ParentThen}; pub use order::Order; pub use traits::{Error, ExecuteXcm, Outcome, Result, SendXcm}; @@ -64,8 +64,9 @@ pub mod prelude { WildMultiAsset::{self, *}, }, multilocation::{ + Ancestor, AncestorThen, Junctions::{self, *}, - MultiLocation, Parent, ParentThen, Ancestor, AncestorThen, + MultiLocation, Parent, ParentThen, }, opaque, order::Order::{self, *}, diff --git a/xcm/xcm-builder/src/tests.rs b/xcm/xcm-builder/src/tests.rs index de46744bb455..5ed3d3c49600 100644 --- a/xcm/xcm-builder/src/tests.rs +++ b/xcm/xcm-builder/src/tests.rs @@ -63,10 +63,8 @@ fn weigher_should_work() { #[test] fn take_weight_credit_barrier_should_work() { - let mut message = opaque::Xcm::TransferAsset { - assets: (Parent, 100).into(), - beneficiary: Here.into(), - }; + let mut message = + opaque::Xcm::TransferAsset { assets: (Parent, 100).into(), beneficiary: Here.into() }; let mut weight_credit = 10; let r = TakeWeightCredit::should_execute( @@ -92,10 +90,8 @@ fn take_weight_credit_barrier_should_work() { #[test] fn allow_unpaid_should_work() { - let mut message = opaque::Xcm::TransferAsset { - assets: (Parent, 100).into(), - beneficiary: Here.into(), - }; + let mut message = + opaque::Xcm::TransferAsset { assets: (Parent, 100).into(), beneficiary: Here.into() }; AllowUnpaidFrom::set(vec![Parent.into()]); @@ -122,10 +118,8 @@ fn allow_unpaid_should_work() { fn allow_paid_should_work() { AllowPaidFrom::set(vec![Parent.into()]); - let mut message = opaque::Xcm::TransferAsset { - assets: (Parent, 100).into(), - beneficiary: Here.into(), - }; + let mut message = + opaque::Xcm::TransferAsset { assets: (Parent, 100).into(), beneficiary: Here.into() }; let r = AllowTopLevelPaidExecutionFrom::<IsInVec<AllowPaidFrom>>::should_execute( &Parachain(1).into(), diff --git a/xcm/xcm-simulator/example/src/parachain.rs b/xcm/xcm-simulator/example/src/parachain.rs index 87fe111e57a6..79c2f6e2947d 100644 --- a/xcm/xcm-simulator/example/src/parachain.rs +++ b/xcm/xcm-simulator/example/src/parachain.rs @@ -266,8 +266,7 @@ pub mod mock_msg_queue { Self::deposit_event(Event::UnsupportedVersion(id)); }, Ok(Ok(x)) => { - let outcome = - T::XcmExecutor::execute_xcm(Parent.into(), x, limit); + let outcome = T::XcmExecutor::execute_xcm(Parent.into(), x, limit); Self::deposit_event(Event::ExecutedDownward(id, outcome)); }, } From 9ed00fc03072fea7d53e2ea60c2b8966927ef1ca Mon Sep 17 00:00:00 2001 From: Gav Wood <gavin@parity.io> Date: Mon, 9 Aug 2021 19:03:00 +0200 Subject: [PATCH 165/166] Fixes --- xcm/xcm-builder/src/currency_adapter.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xcm/xcm-builder/src/currency_adapter.rs b/xcm/xcm-builder/src/currency_adapter.rs index feea36707684..074ae91c244a 100644 --- a/xcm/xcm-builder/src/currency_adapter.rs +++ b/xcm/xcm-builder/src/currency_adapter.rs @@ -53,7 +53,7 @@ impl From<Error> for XcmError { /// # Example /// ``` /// use frame_support::parameter_types; -/// use xcm::latest::MultiLocation; +/// use xcm::latest::prelude::*; /// use xcm_builder::{ParentIsDefault, CurrencyAdapter, IsConcrete}; /// /// /// Our chain's account id. From 38f6e3c6fe316640f450afe5370a743b0a7b8416 Mon Sep 17 00:00:00 2001 From: Keith Yeung <kungfukeith11@gmail.com> Date: Mon, 9 Aug 2021 11:10:00 -0700 Subject: [PATCH 166/166] Fix doc test --- xcm/xcm-builder/src/matches_fungible.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xcm/xcm-builder/src/matches_fungible.rs b/xcm/xcm-builder/src/matches_fungible.rs index accb4aa75256..6c33e18fe97c 100644 --- a/xcm/xcm-builder/src/matches_fungible.rs +++ b/xcm/xcm-builder/src/matches_fungible.rs @@ -32,7 +32,7 @@ use xcm_executor::traits::MatchesFungible; /// # Example /// /// ``` -/// use xcm::latest::MultiLocation; +/// use xcm::latest::{MultiLocation, Parent}; /// use xcm_builder::IsConcrete; /// use xcm_executor::traits::MatchesFungible; ///