* 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
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -22,7 +22,7 @@ use frame_support::{
dispatch::{Dispatchable, Parameter},
weights::{GetDispatchInfo, PostDispatchInfo},
};
use xcm::v0::SendXcm;
use xcm::latest::SendXcm;
/// The trait to parameterize the `XcmExecutor`.
pub trait Config {
+51 -46
View File
@@ -22,8 +22,8 @@ use frame_support::{
weights::GetDispatchInfo,
};
use sp_std::{marker::PhantomData, prelude::*};
use xcm::v0::{
Error as XcmError, ExecuteXcm, MultiAsset, MultiLocation, Order, Outcome, Response, SendXcm,
use xcm::latest::{
Error as XcmError, ExecuteXcm, MultiAssets, MultiLocation, Order, Outcome, Response, SendXcm,
Xcm,
};
@@ -34,7 +34,7 @@ use traits::{
};
mod assets;
pub use assets::{AssetId, Assets};
pub use assets::Assets;
mod config;
pub use config::Config;
@@ -94,10 +94,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.
@@ -144,17 +144,15 @@ 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.saturating_subsume_all(withdrawn);
holding.subsume_assets(withdrawn);
}
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.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!(
@@ -162,31 +160,28 @@ impl<Config: config::Config> XcmExecutor<Config> {
XcmError::UntrustedReserveLocation
);
}
Some((Assets::from(assets), effects))
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 {
ensure!(!asset.is_wildcard(), XcmError::Wildcard);
Config::AssetTransactor::teleport_asset(&asset, &origin, &dest)?;
for asset in assets.inner() {
Config::AssetTransactor::beam_asset(&asset, &origin, &beneficiary)?;
}
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);
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::beam_asset(asset, &origin, &dest)?;
}
Config::XcmSender::send_xcm(dest, Xcm::ReserveAssetDeposit { assets, effects })?;
assets.reanchor(&inv_dest)?;
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.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!(
@@ -198,7 +193,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))
@@ -252,41 +247,41 @@ 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 {
Order::DepositAsset { assets, dest } => {
let deposited = holding.saturating_take(assets);
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() {
Config::AssetTransactor::deposit_asset(&asset, &dest)?;
Config::AssetTransactor::deposit_asset(&asset, &beneficiary)?;
}
},
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)?;
}
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);
@@ -299,29 +294,37 @@ 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.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.
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)?);
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.saturating_subsume_all(unspent);
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,
@@ -331,7 +334,9 @@ impl<Config: config::Config> XcmExecutor<Config> {
Ok(surplus) => total_surplus += surplus,
}
}
holding.saturating_subsume(trader.refund_weight(remaining_weight));
if let Some(w) = trader.refund_weight(remaining_weight) {
holding.subsume(w);
}
},
_ => return Err(XcmError::UnhandledEffect)?,
}
@@ -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::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::v0::{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;
@@ -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::latest::{MultiAsset, MultiLocation};
/// Filters assets/location pairs.
///
@@ -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::latest::MultiAsset;
pub trait MatchesFungible<Balance> {
fn matches_fungible(a: &MultiAsset) -> Option<Balance>;
@@ -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::latest::{Error as XcmError, MultiAsset};
/// Errors associated with [`MatchesFungibles`] operation.
pub enum Error {
@@ -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::latest::{MultiLocation, Response};
/// Define what needs to be done upon receiving a query response.
pub trait OnResponse {
@@ -16,7 +16,7 @@
use frame_support::weights::Weight;
use sp_std::result::Result;
use xcm::v0::{MultiLocation, Xcm};
use xcm::latest::{MultiLocation, Xcm};
/// Trait to determine whether the execution engine should actually execute a given XCM.
///
@@ -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::latest::{Error as XcmError, MultiAsset, MultiLocation, Result as XcmResult};
/// Facility for asset transacting.
///
@@ -89,7 +89,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(
fn beam_asset(
asset: &MultiAsset,
from: &MultiLocation,
to: &MultiLocation,
@@ -111,7 +111,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,
}
)* );
@@ -139,7 +139,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,
}
)* );
@@ -155,7 +155,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,
}
)* );
@@ -175,7 +175,7 @@ impl TransactAsset for Tuple {
) -> 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,
}
)* );
@@ -193,6 +193,7 @@ impl TransactAsset for Tuple {
#[cfg(test)]
mod tests {
use super::*;
use MultiLocation::Here;
pub struct UnimplementedTransactor;
impl TransactAsset for UnimplementedTransactor {}
@@ -272,7 +273,7 @@ mod tests {
(UnimplementedTransactor, NotFoundTransactor, UnimplementedTransactor);
assert_eq!(
MultiTransactor::deposit_asset(&MultiAsset::All, &MultiLocation::Null),
MultiTransactor::deposit_asset(&(Here, 1).into(), &Here),
Err(XcmError::AssetNotFound)
);
}
@@ -281,7 +282,7 @@ mod tests {
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(&(Here, 1).into(), &Here), Ok(()));
}
#[test]
@@ -289,7 +290,7 @@ mod tests {
type MultiTransactor = (OverflowTransactor, SuccessfulTransactor);
assert_eq!(
MultiTransactor::deposit_asset(&MultiAsset::All, &MultiLocation::Null),
MultiTransactor::deposit_asset(&(Here, 1).into(), &Here),
Err(XcmError::Overflow)
);
}
@@ -298,6 +299,6 @@ mod tests {
fn success_stops_iteration() {
type MultiTransactor = (SuccessfulTransactor, OverflowTransactor);
assert_eq!(MultiTransactor::deposit_asset(&MultiAsset::All, &MultiLocation::Null), Ok(()));
assert_eq!(MultiTransactor::deposit_asset(&(Here, 1).into(), &Here), Ok(()));
}
}
@@ -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::latest::{Error, MultiAsset, MultiLocation, Xcm};
/// Determine the weight of an XCM message.
pub trait WeightBounds<Call> {
@@ -71,8 +71,8 @@ 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
}
}