* 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
+40 -23
View File
@@ -23,10 +23,11 @@ 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::latest::prelude::*;
use xcm_executor::traits::ConvertOrigin;
use frame_support::PalletId;
@@ -87,7 +88,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::latest::Outcome),
Sent(MultiLocation, MultiLocation, Xcm<()>),
}
@@ -134,15 +135,15 @@ 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({
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![],
} ]
@@ -153,21 +154,28 @@ pub mod pallet {
origin: OriginFor<T>,
dest: MultiLocation,
beneficiary: MultiLocation,
assets: Vec<MultiAsset>,
assets: MultiAssets,
fee_asset_item: u32,
dest_weight: Weight,
) -> DispatchResult {
let origin_location = T::ExecuteXcmOrigin::ensure_origin(origin)?;
ensure!(assets.len() <= MAX_ASSETS_FOR_TRANSFER, Error::<T>::TooManyAssets);
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 inv_dest = T::LocationInverter::invert_location(&dest);
let mut fees = assets.first().ok_or(Error::<T>::Empty)?.clone();
fees.reanchor(&inv_dest).map_err(|_| Error::<T>::CannotReanchor)?;
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,
effects: vec![InitiateTeleport {
assets: vec![All],
assets: Wild(All),
dest,
effects: vec![
BuyExecution {
@@ -176,9 +184,10 @@ pub mod pallet {
weight: 0,
debt: dest_weight,
halt_on_error: false,
xcm: vec![],
orders: vec![],
instructions: vec![],
},
DepositAsset { assets: vec![All], dest: beneficiary },
DepositAsset { assets: Wild(All), max_assets, beneficiary },
],
}],
};
@@ -203,7 +212,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(),
@@ -216,30 +225,38 @@ pub mod pallet {
origin: OriginFor<T>,
dest: MultiLocation,
beneficiary: MultiLocation,
assets: Vec<MultiAsset>,
assets: MultiAssets,
fee_asset_item: u32,
dest_weight: Weight,
) -> DispatchResult {
let origin_location = T::ExecuteXcmOrigin::ensure_origin(origin)?;
ensure!(assets.len() <= MAX_ASSETS_FOR_TRANSFER, Error::<T>::TooManyAssets);
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 inv_dest = T::LocationInverter::invert_location(&dest);
let mut fees = assets.first().ok_or(Error::<T>::Empty)?.clone();
fees.reanchor(&inv_dest).map_err(|_| Error::<T>::CannotReanchor)?;
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::TransferReserveAsset {
assets,
dest,
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,
xcm: vec![],
orders: vec![],
instructions: vec![],
},
DepositAsset { assets: vec![All], dest: beneficiary },
DepositAsset { assets: Wild(All), max_assets, beneficiary },
],
};
let weight =
@@ -286,7 +303,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);
@@ -363,7 +380,7 @@ where
#[cfg(feature = "runtime-benchmarks")]
fn successful_origin() -> O {
O::from(Origin::Xcm(MultiLocation::Null))
O::from(Origin::Xcm(MultiLocation::Here))
}
}
+20 -13
View File
@@ -25,15 +25,15 @@ 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},
latest::prelude::*,
opaque::latest::{Error as XcmError, MultiAsset, Result as XcmResult, SendXcm, Xcm},
};
use xcm_builder::{
AccountId32Aliases, AllowTopLevelPaidExecutionFrom, ChildParachainAsNative,
ChildParachainConvertsVia, ChildSystemParachainAsSuperuser,
CurrencyAdapter as XcmCurrencyAdapter, FixedRateOfConcreteFungible, FixedWeightBounds,
IsConcrete, LocationInverter, SignedAccountId32AsNative, SignedToAccountId32,
SovereignSignedViaLocation, TakeWeightCredit,
CurrencyAdapter as XcmCurrencyAdapter, FixedRateOfFungible, FixedWeightBounds, IsConcrete,
LocationInverter, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation,
TakeWeightCredit,
};
use xcm_executor::XcmExecutor;
@@ -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;
}
@@ -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 = ();
}
@@ -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::latest::Xcm<Call>)>;
type XcmExecutor = XcmExecutor<XcmConfig>;
type XcmTeleportFilter = All<(MultiLocation, Vec<MultiAsset>)>;
type XcmReserveTransferFilter = All<(MultiLocation, Vec<MultiAsset>)>;
@@ -195,9 +195,16 @@ pub(crate) fn last_event() -> Event {
System::events().pop().expect("Event expected").event
}
pub(crate) fn buy_execution<C>(debt: Weight, fees: MultiAsset) -> Order<C> {
use xcm::opaque::v0::prelude::*;
Order::BuyExecution { fees, weight: 0, debt, halt_on_error: false, xcm: vec![] }
pub(crate) fn buy_execution<C>(fees: impl Into<MultiAsset>, debt: Weight) -> Order<C> {
use xcm::opaque::latest::prelude::*;
Order::BuyExecution {
fees: fees.into(),
weight: 0,
debt,
halt_on_error: false,
orders: vec![],
instructions: vec![],
}
}
pub(crate) fn new_test_ext_with_balances(
+24 -34
View File
@@ -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]);
@@ -38,22 +38,19 @@ 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,
ConcreteFungible { id: MultiLocation::Null, amount: SEND_AMOUNT },
),
DepositAsset { assets: vec![All], dest: sender.clone() },
buy_execution((Parent, SEND_AMOUNT), weight),
DepositAsset { assets: All.into(), max_assets: 1, 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()) }
)]
);
@@ -76,14 +73,11 @@ 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,
ConcreteFungible { id: MultiLocation::Null, amount: SEND_AMOUNT },
),
DepositAsset { assets: vec![All], dest: sender.clone() },
buy_execution((Parent, SEND_AMOUNT), weight),
DepositAsset { assets: All.into(), max_assets: 1, beneficiary: sender.clone() },
],
};
assert_noop!(
@@ -120,8 +114,9 @@ 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() }),
(Here, SEND_AMOUNT).into(),
0,
weight,
));
assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE - SEND_AMOUNT);
@@ -149,7 +144,8 @@ fn reserve_transfer_assets_works() {
Origin::signed(ALICE),
Parachain(PARA_ID).into(),
dest.clone(),
vec![ConcreteFungible { id: MultiLocation::Null, amount: SEND_AMOUNT }],
(Here, SEND_AMOUNT).into(),
0,
weight
));
// Alice spent amount
@@ -161,14 +157,11 @@ fn reserve_transfer_assets_works() {
sent_xcm(),
vec![(
Parachain(PARA_ID).into(),
Xcm::ReserveAssetDeposit {
assets: vec![ConcreteFungible { id: Parent.into(), amount: SEND_AMOUNT }],
Xcm::ReserveAssetDeposited {
assets: (X1(Parent), SEND_AMOUNT).into(),
effects: vec![
buy_execution(
weight,
ConcreteFungible { id: Parent.into(), amount: SEND_AMOUNT }
),
DepositAsset { assets: vec![All], dest },
buy_execution((Parent, SEND_AMOUNT), weight),
DepositAsset { assets: All.into(), max_assets: 1, beneficiary: dest },
]
}
)]
@@ -196,13 +189,10 @@ 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 }],
assets: (Here, SEND_AMOUNT).into(),
effects: vec![
buy_execution(
weight,
ConcreteFungible { id: MultiLocation::Null, amount: SEND_AMOUNT }
),
DepositAsset { assets: vec![All], dest },
buy_execution((Here, SEND_AMOUNT), weight),
DepositAsset { assets: All.into(), max_assets: 1, beneficiary: dest }
],
}),
weight