Ensure MultiLocation always has a canonical representation (#3404)

* MultiAsset TWO

* Ensure MultiLocation always has a canonical representation

* Remove v1 module

* Draft next MultiAsset API.

* Implement custom encoding/decoding scheme for MultiLocation

* Properly implement IntoIterator for Junctions

* Implement TryFrom<MultiLocation> for Junctions

* Fix spelling mistakes

* Fix tests in xcm-executor

* XCM core builds

* XCM Executor builds

* XCM Builder builds

* Fix xcm-builder tests and compilation

* Make pallet-xcm compile

* Use MultiLocation::default()

* Make polkadot-runtime-common compile

* Make rococo-runtime compile

* Change return type of parent_count to u8

* Change MAX_MULTILOCATION_LENGTH to 255

* Make kusama-runtime compile

* Fix logic in pallet-xcm

* Use MultiLocation::empty()

* Fix logic in location_conversion

* Fix logic in origin_conversion.rs

* Make westend-runtime compile

* Rename prefixes and suffixes variables

* Rename non_parent to interior

* Rename non_parent to interior

* Add test for encode/decode roundtrip and fix decode algorithm

* API changes making their way throughout

* Some TODOs

* Further build fixes

* Rename non_parent/junctions to interior

* 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

* Make xcm-simulator compile

* Make xcm-simulator-example compile

* Make spellcheck happy

* cargo fmt

* fix some doc tests

* spelling

* named fields for AllOf

* Fix subtle bug where Null is treated as an identifier

* Add FIXME comment awaiting for const generics eval stabilization

* 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

* Update rustdocs and add debug_assert where sensible

* Revert debug_assert in const fn len()

* 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

* Fix pallet-xcm tests

* fix

* Substitute with_parent with with_parents_const

* Rename argument name from a to m

* Rename split_last to split_last_interior

* Allow adding multiple parents in MultiLocation

* Rename pop_parent to dec_parent

* Ensure relay chain XCM sender receives a MultiLocation without any parents

* Block only when MultiLocation destination length is 8

* Cargo fmt

* Remove reverse iterators, implement DoubleEndedIterator and add tests

* Fix iter_rev lifetime requirements

* Cargo fmt

* Add an into() method for Junctions for conciseness in const context

* Ensure parent count is 0 while executing who in RelayedFrom

* Appease spellchecker

* Use and_then instead of repeated map_err

* Remove custom codec indices for v1 Junctions

* Add convenience 'contains_parents_only' method to MultiLocation

* Fix merge conflict

* Use more convenience methods

* Remove with_parachain_interior

* Prefer matching against tuple instead of using match guards

* Match against tuple instead of using more match guards

* Update encode/decode test for MultiLocation

* Minor tweaks

* Fixes

* Fixes

* Fixes

* Fix MultiLocation

* Add deprecation note for iter_rev and into_iter_rev

* Update some rustdocs

* cargo fmt

* Fix xcm-executor unit tests

* Fix compilation and unit tests in xcm-builder

* cargo fmt

* Fix tests in xcm-simulator-example

* Publicize MultiLocation fields

* Match on the MultiLocation struct directly in xcm-builder

* Do not dereference undereferenceable types

* Add convenience MultiLocation conversions for tuples

* Use clearer import paths

* Remove unused dependency

* fix junction + response

* Import from latest opaque xcm module

* Update xcm/src/v1/mod.rs

* better comment

* Fix ownership transfer

* Fix merge

* Fix merge

* cargo fmt

* Fix merge

* Fix merge

* Fix integration test

* More readable Parent syntax

* cleanup

* cleanup

* cleanup

* cleanup

* cleanup

* cleanup

* cleanup

* cleanup

* cargo fmt

* Fixes

* Fix doc test

Co-authored-by: Gav Wood <gavin@parity.io>
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:
Keith Yeung
2021-08-09 20:55:40 +02:00
committed by GitHub
parent 276dc1981e
commit 1556873060
36 changed files with 1683 additions and 952 deletions
+6 -2
View File
@@ -19,7 +19,7 @@
use frame_support::{ensure, traits::Contains, weights::Weight};
use polkadot_parachain::primitives::IsSystem;
use sp_std::{marker::PhantomData, result::Result};
use xcm::latest::{Junction, MultiLocation, Order, Xcm};
use xcm::latest::{Junction, Junctions, MultiLocation, Order, Xcm};
use xcm_executor::traits::{OnResponse, ShouldExecute};
/// Execution barrier that just takes `shallow_weight` from `weight_credit`.
@@ -84,7 +84,11 @@ impl<T: Contains<MultiLocation>> ShouldExecute for AllowUnpaidExecutionFrom<T> {
pub struct IsChildSystemParachain<ParaId>(PhantomData<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())
matches!(
l.interior(),
Junctions::X1(Junction::Parachain(id))
if ParaId::from(*id).is_system() && l.parent_count() == 0,
)
}
}
@@ -53,7 +53,7 @@ impl From<Error> for XcmError {
/// # Example
/// ```
/// use frame_support::parameter_types;
/// use xcm::latest::{MultiLocation, Junction};
/// use xcm::latest::prelude::*;
/// use xcm_builder::{ParentIsDefault, CurrencyAdapter, IsConcrete};
///
/// /// Our chain's account id.
@@ -61,7 +61,7 @@ impl From<Error> for XcmError {
///
/// /// Our relay chain's location.
/// parameter_types! {
/// RelayChain: MultiLocation = MultiLocation::X1(Junction::Parent);
/// RelayChain: MultiLocation = Parent.into();
/// CheckingAccount: AccountId = Default::default();
/// }
///
@@ -38,18 +38,24 @@ impl<Prefix: Get<MultiLocation>, AssetId: Clone, ConvertAssetId: Convert<u128, A
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
.interior()
.iter()
.enumerate()
.any(|(index, junction)| id.interior().at(index) != Some(junction))
{
return Err(())
}
match id.at(prefix.len()) {
Some(Junction::GeneralIndex { id }) => ConvertAssetId::convert_ref(id),
match id.interior().at(prefix.interior().len()) {
Some(Junction::GeneralIndex(id)) => ConvertAssetId::convert_ref(id),
_ => Err(()),
}
}
fn reverse_ref(what: impl Borrow<AssetId>) -> result::Result<MultiLocation, ()> {
let mut location = Prefix::get();
let id = ConvertAssetId::reverse_ref(what)?;
location.push(Junction::GeneralIndex { id }).map_err(|_| ())?;
location.push_interior(Junction::GeneralIndex(id))?;
Ok(location)
}
}
@@ -19,7 +19,7 @@ use parity_scale_codec::Encode;
use sp_io::hashing::blake2_256;
use sp_runtime::traits::AccountIdConversion;
use sp_std::{borrow::Borrow, marker::PhantomData};
use xcm::latest::{Junction, MultiLocation, NetworkId};
use xcm::latest::{Junction::*, Junctions::*, MultiLocation, NetworkId, Parent};
use xcm_executor::traits::{Convert, InvertLocation};
pub struct Account32Hash<Network, AccountId>(PhantomData<(Network, AccountId)>);
@@ -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 let &MultiLocation::X1(Junction::Parent) = location.borrow() {
if location.borrow().contains_parents_only(1) {
Ok(AccountId::default())
} else {
Err(())
@@ -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(Junction::Parent.into())
Ok(Parent.into())
} else {
Err(())
}
@@ -63,16 +63,16 @@ 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, ()> {
if let &MultiLocation::X1(Junction::Parachain(id)) = location.borrow() {
Ok(ParaId::from(id).into_account())
} else {
Err(())
match location.borrow() {
MultiLocation { parents: 0, interior: X1(Parachain(id)) } =>
Ok(ParaId::from(*id).into_account()),
_ => Err(()),
}
}
fn reverse_ref(who: impl Borrow<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(())
}
@@ -84,16 +84,16 @@ 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, ()> {
if let &MultiLocation::X2(Junction::Parent, Junction::Parachain(id)) = location.borrow() {
Ok(ParaId::from(id).into_account())
} else {
Err(())
match location.borrow() {
MultiLocation { parents: 1, interior: X1(Parachain(id)) } =>
Ok(ParaId::from(*id).into_account()),
_ => Err(()),
}
}
fn reverse_ref(who: impl Borrow<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, X1(Parachain(id.into()))))
} else {
Err(())
}
@@ -107,17 +107,20 @@ impl<Network: Get<NetworkId>, AccountId: From<[u8; 32]> + Into<[u8; 32]> + Clone
{
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() =>
MultiLocation {
parents: 0,
interior: X1(AccountId32 { id, network: NetworkId::Any }),
} => id,
MultiLocation { parents: 0, interior: X1(AccountId32 { id, network }) }
if network == Network::get() =>
id,
l => return Err(l),
_ => return Err(location),
};
Ok(id.into())
}
fn reverse(who: AccountId) -> Result<MultiLocation, AccountId> {
Ok(Junction::AccountId32 { id: who.into(), network: Network::get() }.into())
Ok(AccountId32 { id: who.into(), network: Network::get() }.into())
}
}
@@ -127,17 +130,20 @@ impl<Network: Get<NetworkId>, AccountId: From<[u8; 20]> + Into<[u8; 20]> + Clone
{
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() =>
MultiLocation {
parents: 0,
interior: X1(AccountKey20 { key, network: NetworkId::Any }),
} => key,
MultiLocation { parents: 0, interior: X1(AccountKey20 { key, network }) }
if network == Network::get() =>
key,
l => return Err(l),
_ => return Err(location),
};
Ok(key.into())
}
fn reverse(who: AccountId) -> Result<MultiLocation, AccountId> {
let j = Junction::AccountKey20 { key: who.into(), network: Network::get() };
let j = AccountKey20 { key: who.into(), network: Network::get() };
Ok(j.into())
}
}
@@ -155,7 +161,7 @@ impl<Network: Get<NetworkId>, AccountId: From<[u8; 20]> + Into<[u8; 20]> + Clone
/// ```
/// ```rust
/// # use frame_support::parameter_types;
/// # use xcm::latest::{MultiLocation::{self, *}, Junction::*, NetworkId::Any};
/// # use xcm::latest::{MultiLocation, Junction::*, Junctions::{self, *}, NetworkId::Any};
/// # use xcm_builder::LocationInverter;
/// # use xcm_executor::traits::InvertLocation;
/// # fn main() {
@@ -163,16 +169,14 @@ impl<Network: Get<NetworkId>, AccountId: From<[u8; 20]> + Into<[u8; 20]> + Clone
/// pub Ancestry: MultiLocation = X2(
/// Parachain(1),
/// AccountKey20 { network: Any, key: Default::default() },
/// );
/// ).into();
/// }
///
/// let input = X4(Parent, Parent, Parachain(2), AccountId32 { network: Any, id: Default::default() });
/// let input = MultiLocation::new(2, X2(Parachain(2), AccountId32 { network: Any, id: Default::default() }));
/// let inverted = LocationInverter::<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() }),
/// ));
/// # }
/// ```
@@ -180,18 +184,14 @@ 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 = Here;
for _ in 0..location.parent_count() {
junctions = junctions
.pushed_with(ancestry.take_first_interior().unwrap_or(OnlyChild))
.expect("ancestry is well-formed and has less than 8 non-parent junctions; qed");
}
result
let parents = location.interior().len() as u8;
MultiLocation::new(parents, junctions)
}
}
@@ -200,7 +200,7 @@ mod tests {
use super::*;
use frame_support::parameter_types;
use xcm::latest::{Junction::*, MultiLocation::*, NetworkId::Any};
use xcm::latest::{Junction, NetworkId::Any};
fn account20() -> Junction {
AccountKey20 { network: Any, key: Default::default() }
@@ -225,12 +225,12 @@ mod tests {
#[test]
fn inverter_works_in_tree() {
parameter_types! {
pub Ancestry: MultiLocation = X3(Parachain(1), account20(), account20());
pub Ancestry: MultiLocation = X3(Parachain(1), account20(), account20()).into();
}
let input = X5(Parent, Parent, Parent, Parachain(2), account32());
let input = MultiLocation::new(3, X2(Parachain(2), account32()));
let inverted = LocationInverter::<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())));
}
// Network Topology
@@ -240,12 +240,12 @@ mod tests {
#[test]
fn inverter_uses_ancestry_as_inverted_location() {
parameter_types! {
pub Ancestry: MultiLocation = X2(account20(), account20());
pub Ancestry: MultiLocation = X2(account20(), account20()).into();
}
let input = X2(Parent, Parent);
let input = MultiLocation::grandparent();
let inverted = LocationInverter::<Ancestry>::invert_location(&input);
assert_eq!(inverted, X2(account20(), account20()));
assert_eq!(inverted, X2(account20(), account20()).into());
}
// Network Topology
@@ -255,11 +255,11 @@ mod tests {
#[test]
fn inverter_uses_only_child_on_missing_ancestry() {
parameter_types! {
pub Ancestry: MultiLocation = X1(PalletInstance(5));
pub Ancestry: MultiLocation = X1(PalletInstance(5)).into();
}
let input = X2(Parent, Parent);
let input = MultiLocation::grandparent();
let inverted = LocationInverter::<Ancestry>::invert_location(&input);
assert_eq!(inverted, X2(PalletInstance(5), OnlyChild));
assert_eq!(inverted, X2(PalletInstance(5), OnlyChild).into());
}
}
@@ -32,16 +32,16 @@ use xcm_executor::traits::MatchesFungible;
/// # Example
///
/// ```
/// use xcm::latest::prelude::*;
/// use xcm::latest::{MultiLocation, Parent};
/// use xcm_builder::IsConcrete;
/// use xcm_executor::traits::MatchesFungible;
///
/// frame_support::parameter_types! {
/// pub TargetLocation: MultiLocation = X1(Parent);
/// pub TargetLocation: MultiLocation = Parent.into();
/// }
///
/// # fn main() {
/// let asset = (X1(Parent), 999).into();
/// let asset = (Parent, 999).into();
/// // match `asset` if it is a concrete asset in `TargetLocation`.
/// assert_eq!(<IsConcrete<TargetLocation> as MatchesFungible<u128>>::matches_fungible(&asset), Some(999));
/// # }
+13 -11
View File
@@ -146,16 +146,16 @@ impl TransactAsset for TestAssetTransactor {
pub fn to_account(l: MultiLocation) -> Result<u64, MultiLocation> {
Ok(match l {
// Siblings at 2000+id
X2(Parent, Parachain(id)) => 2000 + id as u64,
MultiLocation { parents: 1, interior: X1(Parachain(id)) } => 2000 + id as u64,
// Accounts are their number
X1(AccountIndex64 { index, .. }) => index,
MultiLocation { parents: 0, interior: X1(AccountIndex64 { index, .. }) } => index,
// Children at 1000+id
X1(Parachain(id)) => 1000 + id as u64,
MultiLocation { parents: 0, interior: X1(Parachain(id)) } => 1000 + id as u64,
// Self at 3000
Here => 3000,
MultiLocation { parents: 0, interior: Here } => 3000,
// Parent at 3001
X1(Parent) => 3001,
l => return Err(l),
MultiLocation { parents: 1, interior: Here } => 3001,
_ => return Err(l),
})
}
@@ -169,9 +169,11 @@ impl ConvertOrigin<TestOrigin> for TestOriginConverter {
match (kind, origin) {
(Superuser, _) => Ok(TestOrigin::Root),
(SovereignAccount, l) => Ok(TestOrigin::Signed(to_account(l)?)),
(Native, X1(Parachain(id))) => Ok(TestOrigin::Parachain(id)),
(Native, X1(Parent)) => Ok(TestOrigin::Relay),
(Native, X1(AccountIndex64 { index, .. })) => Ok(TestOrigin::Signed(index)),
(Native, MultiLocation { parents: 0, interior: X1(Parachain(id)) }) =>
Ok(TestOrigin::Parachain(id)),
(Native, MultiLocation { parents: 1, interior: Here }) => Ok(TestOrigin::Relay),
(Native, MultiLocation { parents: 0, interior: X1(AccountIndex64 { index, .. }) }) =>
Ok(TestOrigin::Signed(index)),
(_, origin) => Err(origin),
}
}
@@ -247,7 +249,7 @@ pub fn response(query_id: u64) -> Option<Response> {
}
parameter_types! {
pub TestAncestry: MultiLocation = X1(Parachain(42));
pub TestAncestry: MultiLocation = X1(Parachain(42)).into();
pub UnitWeightCost: Weight = 10;
}
parameter_types! {
@@ -255,7 +257,7 @@ parameter_types! {
pub static AllowUnpaidFrom: Vec<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(), 1_000_000_000_000);
pub static WeightPrice: (AssetId, u128) = (From::from(Here), 1_000_000_000_000);
}
pub type TestBarrier = (
@@ -20,7 +20,7 @@ use frame_support::traits::{EnsureOrigin, Get, GetBacking, OriginTrait};
use frame_system::RawOrigin as SystemRawOrigin;
use polkadot_parachain::primitives::IsSystem;
use sp_std::{convert::TryInto, marker::PhantomData};
use xcm::latest::{BodyId, BodyPart, Junction, MultiLocation, NetworkId, OriginKind};
use xcm::latest::{BodyId, BodyPart, Junction, Junctions::*, MultiLocation, NetworkId, OriginKind};
use xcm_executor::traits::{Convert, ConvertOrigin};
/// Sovereign accounts use the system's `Signed` origin with an account ID derived from the `LocationConverter`.
@@ -45,9 +45,10 @@ where
pub struct ParentAsSuperuser<Origin>(PhantomData<Origin>);
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.contains_parents_only(1) {
Ok(Origin::root())
} else {
Err(origin)
}
}
}
@@ -58,9 +59,10 @@ impl<ParaId: IsSystem + From<u32>, Origin: OriginTrait> ConvertOrigin<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() =>
Ok(Origin::root()),
(
OriginKind::Superuser,
MultiLocation { parents: 0, interior: X1(Junction::Parachain(id)) },
) if ParaId::from(id).is_system() => Ok(Origin::root()),
(_, origin) => Err(origin),
}
}
@@ -74,7 +76,7 @@ impl<ParaId: IsSystem + From<u32>, Origin: OriginTrait> ConvertOrigin<Origin>
match (kind, origin) {
(
OriginKind::Superuser,
MultiLocation::X2(Junction::Parent, Junction::Parachain(id)),
MultiLocation { parents: 1, interior: X1(Junction::Parachain(id)) },
) if ParaId::from(id).is_system() => Ok(Origin::root()),
(_, origin) => Err(origin),
}
@@ -87,8 +89,10 @@ impl<ParachainOrigin: From<u32>, Origin: From<ParachainOrigin>> ConvertOrigin<Or
{
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))),
(
OriginKind::Native,
MultiLocation { parents: 0, interior: X1(Junction::Parachain(id)) },
) => Ok(Origin::from(ParachainOrigin::from(id))),
(_, origin) => Err(origin),
}
}
@@ -102,8 +106,10 @@ impl<ParachainOrigin: From<u32>, Origin: From<ParachainOrigin>> ConvertOrigin<Or
{
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))),
(
OriginKind::Native,
MultiLocation { parents: 1, interior: X1(Junction::Parachain(id)) },
) => Ok(Origin::from(ParachainOrigin::from(id))),
(_, origin) => Err(origin),
}
}
@@ -115,9 +121,10 @@ impl<RelayOrigin: Get<Origin>, 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.contains_parents_only(1) {
Ok(RelayOrigin::get())
} else {
Err(origin)
}
}
}
@@ -130,8 +137,10 @@ where
{
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() =>
(
OriginKind::Native,
MultiLocation { parents: 0, interior: X1(Junction::AccountId32 { id, network }) },
) if matches!(network, NetworkId::Any) || network == Network::get() =>
Ok(Origin::signed(id.into())),
(_, origin) => Err(origin),
}
@@ -146,8 +155,10 @@ where
{
fn convert_origin(origin: MultiLocation, kind: OriginKind) -> Result<Origin, MultiLocation> {
match (kind, origin) {
(OriginKind::Native, MultiLocation::X1(Junction::AccountKey20 { key, network }))
if matches!(network, NetworkId::Any) || network == Network::get() =>
(
OriginKind::Native,
MultiLocation { parents: 0, interior: X1(Junction::AccountKey20 { key, network }) },
) if (matches!(network, NetworkId::Any) || network == Network::get()) =>
Ok(Origin::signed(key.into())),
(_, origin) => Err(origin),
}
@@ -170,7 +181,7 @@ where
// We institute a root fallback so root can always represent the context. This
// guarantees that `successful_origin` will work.
if o.caller() == Origin::root().caller() {
Ok(MultiLocation::Here)
Ok(Here.into())
} else {
Err(o)
}
+78 -62
View File
@@ -20,35 +20,41 @@ use xcm_executor::{traits::*, Config, XcmExecutor};
#[test]
fn basic_setup_works() {
add_reserve(X1(Parent), Wild((X1(Parent), WildFungible).into()));
add_reserve(Parent.into(), Wild((Parent, WildFungible).into()));
assert!(<TestConfig as Config>::IsReserve::filter_asset_location(
&(X1(Parent), 100).into(),
&X1(Parent),
&(Parent, 100).into(),
&Parent.into(),
));
assert_eq!(to_account(X1(Parachain(1))), Ok(1001));
assert_eq!(to_account(X1(Parachain(50))), Ok(1050));
assert_eq!(to_account(X2(Parent, Parachain(1))), Ok(2001));
assert_eq!(to_account(X2(Parent, Parachain(50))), Ok(2050));
assert_eq!(to_account(X1(AccountIndex64 { index: 1, network: Any })), Ok(1));
assert_eq!(to_account(X1(AccountIndex64 { index: 42, network: Any })), Ok(42));
assert_eq!(to_account(Here), Ok(3000));
assert_eq!(to_account(X1(Parachain(1)).into()), Ok(1001));
assert_eq!(to_account(X1(Parachain(50)).into()), Ok(1050));
assert_eq!(to_account(MultiLocation::new(1, X1(Parachain(1)))), Ok(2001));
assert_eq!(to_account(MultiLocation::new(1, X1(Parachain(50)))), Ok(2050));
assert_eq!(
to_account(MultiLocation::new(0, X1(AccountIndex64 { index: 1, network: Any }))),
Ok(1),
);
assert_eq!(
to_account(MultiLocation::new(0, X1(AccountIndex64 { index: 42, network: Any }))),
Ok(42),
);
assert_eq!(to_account(Here.into()), Ok(3000));
}
#[test]
fn weigher_should_work() {
let mut message = opaque::Xcm::ReserveAssetDeposited {
assets: (X1(Parent), 100).into(),
assets: (Parent, 100).into(),
effects: vec![
Order::BuyExecution {
fees: (X1(Parent), 1).into(),
fees: (Parent, 1).into(),
weight: 0,
debt: 30,
halt_on_error: true,
orders: vec![],
instructions: vec![],
},
Order::DepositAsset { assets: All.into(), max_assets: 1, beneficiary: Here },
Order::DepositAsset { assets: All.into(), max_assets: 1, beneficiary: Here.into() },
],
}
.into();
@@ -58,16 +64,26 @@ fn weigher_should_work() {
#[test]
fn take_weight_credit_barrier_should_work() {
let mut message =
opaque::Xcm::TransferAsset { assets: (X1(Parent), 100).into(), beneficiary: Here };
opaque::Xcm::TransferAsset { assets: (Parent, 100).into(), beneficiary: Here.into() };
let mut weight_credit = 10;
let r =
TakeWeightCredit::should_execute(&X1(Parent), true, &mut message, 10, &mut weight_credit);
let r = TakeWeightCredit::should_execute(
&Parent.into(),
true,
&mut message,
10,
&mut weight_credit,
);
assert_eq!(r, Ok(()));
assert_eq!(weight_credit, 0);
let r =
TakeWeightCredit::should_execute(&X1(Parent), true, &mut message, 10, &mut weight_credit);
let r = TakeWeightCredit::should_execute(
&Parent.into(),
true,
&mut message,
10,
&mut weight_credit,
);
assert_eq!(r, Err(()));
assert_eq!(weight_credit, 0);
}
@@ -75,12 +91,12 @@ fn take_weight_credit_barrier_should_work() {
#[test]
fn allow_unpaid_should_work() {
let mut message =
opaque::Xcm::TransferAsset { assets: (X1(Parent), 100).into(), beneficiary: Here };
opaque::Xcm::TransferAsset { assets: (Parent, 100).into(), beneficiary: Here.into() };
AllowUnpaidFrom::set(vec![X1(Parent)]);
AllowUnpaidFrom::set(vec![Parent.into()]);
let r = AllowUnpaidExecutionFrom::<IsInVec<AllowUnpaidFrom>>::should_execute(
&X1(Parachain(1)),
&Parachain(1).into(),
true,
&mut message,
10,
@@ -89,7 +105,7 @@ fn allow_unpaid_should_work() {
assert_eq!(r, Err(()));
let r = AllowUnpaidExecutionFrom::<IsInVec<AllowUnpaidFrom>>::should_execute(
&X1(Parent),
&Parent.into(),
true,
&mut message,
10,
@@ -100,13 +116,13 @@ fn allow_unpaid_should_work() {
#[test]
fn allow_paid_should_work() {
AllowPaidFrom::set(vec![X1(Parent)]);
AllowPaidFrom::set(vec![Parent.into()]);
let mut message =
opaque::Xcm::TransferAsset { assets: (X1(Parent), 100).into(), beneficiary: Here };
opaque::Xcm::TransferAsset { assets: (Parent, 100).into(), beneficiary: Here.into() };
let r = AllowTopLevelPaidExecutionFrom::<IsInVec<AllowPaidFrom>>::should_execute(
&X1(Parachain(1)),
&Parachain(1).into(),
true,
&mut message,
10,
@@ -114,9 +130,9 @@ fn allow_paid_should_work() {
);
assert_eq!(r, Err(()));
let fees = (X1(Parent), 1).into();
let fees = (Parent, 1).into();
let mut underpaying_message = opaque::Xcm::ReserveAssetDeposited {
assets: (X1(Parent), 100).into(),
assets: (Parent, 100).into(),
effects: vec![
Order::BuyExecution {
fees,
@@ -126,12 +142,12 @@ fn allow_paid_should_work() {
orders: vec![],
instructions: vec![],
},
Order::DepositAsset { assets: All.into(), max_assets: 1, beneficiary: Here },
Order::DepositAsset { assets: All.into(), max_assets: 1, beneficiary: Here.into() },
],
};
let r = AllowTopLevelPaidExecutionFrom::<IsInVec<AllowPaidFrom>>::should_execute(
&X1(Parent),
&Parent.into(),
true,
&mut underpaying_message,
30,
@@ -139,9 +155,9 @@ fn allow_paid_should_work() {
);
assert_eq!(r, Err(()));
let fees = (X1(Parent), 1).into();
let fees = (Parent, 1).into();
let mut paying_message = opaque::Xcm::ReserveAssetDeposited {
assets: (X1(Parent), 100).into(),
assets: (Parent, 100).into(),
effects: vec![
Order::BuyExecution {
fees,
@@ -151,12 +167,12 @@ fn allow_paid_should_work() {
orders: vec![],
instructions: vec![],
},
Order::DepositAsset { assets: All.into(), max_assets: 1, beneficiary: Here },
Order::DepositAsset { assets: All.into(), max_assets: 1, beneficiary: Here.into() },
],
};
let r = AllowTopLevelPaidExecutionFrom::<IsInVec<AllowPaidFrom>>::should_execute(
&X1(Parachain(1)),
&Parachain(1).into(),
true,
&mut paying_message,
30,
@@ -165,7 +181,7 @@ fn allow_paid_should_work() {
assert_eq!(r, Err(()));
let r = AllowTopLevelPaidExecutionFrom::<IsInVec<AllowPaidFrom>>::should_execute(
&X1(Parent),
&Parent.into(),
true,
&mut paying_message,
30,
@@ -176,14 +192,14 @@ fn allow_paid_should_work() {
#[test]
fn paying_reserve_deposit_should_work() {
AllowPaidFrom::set(vec![X1(Parent)]);
add_reserve(X1(Parent), (Parent, WildFungible).into());
AllowPaidFrom::set(vec![Parent.into()]);
add_reserve(Parent.into(), (Parent, WildFungible).into());
WeightPrice::set((Parent.into(), 1_000_000_000_000));
let origin = X1(Parent);
let fees = (X1(Parent), 30).into();
let origin = Parent.into();
let fees = (Parent, 30).into();
let message = Xcm::<TestCall>::ReserveAssetDeposited {
assets: (X1(Parent), 100).into(),
assets: (Parent, 100).into(),
effects: vec![
Order::<TestCall>::BuyExecution {
fees,
@@ -196,28 +212,28 @@ fn paying_reserve_deposit_should_work() {
Order::<TestCall>::DepositAsset {
assets: All.into(),
max_assets: 1,
beneficiary: Here,
beneficiary: Here.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![(X1(Parent), 70).into()]);
assert_eq!(assets(3000), vec![(Parent, 70).into()]);
}
#[test]
fn transfer_should_work() {
// we'll let them have message execution for free.
AllowUnpaidFrom::set(vec![X1(Parachain(1))]);
AllowUnpaidFrom::set(vec![X1(Parachain(1)).into()]);
// Child parachain #1 owns 1000 tokens held by us in reserve.
add_asset(1001, (Here, 1000).into());
// They want to transfer 100 of them to their sibling parachain #2
let r = XcmExecutor::<TestConfig>::execute_xcm(
X1(Parachain(1)),
Parachain(1).into(),
Xcm::TransferAsset {
assets: (Here, 100).into(),
beneficiary: X1(AccountIndex64 { index: 3, network: Any }),
beneficiary: X1(AccountIndex64 { index: 3, network: Any }).into(),
},
50,
);
@@ -229,19 +245,19 @@ fn transfer_should_work() {
#[test]
fn reserve_transfer_should_work() {
AllowUnpaidFrom::set(vec![X1(Parachain(1))]);
AllowUnpaidFrom::set(vec![X1(Parachain(1)).into()]);
// Child parachain #1 owns 1000 tokens held by us in reserve.
add_asset(1001, (Here, 1000).into());
// The remote account owned by gav.
let three = X1(AccountIndex64 { index: 3, network: Any });
let three: MultiLocation = X1(AccountIndex64 { index: 3, network: Any }).into();
// They want to transfer 100 of our native asset from sovereign account of parachain #1 into #2
// and let them know to hand it to account #3.
let r = XcmExecutor::<TestConfig>::execute_xcm(
X1(Parachain(1)),
Parachain(1).into(),
Xcm::TransferReserveAsset {
assets: (Here, 100).into(),
dest: X1(Parachain(2)),
dest: Parachain(2).into(),
effects: vec![Order::DepositAsset {
assets: All.into(),
max_assets: 1,
@@ -256,9 +272,9 @@ fn reserve_transfer_should_work() {
assert_eq!(
sent_xcm(),
vec![(
X1(Parachain(2)),
Parachain(2).into(),
Xcm::ReserveAssetDeposited {
assets: (X1(Parent), 100).into(),
assets: (Parent, 100).into(),
effects: vec![Order::DepositAsset {
assets: All.into(),
max_assets: 1,
@@ -271,9 +287,9 @@ fn reserve_transfer_should_work() {
#[test]
fn transacting_should_work() {
AllowUnpaidFrom::set(vec![X1(Parent)]);
AllowUnpaidFrom::set(vec![Parent.into()]);
let origin = X1(Parent);
let origin = Parent.into();
let message = Xcm::<TestCall>::Transact {
origin_type: OriginKind::Native,
require_weight_at_most: 50,
@@ -286,9 +302,9 @@ fn transacting_should_work() {
#[test]
fn transacting_should_respect_max_weight_requirement() {
AllowUnpaidFrom::set(vec![X1(Parent)]);
AllowUnpaidFrom::set(vec![Parent.into()]);
let origin = X1(Parent);
let origin = Parent.into();
let message = Xcm::<TestCall>::Transact {
origin_type: OriginKind::Native,
require_weight_at_most: 40,
@@ -301,9 +317,9 @@ fn transacting_should_respect_max_weight_requirement() {
#[test]
fn transacting_should_refund_weight() {
AllowUnpaidFrom::set(vec![X1(Parent)]);
AllowUnpaidFrom::set(vec![Parent.into()]);
let origin = X1(Parent);
let origin = Parent.into();
let message = Xcm::<TestCall>::Transact {
origin_type: OriginKind::Native,
require_weight_at_most: 50,
@@ -316,15 +332,15 @@ fn transacting_should_refund_weight() {
#[test]
fn paid_transacting_should_refund_payment_for_unused_weight() {
let one = X1(AccountIndex64 { index: 1, network: Any });
let one: MultiLocation = X1(AccountIndex64 { index: 1, network: Any }).into();
AllowPaidFrom::set(vec![one.clone()]);
add_asset(1, (Parent, 100).into());
WeightPrice::set((Parent.into(), 1_000_000_000_000));
let origin = one.clone();
let fees = (X1(Parent), 100).into();
let fees = (Parent, 100).into();
let message = Xcm::<TestCall>::WithdrawAsset {
assets: (X1(Parent), 100).into(), // enough for 100 units of weight.
assets: (Parent, 100).into(), // enough for 100 units of weight.
effects: vec![
Order::<TestCall>::BuyExecution {
fees,
@@ -349,17 +365,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![(X1(Parent), 50).into()]);
assert_eq!(assets(1), vec![(Parent, 50).into()]);
}
#[test]
fn prepaid_result_of_query_should_get_free_execution() {
let query_id = 33;
let origin = X1(Parent);
let origin: MultiLocation = Parent.into();
// We put this in manually here, but normally this would be done at the point of crafting the message.
expect_response(query_id, origin.clone());
let the_response = Response::Assets((X1(Parent), 100).into());
let the_response = Response::Assets((Parent, 100).into());
let message = Xcm::<TestCall>::QueryResponse { query_id, response: the_response.clone() };
let weight_limit = 10;