* MultiAsset TWO

* Draft next MultiAsset API.

* XCM core builds

* XCM Executor builds

* XCM Builder builds

* API changes making their way throughout

* Some TODOs

* Further build fixes

* Basic compile builds

* First test fixed

* All executor tests fixed

* Typo

* Optimize subsume_assets and add test

* Optimize checked_sub

* XCM Builder first test fixed

* Fix builder tests

* Fix doc test

* fix some doc tests

* spelling

* named fields for AllOf

* Update xcm/src/v0/multiasset.rs

Co-authored-by: Alexander Popiak <alexander.popiak@parity.io>

* Update xcm/src/v0/multiasset.rs

Co-authored-by: Alexander Popiak <alexander.popiak@parity.io>

* Update xcm/src/v0/multiasset.rs

Co-authored-by: Alexander Popiak <alexander.popiak@parity.io>

* Update xcm/src/v0/multiasset.rs

Co-authored-by: Alexander Popiak <alexander.popiak@parity.io>

* Reformat

* Move to XCM version 1

* Spelling

* warnings

* Replace some more v0->v1s

* warnings

* format

* Add max_assets param

* building

* test fixes

* tests

* another test

* final test

* tests

* Rename Null -> Here

* Introduce

* More ergonomics

* More ergonomics

* test fix

* test fixes

* docs

* BuyExecution includes

* Fix XCM extrinsics

* fmt

* Make Vec<MultiAsset>/MultiAssets conversions safe

* More MultiAssets conversion safety

* spelling

* fix doc test

* Apply suggestions from code review

Co-authored-by: Amar Singh <asinghchrony@protonmail.com>

* Apply suggestions from code review

Co-authored-by: Amar Singh <asinghchrony@protonmail.com>

* fmt

* Add v0, remove VersionedMultiAsset

* Remove VersionedMultiLocation

* Update xcm/src/v1/order.rs

Co-authored-by: Amar Singh <asinghchrony@protonmail.com>

* Update xcm/src/v1/mod.rs

Co-authored-by: Amar Singh <asinghchrony@protonmail.com>

* XCM v0 backwards compatibility

* Full compatibility

* fmt

* Update xcm/pallet-xcm/src/lib.rs

* Update xcm/src/v0/order.rs

Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com>

* Tweaks to versioning system

* Fixes

* fmt

* Update xcm/xcm-executor/src/assets.rs

Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com>

* Update xcm/xcm-executor/src/assets.rs

Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com>

* Grumbles

* Update xcm/src/v1/multiasset.rs

Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com>

* fmt

* Update xcm/src/v1/multiasset.rs

Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com>

* Update xcm/src/v1/multiasset.rs

Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com>

* Fixes

* Formatting

Co-authored-by: Alexander Popiak <alexander.popiak@parity.io>
Co-authored-by: Amar Singh <asinghchrony@protonmail.com>
Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com>
This commit is contained in:
Gavin Wood
2021-08-06 18:25:01 +02:00
committed by GitHub
parent d86bb658a0
commit ce80bc2d4c
49 changed files with 3475 additions and 1242 deletions
+392
View File
@@ -0,0 +1,392 @@
// 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 1 of the Cross-Consensus Message format data structures.
use super::v0::Xcm as Xcm0;
use crate::DoubleEncoded;
use alloc::vec::Vec;
use core::{
convert::{TryFrom, TryInto},
fmt::Debug,
result,
};
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,
};
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::{
junction::{
BodyId, BodyPart,
Junction::*,
NetworkId::{self, *},
},
multiasset::{
AssetId::{self, *},
AssetInstance::{self, *},
Fungibility::{self, *},
MultiAsset,
MultiAssetFilter::{self, *},
MultiAssets,
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},
OriginKind, Response,
Xcm::{self, *},
};
}
// 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(MultiAssets),
}
/// 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 register.
///
/// Kind: *Instruction*.
///
/// Errors:
#[codec(index = 0)]
WithdrawAsset { assets: MultiAssets, 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 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.
///
/// Kind: *Trusted Indication*.
///
/// Errors:
#[codec(index = 1)]
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.
///
/// Some orders are given (`effects`) which should be executed once the corresponding derivative assets have
/// been placed into 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 corresponding `assets` prior as a consequence
/// of sending this message.
///
/// Kind: *Trusted Indication*.
///
/// Errors:
#[codec(index = 2)]
ReceiveTeleportedAsset { assets: MultiAssets, effects: Vec<Order<Call>> },
/// 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.
///
/// 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 `beneficiary`.
///
/// - `assets`: The asset(s) to be withdrawn.
/// - `beneficiary`: The new owner for the assets.
///
/// Safety: No concerns.
///
/// Kind: *Instruction*.
///
/// Errors:
#[codec(index = 4)]
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 (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 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`.
///
/// Safety: No concerns.
///
/// Kind: *Instruction*.
///
/// Errors:
#[codec(index = 5)]
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`.
///
/// - `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> 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() },
ReserveAssetDeposited { assets, effects } => ReserveAssetDeposited {
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 } =>
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::*;
}
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()?),
},
})
}
}